diff --git a/application/editormode.h b/application/editormode.h index 5df3f4c2..b0550310 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1132,6 +1132,7 @@ class editor_mode : public application_mode, private editor_track::observer double along{0.0}; int forward{1}; int side{1}; + double moved{0.0}; std::vector paths; std::string reason; }; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index f84d4643..07c0f439 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -5884,15 +5884,33 @@ bool editor_mode::plan_switch_link(switch_link &Plan) const } if (shape.length > line.length - 0.02) return false; + auto const kink{glm::radians(m_joints.angle * 0.5)}; + auto const plan = [&](double const Along) { + Plan.along = Along; + Plan.paths = place(Along); + if (Plan.paths.size() < 2) + return false; + auto const radius{editor_track::branch_radius(Plan.paths[1])}; + Plan.link = editor_track::link_branch(branch_start(Plan.paths[1]), radius, branch_target(Plan.target), kink, + editor_track::reverse_insert(std::min(editor_track::diverging_speed(radius), design_speed(nullptr, Plan.target.track)))); + Plan.reason = link_problem(Plan.target, Plan.link); + return Plan.reason.empty(); + }; auto const from{switch_from(line, shape.length, tool.along, Plan.forward, true)}; - Plan.along = Plan.forward > 0 ? from : from + shape.length; - Plan.paths = place(Plan.along); - if (Plan.paths.size() < 2) + auto const snapped{Plan.forward > 0 ? from : from + shape.length}; + auto const paths{place(snapped)}; + if (paths.size() < 2) return false; - Plan.link = editor_track::link_branch(branch_start(Plan.paths[1]), editor_track::branch_radius(Plan.paths[1]), branch_target(Plan.target), glm::radians(m_joints.angle * 0.5), - editor_track::reverse_insert(design_speed(line.tracks.front(), Plan.target.track))); - Plan.reason = link_problem(Plan.target, Plan.link); - return Plan.reason.empty(); + if (auto const shift{editor_track::branch_shift(branch_start(paths[1]), line.direction * static_cast(Plan.forward), editor_track::branch_radius(paths[1]), branch_target(Plan.target), kink)}) + { + auto const along{snapped + *shift * Plan.forward}; + auto const begin{Plan.forward > 0 ? along : along - shape.length}; + Plan.moved = std::abs(*shift); + if (begin >= -1e-6 && begin + shape.length <= line.length + 1e-6 && plan(along) && false == Plan.link.reverse) + return true; + } + Plan.moved = 0.0; + return plan(snapped); } void editor_mode::insert_linked_switch(switch_link const &Plan) @@ -5908,7 +5926,10 @@ void editor_mode::insert_linked_switch(switch_link const &Plan) straight_refresh(); m_switch.status.clear(); switch_placed(placed); - m_switch.status = link_summary(Plan.target, Plan.link, editor_track::branch_radius(Plan.paths[1])) + (m_switch.status.empty() ? std::string{} : "\n" + m_switch.status); + auto summary{link_summary(Plan.target, Plan.link, editor_track::branch_radius(Plan.paths[1]))}; + if (Plan.moved >= 0.005) + summary += format(STR_C(", the switch moved %.2f m"), Plan.moved); + m_switch.status = summary + (m_switch.status.empty() ? std::string{} : "\n" + m_switch.status); ui()->set_status(m_switch.status, false); } @@ -5922,7 +5943,9 @@ bool editor_mode::plan_branch_link(editor_track::branch_link &Link, std::string if (std::find(tool.line.begin(), tool.line.end(), target.track) != tool.line.end()) return false; auto const &diverging{tool.track->m_paths[1]}; - Link = editor_track::link_branch(branch_start(diverging), editor_track::branch_radius(diverging), branch_target(target), glm::radians(m_joints.angle * 0.5), editor_track::reverse_insert(design_speed(tool.track, target.track))); + auto const radius{editor_track::branch_radius(diverging)}; + Link = editor_track::link_branch(branch_start(diverging), radius, branch_target(target), glm::radians(m_joints.angle * 0.5), + editor_track::reverse_insert(std::min(editor_track::diverging_speed(radius), design_speed(tool.track, target.track)))); Reason = link_problem(target, Link); return Reason.empty(); } diff --git a/editor/editorTrack.hpp b/editor/editorTrack.hpp index ad1ab085..d63a157d 100644 --- a/editor/editorTrack.hpp +++ b/editor/editorTrack.hpp @@ -225,6 +225,8 @@ class editor_track }; static double branch_radius(segment_data const &Diverging); static double reverse_insert(double const Speed); + static double diverging_speed(double const Radius); + static std::optional branch_shift(branch_end const &From, glm::dvec2 const &Slide, double const Radius, branch_end const &To, double const Kink); static branch_link link_branch(branch_end const &From, double const Radius, branch_end const &To, double const Kink, double const Insert); struct snap_target diff --git a/editor/editorTrackShape.cpp b/editor/editorTrackShape.cpp index 9cc4cc3d..9f282a65 100644 --- a/editor/editorTrackShape.cpp +++ b/editor/editorTrackShape.cpp @@ -386,6 +386,19 @@ double editor_track::reverse_insert(double const Speed) return Speed <= 100.0 ? 0.15 * Speed : 0.25 * Speed; } +double editor_track::diverging_speed(double const Radius) +{ + if (Radius < 300.0) + return 40.0; + if (Radius < 500.0) + return 50.0; + if (Radius < 760.0) + return 60.0; + if (Radius < 1200.0) + return 80.0; + return Radius < 2500.0 ? 100.0 : 130.0; +} + namespace { @@ -455,6 +468,35 @@ std::optional fit_reverse(glm::dvec2 const &Offset, glm::dvec2 cons } // namespace +std::optional editor_track::branch_shift(branch_end const &From, glm::dvec2 const &Slide, double const Radius, branch_end const &To, double const Kink) +{ + if (glm::length(From.direction) < 1e-9 || glm::length(To.direction) < 1e-9 || glm::length(Slide) < 1e-9) + return std::nullopt; + auto const slide{glm::normalize(Slide)}; + auto const tangent{glm::normalize(From.direction)}; + auto const into{glm::normalize(To.direction)}; + auto const turn{signed_angle(tangent, into)}; + auto const offset{plan_of(To.position) - plan_of(From.position)}; + auto const across{cross(into, slide)}; + if (std::abs(turn) > glm::radians(170.0)) + return std::nullopt; + if (std::abs(turn) <= Kink) + { + if (std::abs(across) < 1e-6) + return std::nullopt; + return cross(into, offset) / across; + } + if (Radius < 1.0) + return std::nullopt; + auto const gap{offset - unit_chord(tangent, turn) * Radius}; + if (std::abs(across) >= std::sin(glm::radians(1.0))) + return cross(into, gap) / across; + auto const determinant{cross(tangent, slide)}; + if (std::abs(determinant) < 1e-6 || cross(gap, slide) / determinant < -0.01) + return std::nullopt; + return cross(tangent, gap) / determinant; +} + editor_track::branch_link editor_track::link_branch(branch_end const &From, double const Radius, branch_end const &To, double const Kink, double const Insert) { branch_link result; @@ -508,6 +550,7 @@ editor_track::branch_link editor_track::link_branch(branch_end const &From, doub } else if (false == reverse()) { + result.radius = Radius; result.shortfall = std::max(0.01, -result.before); return result; } diff --git a/lang/editor_pl.po b/lang/editor_pl.po index dd3af8ca..738c3a82 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -5481,3 +5481,6 @@ msgstr ", między nimi prosta %.1f m" msgid ", sharper than the switch (R %.0f m)" msgstr ", ostrzej niż rozjazd (R %.0f m)" + +msgid ", the switch moved %.2f m" +msgstr ", rozjazd przesunięty o %.2f m"