From a0427bb80b5e27cc68281e02fd955697582aa8f1 Mon Sep 17 00:00:00 2001 From: maj00r Date: Sun, 25 Oct 2026 17:26:26 +0100 Subject: [PATCH] feat(editor): from the end of the diverging track of a switch the line laid always goes on with the curve of the switch: a straight or a bend the other way after P4 begins with the transition out of the curve of the switch, as after a plain track on a curve, never with a jump of the curvature, whether laid through points, traced, dragged in the straight layout or joined to another free end. The transition is the one for the speed the curve of the switch allows with no cant (about 48 km/h at R 300, so 20 to 30 m), not for the speed of the line. A straight with no bend clicked on from such an end runs on the way the transition leaves, as far as the point clicked, not along the tangent at the end, which left no room for the transition. Where no transition fits, as for a straight shorter than it, nothing is laid and the status says why --- application/editormodelay.cpp | 58 ++++++++++++++++++++++------------- editor/editorTrackShape.cpp | 7 ++++- lang/editor_pl.po | 3 ++ 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index d0b9261d..babedf0a 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -460,8 +460,9 @@ void editor_mode::point_drag_finish() std::optional editor_mode::eased_layout(TTrack const *From, glm::dvec3 const &Point, glm::dvec2 const &Direction, glm::dvec3 const &Target, double const Radius) const { m_eased_last.reset(); - // from the diverging track of a switch a curve goes on from its curvature, a straight goes on right from its end, as from the switch - if (From == nullptr || (From->eType != tt_Normal && (From->eType != tt_Switch || m_track_layout == track_layout::straight))) + // from the end of a curved track, the diverging track of a switch too, the line goes on from its curvature: a curve from it, a + // straight after a transition out of it, never with a jump of the curvature at the end + if (From == nullptr || (From->eType != tt_Normal && From->eType != tt_Switch)) return std::nullopt; auto const end{editor_track::bend_at(*From, Point)}; if (false == end.has_value()) @@ -483,6 +484,10 @@ std::optional editor_mode::eased_layout(TTrack const *Fro request.speed = design_speed(From, nullptr); request.piece_length = m_lay.piece_length; request.norms = laying_norms(); + // the diverging track of a switch has no cant: the line out of its curve is laid for the speed the curve lets with the unbalanced + // acceleration alone, as ease_out_of does + if (From->eType == tt_Switch && std::abs(end->curvature) > 1e-9) + request.speed = std::min(request.speed, std::sqrt(12.96 * request.norms.unbalanced / std::abs(end->curvature))); if (false == m_eased_cache.has_value() || m_eased_cache->first != request) m_eased_cache.emplace(request, alignment::lay_on(request)); m_eased_last = m_eased_cache->second; @@ -615,8 +620,9 @@ std::vector editor_mode::join_pieces(TTrack const *From, editor_tr if (result.kind != alignment::join_kind::straight && result.kind != alignment::join_kind::arc && glm::length(request.end.direction) > 1e-9) { auto const grade{(End.position.y - Start.y) / std::max(1.0, plan_distance(Start, End.position))}; - auto const in{From != nullptr && From->eType == tt_Normal ? editor_track::ease_out_of(*From, Start, grade, request.speed, request.norms) : editor_track::easing{}}; - auto const out{End.track != nullptr && End.track->eType == tt_Normal ? editor_track::ease_out_of(*End.track, End.position, -grade, request.speed, request.norms) : editor_track::easing{}}; + auto const curved = [](TTrack const *Track) { return Track != nullptr && (Track->eType == tt_Normal || Track->eType == tt_Switch); }; + auto const in{curved(From) ? editor_track::ease_out_of(*From, Start, grade, request.speed, request.norms) : editor_track::easing{}}; + auto const out{curved(End.track) ? editor_track::ease_out_of(*End.track, End.position, -grade, request.speed, request.norms) : editor_track::easing{}}; if (auto eased{eased_join(request, in, out)}) result = std::move(*eased); } @@ -995,11 +1001,11 @@ std::vector editor_mode::lay_pieces(std::vector const return std::max(alignment::minimum_pieces(Shape, Design), static_cast(std::ceil(Shape.length / std::max(5.0, tool.piece_length)))); }; std::vector pieces; - // the curvature of the track laid has to go on from the one of the track it joins, a jump gets a transition curve between them. Not - // at a switch: its diverging track ends its curve with a jump as it begins it, a straight going on right from there + // the curvature of the track laid has to go on from the one of the track it joins, a jump gets a transition curve between them; at + // the end of the diverging track of a switch as well, the curve of the switch going on auto const grade{(Points.back().y - Points.front().y) / std::max(1.0, plan_distance(Points.front(), Points.back()))}; auto const eased = [&](editor_track::snap_target const &Joint, double const Chainage, double const Sign) { - if (Joint.track == nullptr || Joint.track->eType != tt_Normal) + if (Joint.track == nullptr || (Joint.track->eType != tt_Normal && Joint.track->eType != tt_Switch)) return editor_track::easing{}; auto result{editor_track::ease_out_of(*Joint.track, Joint.position, grade * Sign, design.speed, design.norms)}; auto const own{Sign * curvature_at(shape, Chainage)}; @@ -1029,6 +1035,15 @@ std::vector editor_mode::lay_pieces(std::vector const easeddesign.end_radius = 0.0; easeddesign.end_turn = 0; } + // a straight with no bend, clicked on from the end the way it went: after the transition it runs on the way the transition leaves, + // as far as the point clicked + if (false == in.pieces.empty() && out.pieces.empty() && End.track == nullptr && easeddesign.vertices.empty()) + { + auto const along{glm::normalize(in.direction)}; + auto const distance{glm::dot(plan_of(easeddesign.end - in.end), along)}; + easeddesign.end = {in.end.x + along.x * distance, easeddesign.end.y, in.end.z + along.y * distance}; + easeddesign.end_direction = along; + } // the bends stay where they are, measured from the ends moved if (easeddesign.vertices.size() >= 2 && shape.vertices.size() == easeddesign.vertices.size()) { @@ -1055,6 +1070,15 @@ std::vector editor_mode::lay_pieces(std::vector const auto const after = [&](editor_track::easing const &Easing, glm::dvec3 const &Joint, glm::dvec3 const &Own) { return false == Easing.pieces.empty() && plan_distance(Joint, Own) > 0.01; }; auto const &before{after(in, Points.front(), design.start) ? in : editor_track::easing{}}; auto const &beyond{after(out, Points.back(), design.end) ? out : editor_track::easing{}}; + // at the diverging track of a switch the curve goes on, a line jumping from it isn't laid + auto const jumps = [](editor_track::snap_target const &Joint, editor_track::easing const &Needed, editor_track::easing const &Laid) { + return Joint.track != nullptr && Joint.track->eType == tt_Switch && false == Needed.pieces.empty() && Laid.pieces.empty(); + }; + if (jumps(tool.start, in, before) || jumps(End, out, beyond)) + { + Error = STR("At the end of the switch the line goes on with the curve of the switch, and there's no room for the transition out of it here") + (Error.empty() ? std::string{} : "\n" + Error); + return {}; + } Length = editor_track::eased_length(before, Length, beyond); pieces = editor_track::eased_pieces(before, pieces, beyond); } @@ -1244,8 +1268,8 @@ bool editor_mode::lay_line(std::vector const &Points, std::vector const &Points, std::vector kept; auto const easing = [&](editor_track::snap_target const &Joint, double const Grade) { - return Joint.track != nullptr && Joint.track->eType == tt_Normal ? editor_track::ease_out_of(*Joint.track, Joint.position, Grade, design.speed, design.norms) : editor_track::easing{}; + return Joint.track != nullptr && (Joint.track->eType == tt_Normal || Joint.track->eType == tt_Switch) ? editor_track::ease_out_of(*Joint.track, Joint.position, Grade, design.speed, design.norms) : editor_track::easing{}; }; auto const in{base.start_curved ? easing(tool.start, 0.0) : editor_track::easing{}}; auto const out{base.end_curved ? easing(End, 0.0) : editor_track::easing{}}; @@ -1297,19 +1321,11 @@ bool editor_mode::lay_line(std::vector const &Points, std::vectoreType == tt_Switch) - { - Radius = 0.0; - Turn = 0; - } - }; + // from a straight there if (base.start_curved) - straight_at(tool.start, design.start_curved, design.start_radius, design.start_turn); + design.start_curved = false; if (base.end_curved) - straight_at(End, design.end_curved, design.end_radius, design.end_turn); + design.end_curved = false; } } auto const &fit{*fitted}; diff --git a/editor/editorTrackShape.cpp b/editor/editorTrackShape.cpp index 0c856517..dd626bdb 100644 --- a/editor/editorTrackShape.cpp +++ b/editor/editorTrackShape.cpp @@ -680,7 +680,12 @@ editor_track::easing editor_track::ease_out_of(TTrack const &Neighbour, glm::dve result.curvature = end->curvature; if (std::abs(end->curvature) < 1e-4) return result; - result.length = std::max(20.0, alignment::recommend(Speed, 1.0 / std::abs(end->curvature), Limits).transition); + // the diverging track of a switch has no cant: run no faster than its curve lets with the unbalanced acceleration alone, the + // transition out of it is the one for that speed + auto speed{Speed}; + if (Neighbour.eType == tt_Switch) + speed = std::min(Speed, std::sqrt(12.96 * Limits.unbalanced / std::abs(end->curvature))); + result.length = std::max(20.0, alignment::recommend(speed, 1.0 / std::abs(end->curvature), Limits).transition); lay_transition(result, Joint, end->direction, Grade, end->roll); return result; } diff --git a/lang/editor_pl.po b/lang/editor_pl.po index e5fa198b..ac2c61de 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -952,6 +952,9 @@ msgstr "Kliknij co najmniej dwa punkty" msgid "The curvature changes abruptly where the track joins, there's no room for a transition curve" msgstr "Na styku z torem krzywizna zmienia się skokowo, nie ma miejsca na krzywą przejściową" +msgid "At the end of the switch the line goes on with the curve of the switch, and there's no room for the transition out of it here" +msgstr "Za końcem rozjazdu tor kontynuuje łuk rozjazdu, a nie ma tu miejsca na krzywą przejściową wychodzącą z niego" + msgid "Compound curve: R %.0f m meets R %.0f m with no transition curve between them" msgstr "Łuk koszowy: R %.0f m styka się z R %.0f m bez krzywej przejściowej między nimi"