17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 02:49:19 +02:00

feat(editor): move straights keeping parallel

This commit is contained in:
maj00r
2026-10-02 22:59:55 +02:00
parent 90f03849c0
commit b986cc8990
4 changed files with 123 additions and 26 deletions

View File

@@ -334,6 +334,8 @@ class editor_mode : public application_mode
int handle{-1};
bool dragging{false};
editor_track::straight drag_line;
std::vector<editor_track::straight> set;
std::vector<editor_track::straight> drag_lines;
std::vector<std::pair<TTrack *, editor_track::state>> drag_states;
glm::dvec3 preview_start{0.0};
glm::dvec3 preview_end{0.0};
@@ -352,6 +354,8 @@ class editor_mode : public application_mode
bool pick_straight_handle();
void render_straight_gizmo();
void straight_apply(editor_track::straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End);
void straights_apply(std::vector<editor_track::straight> const &Lines, std::vector<std::pair<glm::dvec3, glm::dvec3>> const &Ends);
bool in_straight_set(editor_track::straight const &Line) const;
void straight_refresh();
straights_state m_straights;
enum class track_tab { straights, route, path };

View File

@@ -24,6 +24,7 @@ http:
#include <algorithm>
#include <cmath>
#include <cstring>
#include <functional>
namespace
{
@@ -1158,10 +1159,19 @@ void editor_mode::draw_straights_overlay() const
if (nearby(line))
draw(line, i == m_straights.listed ? IM_COL32(40, 220, 255, 255) : IM_COL32(255, 255, 255, 110), i == m_straights.listed ? 4.0f : 2.0f);
}
for (auto const &member : m_straights.set)
draw(member, IM_COL32(255, 150, 30, 255), 4.0f);
draw(m_straights.current, IM_COL32(40, 220, 255, 255), 4.0f);
if (m_straights.dragging)
{
projection.line(drawlist, m_straights.preview_start, m_straights.preview_end, IM_COL32(255, 210, 60, 255), 3.0f);
for (auto const &member : m_straights.drag_lines)
{
for (auto const *track : member.tracks)
{
auto const &path{track->m_paths.front()};
projection.line(drawlist, path.points[segment_data::point::start], path.points[segment_data::point::end], IM_COL32(255, 210, 60, 255), 3.0f);
}
}
}
else if (false == m_straights.current.tracks.empty())
{
@@ -1262,6 +1272,16 @@ void editor_mode::render_straights_ui()
ImGui::SameLine();
if (ImGui::Button("Set as B"))
state.b = line;
ImGui::SameLine();
if (in_straight_set(line))
{
if (ImGui::Button("Remove from the set"))
state.set.erase(std::remove_if(state.set.begin(), state.set.end(), [&](editor_track::straight const &Member) { return std::any_of(line.tracks.begin(), line.tracks.end(), [&](TTrack const *Track) { return std::find(Member.tracks.begin(), Member.tracks.end(), Track) != Member.tracks.end(); }); }), state.set.end());
}
else if (ImGui::Button("Add to the set"))
{
state.set.push_back(line);
}
if (false == ImGui::IsAnyItemActive())
{
@@ -1298,6 +1318,14 @@ void editor_mode::render_straights_ui()
if (false == state.status.empty())
ImGui::TextColored(ImVec4(1.0f, 0.35f, 0.3f, 1.0f), "%s", state.status.c_str());
if (false == state.set.empty())
{
ImGui::Text("Set: %zu straights, dragging any of them moves the whole set, keeping it parallel", state.set.size());
ImGui::SameLine();
if (ImGui::SmallButton("Clear the set"))
state.set.clear();
}
ImGui::Separator();
auto const &a{state.a};
auto const &b{state.b};
@@ -1388,13 +1416,30 @@ void editor_mode::straight_refresh()
for (auto &line : state.found)
if (false == line.tracks.empty())
line = editor_track::find_straight(*line.tracks.front(), state.tolerance);
for (auto &line : state.set)
if (false == line.tracks.empty())
line = editor_track::find_straight(*line.tracks.front(), state.tolerance);
}
bool editor_mode::in_straight_set(editor_track::straight const &Line) const
{
for (auto const &member : m_straights.set)
for (auto const *track : Line.tracks)
if (std::find(member.tracks.begin(), member.tracks.end(), track) != member.tracks.end())
return true;
return false;
}
void editor_mode::straight_apply(editor_track::straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End)
{
straights_apply({Line}, {{Start, End}});
}
void editor_mode::straights_apply(std::vector<editor_track::straight> const &Lines, std::vector<std::pair<glm::dvec3, glm::dvec3>> const &Ends)
{
auto &state{m_straights};
state.status.clear();
auto const tracks{editor_track::straight_affected(Line)};
auto const tracks{editor_track::straight_affected(Lines)};
for (auto *track : tracks)
{
if (false == track->Dynamics.empty())
@@ -1407,7 +1452,7 @@ void editor_mode::straight_apply(editor_track::straight const &Line, glm::dvec3
for (auto *track : tracks)
states.emplace_back(track, editor_track::capture(*track));
push_track_snapshot(std::move(states));
editor_track::move_straight(Line, Start, End);
editor_track::move_straights(Lines, Ends);
editor_track::commit(tracks);
straight_refresh();
}
@@ -1443,39 +1488,68 @@ void editor_mode::render_straight_gizmo()
{
if (false == state.dragging)
{
auto const tracks{editor_track::straight_affected(line)};
std::vector<editor_track::straight> lines;
if (in_straight_set(line))
{
for (auto const &member : state.set)
if (false == member.tracks.empty())
lines.push_back(editor_track::find_straight(*member.tracks.front(), state.tolerance));
}
else
{
lines.push_back(line);
}
auto const tracks{editor_track::straight_affected(lines)};
if (std::any_of(tracks.begin(), tracks.end(), [](TTrack const *Track) { return false == Track->Dynamics.empty(); }))
{
state.status = "There are vehicles placed on the straight or the paths attached to it";
state.status = "There are vehicles placed on the straights or the paths attached to them";
return;
}
state.dragging = true;
state.drag_line = line;
state.drag_lines = lines;
state.drag_states.clear();
for (auto *track : tracks)
state.drag_states.emplace_back(track, editor_track::capture(*track));
push_track_snapshot(state.drag_states);
m_track_drag = tracks;
}
auto const &original{state.drag_line};
auto const &grabbed{state.drag_line};
glm::dvec3 const moved{camerapos + glm::dvec3(state.gizmo[3])};
auto start{original.start};
auto end{original.end};
if (state.handle == 0)
start = moved;
else if (state.handle == 1)
end = moved;
std::function<glm::dvec3(glm::dvec3 const &)> transform;
if (state.handle == 2)
{
auto const offset{moved - (grabbed.start + grabbed.end) * 0.5};
transform = [offset](glm::dvec3 const &Point) { return Point + offset; };
}
else
{
auto const offset{moved - (original.start + original.end) * 0.5};
start += offset;
end += offset;
auto const pivot{state.handle == 0 ? grabbed.end : grabbed.start};
auto const original{state.handle == 0 ? grabbed.start : grabbed.end};
glm::dvec2 const before{original.x - pivot.x, original.z - pivot.z};
glm::dvec2 const after{moved.x - pivot.x, moved.z - pivot.z};
auto const lengthbefore{glm::length(before)};
auto const lengthafter{std::max(0.1, glm::length(after))};
auto const axis{before / std::max(1e-9, lengthbefore)};
auto const newaxis{after / lengthafter};
auto const scale{lengthafter / std::max(1e-9, lengthbefore)};
auto const rise{moved.y - original.y};
transform = [=](glm::dvec3 const &Point) {
glm::dvec2 const offset{Point.x - pivot.x, Point.z - pivot.z};
auto const along{glm::dot(offset, axis)};
auto const across{axis.x * offset.y - axis.y * offset.x};
auto const planar{glm::dvec2{pivot.x, pivot.z} + newaxis * (along * scale) + glm::dvec2{-newaxis.y, newaxis.x} * across};
return glm::dvec3{planar.x, Point.y + rise * along / std::max(1e-9, lengthbefore), planar.y};
};
}
state.preview_start = start;
state.preview_end = end;
std::vector<std::pair<glm::dvec3, glm::dvec3>> ends;
for (auto const &member : state.drag_lines)
ends.emplace_back(transform(member.start), transform(member.end));
state.preview_start = transform(grabbed.start);
state.preview_end = transform(grabbed.end);
for (auto const &entry : state.drag_states)
editor_track::apply(*entry.first, entry.second);
editor_track::move_straight(original, start, end);
editor_track::move_straights(state.drag_lines, ends);
m_track_dirty = true;
commit_track_drag(false);
}
@@ -1485,6 +1559,7 @@ void editor_mode::render_straight_gizmo()
state.dragging = false;
m_track_drag.clear();
state.drag_states.clear();
state.drag_lines.clear();
straight_refresh();
}
}

View File

@@ -22,6 +22,7 @@ http:
#include <cmath>
#include <limits>
#include <deque>
#include <functional>
#include <sstream>
#include <unordered_set>
@@ -970,11 +971,15 @@ std::vector<editor_track::straight> editor_track::find_straights(double const Mi
return result;
}
std::vector<TTrack *> editor_track::straight_affected(straight const &Line)
std::vector<TTrack *> editor_track::straight_affected(std::vector<straight> const &Lines)
{
std::vector<TTrack *> result(Line.tracks.begin(), Line.tracks.end());
auto const member = [&](TTrack const *Track) { return std::find(Line.tracks.begin(), Line.tracks.end(), Track) != Line.tracks.end(); };
for (auto *track : Line.tracks)
std::vector<TTrack *> result;
for (auto const &line : Lines)
for (auto *track : line.tracks)
add_unique(result, track);
auto const members{result};
auto const member = [&](TTrack const *Track) { return std::find(members.begin(), members.end(), Track) != members.end(); };
for (auto *track : members)
{
for (int i = 0; i < static_cast<int>(track->m_paths.size()); ++i)
{
@@ -995,7 +1000,18 @@ std::vector<TTrack *> editor_track::straight_affected(straight const &Line)
return result;
}
void editor_track::move_straight(straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End)
void editor_track::move_straights(std::vector<straight> const &Lines, std::vector<std::pair<glm::dvec3, glm::dvec3>> const &Ends)
{
std::vector<TTrack *> members;
for (auto const &line : Lines)
for (auto *track : line.tracks)
add_unique(members, track);
auto const member = [&](TTrack const *Track) { return std::find(members.begin(), members.end(), Track) != members.end(); };
for (std::size_t i = 0; i < Lines.size() && i < Ends.size(); ++i)
move_straight(Lines[i], Ends[i].first, Ends[i].second, member);
}
void editor_track::move_straight(straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End, std::function<bool(TTrack const *)> const &Member)
{
if (Line.tracks.empty() || Line.length < 1e-6)
return;
@@ -1053,7 +1069,7 @@ void editor_track::move_straight(straight const &Line, glm::dvec3 const &Start,
return glm::dvec3{moved.x, Point.y - oldheight + newheight, moved.y};
};
auto const member = [&](TTrack const *Track) { return std::find(Line.tracks.begin(), Line.tracks.end(), Track) != Line.tracks.end(); };
auto const &member{Member};
std::vector<std::pair<glm::dvec3, glm::dvec3>> joints;
for (std::size_t i = 0; i < Line.tracks.size(); ++i)
{

View File

@@ -9,6 +9,7 @@ http:
#pragma once
#include <functional>
#include <string>
#include <utility>
#include <vector>
@@ -115,8 +116,8 @@ class editor_track
static bool is_straight(TTrack const &Track, straight_tolerance const &Tolerance);
static straight find_straight(TTrack &Track, straight_tolerance const &Tolerance);
static std::vector<straight> find_straights(double const Minimumlength, straight_tolerance const &Tolerance);
static std::vector<TTrack *> straight_affected(straight const &Line);
static void move_straight(straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End);
static std::vector<TTrack *> straight_affected(std::vector<straight> const &Lines);
static void move_straights(std::vector<straight> const &Lines, std::vector<std::pair<glm::dvec3, glm::dvec3>> const &Ends);
static std::vector<TTrack *> relay(chain const &Chain, std::vector<segment_data> const &Pieces);
static void retire(TTrack &Track);
static void revive(TTrack &Track);
@@ -139,4 +140,5 @@ class editor_track
static void store_switch_path(TTrack &Switch, int const Path);
static void rebuild_geometry(TTrack &Track);
static TTrack *clone(TTrack const &Template);
static void move_straight(straight const &Line, glm::dvec3 const &Start, glm::dvec3 const &End, std::function<bool(TTrack const *)> const &Member);
};