mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-06 15:08:36 +01:00
feat(editor): dragging straight refits neighbor curves
This commit is contained in:
@@ -340,6 +340,9 @@ class editor_mode : public application_mode
|
|||||||
editor_track::straight drag_line;
|
editor_track::straight drag_line;
|
||||||
std::vector<editor_track::straight> set;
|
std::vector<editor_track::straight> set;
|
||||||
std::vector<editor_track::straight> drag_lines;
|
std::vector<editor_track::straight> drag_lines;
|
||||||
|
bool fitting{false};
|
||||||
|
editor_track::curve fit_before;
|
||||||
|
editor_track::curve fit_after;
|
||||||
std::vector<std::pair<TTrack *, editor_track::state>> drag_states;
|
std::vector<std::pair<TTrack *, editor_track::state>> drag_states;
|
||||||
glm::dvec3 preview_start{0.0};
|
glm::dvec3 preview_start{0.0};
|
||||||
glm::dvec3 preview_end{0.0};
|
glm::dvec3 preview_end{0.0};
|
||||||
@@ -381,6 +384,8 @@ class editor_mode : public application_mode
|
|||||||
double straight_tool_radius(editor_track::straight const &Line) const;
|
double straight_tool_radius(editor_track::straight const &Line) const;
|
||||||
void straight_reshape(editor_track::straight const &Line, double const From, double const To, std::function<glm::dvec3(glm::dvec3 const &)> const &Tail, double const Radius);
|
void straight_reshape(editor_track::straight const &Line, double const From, double const To, std::function<glm::dvec3(glm::dvec3 const &)> const &Tail, double const Radius);
|
||||||
void straight_refresh();
|
void straight_refresh();
|
||||||
|
bool start_curve_fit(editor_track::straight const &Line);
|
||||||
|
void update_curve_fit(glm::dvec3 const &Start, glm::dvec3 const &End);
|
||||||
void add_detour_point();
|
void add_detour_point();
|
||||||
void apply_detour();
|
void apply_detour();
|
||||||
std::vector<glm::dvec3> detour_outline() const;
|
std::vector<glm::dvec3> detour_outline() const;
|
||||||
|
|||||||
@@ -1474,7 +1474,22 @@ void editor_mode::draw_straights_overlay() const
|
|||||||
projection.line(drawlist, state.tool_point + along * length + shifted, line.end + shifted, IM_COL32(255, 210, 60, 255), 3.0f);
|
projection.line(drawlist, state.tool_point + along * length + shifted, line.end + shifted, IM_COL32(255, 210, 60, 255), 3.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_straights.dragging)
|
if (m_straights.dragging && m_straights.fitting)
|
||||||
|
{
|
||||||
|
auto const &result{m_route.result};
|
||||||
|
if (result.length > 0.0 && result.profile.size() >= 2)
|
||||||
|
{
|
||||||
|
int const steps{std::clamp(static_cast<int>(result.length / 2.0), 2, 2000)};
|
||||||
|
auto previous{alignment::evaluate(result, 0.0).position};
|
||||||
|
for (int i = 1; i <= steps; ++i)
|
||||||
|
{
|
||||||
|
auto const next{alignment::evaluate(result, result.length * i / steps).position};
|
||||||
|
projection.line(drawlist, previous, next, result.valid ? IM_COL32(255, 210, 60, 255) : IM_COL32(255, 60, 60, 255), 3.0f);
|
||||||
|
previous = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_straights.dragging)
|
||||||
{
|
{
|
||||||
for (auto const &member : m_straights.drag_lines)
|
for (auto const &member : m_straights.drag_lines)
|
||||||
{
|
{
|
||||||
@@ -1911,15 +1926,19 @@ void editor_mode::render_straight_gizmo()
|
|||||||
{
|
{
|
||||||
lines.push_back(line);
|
lines.push_back(line);
|
||||||
}
|
}
|
||||||
auto const tracks{editor_track::straight_affected(lines)};
|
state.fitting = lines.size() == 1 && start_curve_fit(line);
|
||||||
|
auto const tracks{state.fitting ? std::vector<TTrack *>{} : editor_track::straight_affected(lines)};
|
||||||
state.dragging = true;
|
state.dragging = true;
|
||||||
state.drag_line = line;
|
state.drag_line = line;
|
||||||
state.drag_lines = lines;
|
state.drag_lines = lines;
|
||||||
state.drag_states.clear();
|
state.drag_states.clear();
|
||||||
for (auto *track : tracks)
|
for (auto *track : tracks)
|
||||||
state.drag_states.emplace_back(track, editor_track::capture(*track));
|
state.drag_states.emplace_back(track, editor_track::capture(*track));
|
||||||
push_track_snapshot(state.drag_states);
|
if (false == state.fitting)
|
||||||
m_track_drag = tracks;
|
{
|
||||||
|
push_track_snapshot(state.drag_states);
|
||||||
|
m_track_drag = tracks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto const &grabbed{state.drag_line};
|
auto const &grabbed{state.drag_line};
|
||||||
glm::dvec3 moved{camerapos + glm::dvec3(state.gizmo[3])};
|
glm::dvec3 moved{camerapos + glm::dvec3(state.gizmo[3])};
|
||||||
@@ -1955,6 +1974,11 @@ void editor_mode::render_straight_gizmo()
|
|||||||
ends.emplace_back(transform(member.start), transform(member.end));
|
ends.emplace_back(transform(member.start), transform(member.end));
|
||||||
state.preview_start = transform(grabbed.start);
|
state.preview_start = transform(grabbed.start);
|
||||||
state.preview_end = transform(grabbed.end);
|
state.preview_end = transform(grabbed.end);
|
||||||
|
if (state.fitting)
|
||||||
|
{
|
||||||
|
update_curve_fit(state.preview_start, state.preview_end);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (auto const &entry : state.drag_states)
|
for (auto const &entry : state.drag_states)
|
||||||
editor_track::apply(*entry.first, entry.second);
|
editor_track::apply(*entry.first, entry.second);
|
||||||
editor_track::move_straights(state.drag_lines, ends);
|
editor_track::move_straights(state.drag_lines, ends);
|
||||||
@@ -1963,6 +1987,16 @@ void editor_mode::render_straight_gizmo()
|
|||||||
}
|
}
|
||||||
else if (state.dragging)
|
else if (state.dragging)
|
||||||
{
|
{
|
||||||
|
if (state.fitting)
|
||||||
|
{
|
||||||
|
state.fitting = false;
|
||||||
|
state.dragging = false;
|
||||||
|
state.drag_lines.clear();
|
||||||
|
if (m_route.result.valid)
|
||||||
|
route_apply();
|
||||||
|
straight_refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
commit_track_drag(true);
|
commit_track_drag(true);
|
||||||
state.dragging = false;
|
state.dragging = false;
|
||||||
m_track_drag.clear();
|
m_track_drag.clear();
|
||||||
@@ -2898,3 +2932,62 @@ void editor_mode::apply_detour()
|
|||||||
route_apply();
|
route_apply();
|
||||||
straight_refresh();
|
straight_refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool editor_mode::start_curve_fit(editor_track::straight const &Line)
|
||||||
|
{
|
||||||
|
auto &state{m_straights};
|
||||||
|
auto *before{editor_track::outside_neighbour(Line, false)};
|
||||||
|
auto *after{editor_track::outside_neighbour(Line, true)};
|
||||||
|
if (before == nullptr || after == nullptr)
|
||||||
|
return false;
|
||||||
|
if (false == editor_track::find_curve(*before, state.tolerance, m_route.design.norms.gauge, state.fit_before) || false == editor_track::find_curve(*after, state.tolerance, m_route.design.norms.gauge, state.fit_after))
|
||||||
|
return false;
|
||||||
|
if (state.fit_before.reversals != 0 || state.fit_after.reversals != 0)
|
||||||
|
return false;
|
||||||
|
auto const far = [](editor_track::curve const &Curve, glm::dvec3 const &Joint) { return editor_track::touches(*Curve.from, Joint) ? Curve.to : Curve.from; };
|
||||||
|
m_route.from = far(state.fit_before, Line.start);
|
||||||
|
m_route.to = far(state.fit_after, Line.end);
|
||||||
|
route_reset();
|
||||||
|
if (m_route.chain.tracks.empty())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void editor_mode::update_curve_fit(glm::dvec3 const &Start, glm::dvec3 const &End)
|
||||||
|
{
|
||||||
|
auto &state{m_straights};
|
||||||
|
auto &design{m_route.design};
|
||||||
|
glm::dvec2 const point{Start.x, Start.z};
|
||||||
|
glm::dvec2 const direction{glm::normalize(glm::dvec2{End.x - Start.x, End.z - Start.z})};
|
||||||
|
auto const cross = [](glm::dvec2 const &A, glm::dvec2 const &B) { return A.x * B.y - A.y * B.x; };
|
||||||
|
glm::dvec2 const start{design.start.x, design.start.z};
|
||||||
|
glm::dvec2 const end{design.end.x, design.end.z};
|
||||||
|
auto const startdirection{glm::normalize(design.start_direction)};
|
||||||
|
auto const enddirection{glm::normalize(design.end_direction)};
|
||||||
|
auto const first{cross(point - start, direction) / cross(startdirection, direction)};
|
||||||
|
auto const last{cross(end - point, direction) / cross(enddirection, direction)};
|
||||||
|
auto const make = [&](editor_track::curve const &Curve, double const Offset) {
|
||||||
|
alignment::vertex vertex;
|
||||||
|
vertex.radius = Curve.radius > 0.0 ? std::round(Curve.radius) : 1000.0;
|
||||||
|
route_recommend(vertex);
|
||||||
|
if (Curve.transition_in > 0.0)
|
||||||
|
vertex.transition_in = std::round(Curve.transition_in);
|
||||||
|
if (Curve.transition_out > 0.0)
|
||||||
|
vertex.transition_out = std::round(Curve.transition_out);
|
||||||
|
if (Curve.cant > 0.0)
|
||||||
|
vertex.cant = std::round(Curve.cant);
|
||||||
|
if (Curve.compound)
|
||||||
|
{
|
||||||
|
vertex.compound = true;
|
||||||
|
vertex.radius2 = std::round(Curve.radius2);
|
||||||
|
vertex.transition_middle = std::round(Curve.transition_middle);
|
||||||
|
vertex.split = Curve.split;
|
||||||
|
}
|
||||||
|
vertex.offset = std::max(0.1, Offset);
|
||||||
|
return vertex;
|
||||||
|
};
|
||||||
|
auto before{make(state.fit_before, first)};
|
||||||
|
auto after{make(state.fit_after, last)};
|
||||||
|
design.vertices = {before, after};
|
||||||
|
route_update();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1253,6 +1253,33 @@ TTrack *editor_track::create_switch(switch_template const &Template, std::vector
|
|||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool editor_track::touches(TTrack const &Track, glm::dvec3 const &Point)
|
||||||
|
{
|
||||||
|
for (auto const &path : Track.m_paths)
|
||||||
|
for (auto const index : {segment_data::point::start, segment_data::point::end})
|
||||||
|
if (glm::distance(path.points[index], Point) <= kSamePoint)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TTrack *editor_track::outside_neighbour(straight const &Line, bool const Atend)
|
||||||
|
{
|
||||||
|
auto const &point{Atend ? Line.end : Line.start};
|
||||||
|
for (std::size_t i = 0; i < Line.tracks.size(); ++i)
|
||||||
|
{
|
||||||
|
auto const &path{Line.tracks[i]->m_paths[Line.paths[i]]};
|
||||||
|
for (auto const end : {false, true})
|
||||||
|
{
|
||||||
|
if (glm::distance(path.points[end ? segment_data::point::end : segment_data::point::start], point) > kSamePoint)
|
||||||
|
continue;
|
||||||
|
auto *neighbour{neighbour_at(*Line.tracks[i], Line.paths[i], end)};
|
||||||
|
if (neighbour != nullptr && std::find(Line.tracks.begin(), Line.tracks.end(), neighbour) == Line.tracks.end())
|
||||||
|
return neighbour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<TTrack *> editor_track::straight_affected(std::vector<straight> const &Lines)
|
std::vector<TTrack *> editor_track::straight_affected(std::vector<straight> const &Lines)
|
||||||
{
|
{
|
||||||
std::vector<TTrack *> result;
|
std::vector<TTrack *> result;
|
||||||
|
|||||||
@@ -118,6 +118,8 @@ class editor_track
|
|||||||
static straight find_straight(TTrack &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<straight> find_straights(double const Minimumlength, straight_tolerance const &Tolerance);
|
||||||
static std::vector<TTrack *> straight_affected(std::vector<straight> const &Lines);
|
static std::vector<TTrack *> straight_affected(std::vector<straight> const &Lines);
|
||||||
|
static TTrack *outside_neighbour(straight const &Line, bool const Atend);
|
||||||
|
static bool touches(TTrack const &Track, glm::dvec3 const &Point);
|
||||||
struct curve
|
struct curve
|
||||||
{
|
{
|
||||||
TTrack *from{nullptr};
|
TTrack *from{nullptr};
|
||||||
|
|||||||
Reference in New Issue
Block a user