diff --git a/application/editormode.h b/application/editormode.h index b0550310..32c59c6b 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1141,6 +1141,7 @@ class editor_mode : public application_mode, private editor_track::observer bool plan_branch_link(editor_track::branch_link &Link, std::string &Reason) const; void finish_branch_link(editor_track::branch_link const &Link); std::string link_problem(editor_track::snap_target const &Target, editor_track::branch_link const &Link) const; + bool stretchable(editor_track::snap_target const &Target) const; std::vector link_tracks(editor_track::snap_target const &Target, editor_track::branch_link const &Link, TTrack const &Style, std::vector> &States, std::vector &Created); bool cut_straight(editor_track::straight const &Line, double const From, double const To, std::vector> &States, std::vector &Created, std::vector &Removed, TTrack **Style); bool insert_double_slip(editor_track::straight const &Line, glm::dvec3 const &Point, editor_track::switch_template const &Shape); diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 07c0f439..9d1ac2b7 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -155,6 +155,8 @@ std::string link_summary(editor_track::snap_target const &Target, editor_track:: text += format(STR_C(", sharper than the switch (R %.0f m)"), Switchradius); if (Link.trim > 0.0) text += format(STR_C(", %s shortened %.2f m"), name.c_str(), Link.trim); + else if (Link.trim < 0.0) + text += format(STR_C(", %s lengthened %.2f m"), name.c_str(), -Link.trim); return text; } @@ -5838,15 +5840,16 @@ std::string editor_mode::link_problem(editor_track::snap_target const &Target, e if (false == Link.valid) return Link.shortfall > 0.0 ? format(STR_C("The branch can't lead into %s: the R %.0f m curve needs %.2f m more room"), name.c_str(), Link.radius, Link.shortfall) : format(STR_C("The branch can't lead into %s"), name.c_str()); - if (Link.trim > 0.0) - { - auto const &path{Target.track->m_paths[Target.point.path]}; - if (has_controls(path) || geometry::chord_length(path) < Link.trim + 1.0) - return format(STR_C("%s would have to be shortened by %.2f m, it's too short or not straight"), name.c_str(), Link.trim); - } + if (Link.trim > 0.0 && (false == stretchable(Target) || geometry::chord_length(Target.track->m_paths[Target.point.path]) < Link.trim + 1.0)) + return format(STR_C("%s would have to be shortened by %.2f m, it's too short or not straight"), name.c_str(), Link.trim); return {}; } +bool editor_mode::stretchable(editor_track::snap_target const &Target) const +{ + return Target.track != nullptr && Target.track->eType == tt_Normal && Target.track->m_paths.size() == 1 && editor_track::is_straight(*Target.track, m_straights.tolerance); +} + bool editor_mode::plan_switch_link(switch_link &Plan) const { auto const &tool{m_switch}; @@ -5892,7 +5895,7 @@ bool editor_mode::plan_switch_link(switch_link &Plan) const 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)))); + editor_track::reverse_insert(std::min(editor_track::diverging_speed(radius), design_speed(nullptr, Plan.target.track))), stretchable(Plan.target)); Plan.reason = link_problem(Plan.target, Plan.link); return Plan.reason.empty(); }; @@ -5945,7 +5948,7 @@ bool editor_mode::plan_branch_link(editor_track::branch_link &Link, std::string auto const &diverging{tool.track->m_paths[1]}; 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)))); + editor_track::reverse_insert(std::min(editor_track::diverging_speed(radius), design_speed(tool.track, target.track))), stretchable(target)); Reason = link_problem(target, Link); return Reason.empty(); } @@ -5969,11 +5972,13 @@ void editor_mode::finish_branch_link(editor_track::branch_link const &Link) std::vector editor_mode::link_tracks(editor_track::snap_target const &Target, editor_track::branch_link const &Link, TTrack const &Style, std::vector> &States, std::vector &Created) { auto *target{Target.track}; - if (Link.trim > 0.0) + if (Link.trim != 0.0) { States.emplace_back(target, editor_track::capture(*target)); - auto const run{glm::length(plan_of(Target.direction))}; - editor_track::move_point(*target, Target.point, Target.position + Target.direction * (Link.trim / std::max(run, 1e-6))); + editor_track::move_point(*target, Target.point, Link.landing); + auto &path{target->m_paths[Target.point.path]}; + path.points[segment_data::point::control1] = glm::dvec3{0.0}; + path.points[segment_data::point::control2] = glm::dvec3{0.0}; editor_track::commit({target}); } std::vector pieces; diff --git a/editor/editorTrack.hpp b/editor/editorTrack.hpp index d63a157d..194f9d49 100644 --- a/editor/editorTrack.hpp +++ b/editor/editorTrack.hpp @@ -221,13 +221,14 @@ class editor_track double shortfall{0.0}; bool reverse{false}; double insert{0.0}; + glm::dvec3 landing{0.0}; std::vector pieces; }; 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); + static branch_link link_branch(branch_end const &From, double const Radius, branch_end const &To, double const Kink, double const Insert, bool const Stretch); struct snap_target { diff --git a/editor/editorTrackShape.cpp b/editor/editorTrackShape.cpp index 9f282a65..2770dd4c 100644 --- a/editor/editorTrackShape.cpp +++ b/editor/editorTrackShape.cpp @@ -497,7 +497,7 @@ std::optional editor_track::branch_shift(branch_end const &From, glm::dv 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) +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, bool const Stretch) { branch_link result; if (glm::length(From.direction) < 1e-9 || glm::length(To.direction) < 1e-9 || Radius < 1.0) @@ -555,7 +555,7 @@ editor_track::branch_link editor_track::link_branch(branch_end const &From, doub return result; } } - if (result.after < -0.01) + if (result.after < -0.01 || (Stretch && result.after >= 0.01)) { result.trim = -result.after; result.after = 0.0; @@ -592,7 +592,7 @@ editor_track::branch_link editor_track::link_branch(branch_end const &From, doub result.pieces.back().points[segment_data::point::end] = {target.x, 0.0, target.y}; if (false == result.pieces.empty()) { - auto const height1{result.trim > 0.0 ? To.position.y + To.grade * result.trim : To.position.y}; + auto const height1{To.position.y + To.grade * result.trim}; ground_follow::follow(result.pieces, {From.position.y, From.grade, height1, To.grade}, [](std::vector const &Points, std::vector const &) { return std::vector(Points.size(), std::numeric_limits::quiet_NaN()); }); std::vector lengths; double total{0.0}; @@ -607,6 +607,7 @@ editor_track::branch_link editor_track::link_branch(branch_end const &From, doub result.pieces[i].rolls = {static_cast(from), static_cast(to)}; } } + result.landing = result.pieces.empty() ? From.position : result.pieces.back().points[segment_data::point::end]; result.valid = true; return result; } diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 738c3a82..7f9d77f9 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -5464,6 +5464,9 @@ msgstr "Odgałęzienie wchodzi w %s prostą" msgid ", %s shortened %.2f m" msgstr ", %s skrócony o %.2f m" +msgid ", %s lengthened %.2f m" +msgstr ", %s wydłużony o %.2f m" + msgid "The branch can't lead into %s: the R %.0f m curve needs %.2f m more room" msgstr "Odgałęzienie nie wejdzie w %s: łuk R %.0f m potrzebuje %.2f m więcej miejsca"