diff --git a/application/editormode.cpp b/application/editormode.cpp index 061f2fb1..04cfc07a 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -5583,7 +5583,7 @@ void editor_mode::render_shortcuts_window() {"Ctrl+F", "Find a track by its name"}, {"Shift+LMB", "Add a track to the selection, drag: a box"}, {"RMB on a track", "What can be done with it"}, - {"K", "Split the selected track at the cursor"}, + {"K", "Split the selected track at the cursor, a break of the grade at the height of the ground"}, {"L, LMB, LMB...", "Lay track: each click lays a piece and goes on from its end"}, {"Drag from a free end", "Lead a track out of it; onto another free end: join the two"}, {"Ctrl+wheel", "Laying: radius"}, diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index b74389cb..f1e529ad 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -65,6 +65,7 @@ editor_mode::selftest_result editor_mode::selftest_dispatch(std::string const &c // camera from the first point, looking at the second // select // selectat the path nearest the point, within 3 m, as a click on it +// kbreak K on the track nearest the point: split there, a break of the grade at the height of the ground // blade [name] logs the blades of each switch cut from the rails: tip, 50 mm head, full head, heel, drop of the head, open flangeway, the gauge lines apart against x^2/2R, vertices in both positions // frog [name] logs where the inner rails of each switch cross: distance on both paths, 1:n, throat, nose, check rails // guards [name] logs each guard rail and what each of its ends and breaks is cut along; a fault when a cut is not along a rail or a glued end not on the guard rail of the other track diff --git a/application/editormodeselftestscene.cpp b/application/editormodeselftestscene.cpp index b939d597..49e550d2 100644 --- a/application/editormodeselftestscene.cpp +++ b/application/editormodeselftestscene.cpp @@ -93,6 +93,37 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm WriteLog(format("SELFTEST selectat %.1f %.1f: %s", point.x, point.z, m_node != nullptr ? m_node->name().c_str() : "nothing")); return selftest_result::handled; } + if (command == "kbreak") + { + // K on the track nearest the point: split there, the point between at the height of the ground and the ballast + glm::dvec3 point{0.0}; + words >> point.x >> point.z; + TTrack *nearest{nullptr}; + double distance{1e9}; + for (auto *track : simulation::Paths.sequence()) + if (track != nullptr && false == track->m_editorremoved && false == track->m_paths.empty() && track->eType == tt_Normal) + if (auto const d{geometry::plan_distance(editor_track::point_at(*track, editor_track::nearest_parameter(*track, point)), point)}; d < distance) + { + distance = d; + nearest = track; + } + if (nearest == nullptr || distance > 3.0) + { + WriteLog(format("SELFTEST kbreak %.1f %.1f: no track", point.x, point.z)); + return selftest_result::handled; + } + auto const tracks{simulation::Paths.sequence().size()}; + split_track_at(*nearest, point); + auto const &path{nearest->m_paths.front()}; + auto const joint{path.points[segment_data::point::end]}; + std::vector found; + auto const ground{ground_heights({glm::dvec3{joint.x, joint.y + 50.0, joint.z}}, true, &found).front()}; + geometry::bezier const curve{path}; + auto const rise = [](glm::dvec3 const &Tangent) { return 1000.0 * Tangent.y / std::max(1e-9, glm::length(geometry::plan_of(Tangent))); }; + WriteLog(format("SELFTEST kbreak %s: %zu tracks more, joint %.2f %.3f %.2f, ground %.3f (found %d), grade %.2f -> %.2f permille", nearest->name().c_str(), simulation::Paths.sequence().size() - tracks, joint.x, joint.y, joint.z, ground, found[0], rise(curve.first(0.0)), + rise(curve.first(1.0)))); + return selftest_result::handled; + } if (command == "select") { std::string name; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 8b800cd9..df0c751e 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -1800,7 +1800,7 @@ std::vector editor_mode::track_key_hints(bool const All) { if (gizmo && m_gizmo_snap > 0.0f) hints.push_back({"Ctrl", format("gizmo snaps by %.2f m", m_gizmo_snap)}); - hints.push_back({"K", "split the path under the cursor"}); + hints.push_back({"K", "split the path under the cursor, a break of the grade at the height of the ground"}); hints.push_back({"O", "top view"}); hints.push_back({"Esc", "back to Select"}); if (Global.EditorOrtho) diff --git a/application/editormodetrackux.cpp b/application/editormodetrackux.cpp index 64fe2d8c..4e522a90 100644 --- a/application/editormodetrackux.cpp +++ b/application/editormodetrackux.cpp @@ -1076,6 +1076,22 @@ void editor_mode::split_track_at(TTrack &Track, glm::dvec3 const &Point) auto const before{editor_track::capture(Track)}; if (auto *created{editor_track::split_path(Track, parameter)}) { + // a break of the grade, as a point of a road: the point between the two takes the height of the ground and the ballast + // there, each of them an even grade from its other end up to it + auto const &path{Track.m_paths.front()}; + auto const joint{path.points[segment_data::point::end]}; + auto const height{bed_height(joint, geometry::plan_of(geometry::bezier{path}.first(1.0)), &Track)}; + auto const none{std::numeric_limits::quiet_NaN()}; + auto const unknown = [](std::vector const &Points, std::vector const &) { return std::vector(Points.size(), std::numeric_limits::quiet_NaN()); }; + for (auto *part : {&Track, created}) + { + std::vector pieces{part->m_paths.front()}; + auto &points{pieces.front().points}; + points[part == &Track ? segment_data::point::end : segment_data::point::start].y = height; + ground_follow::follow(pieces, {points[segment_data::point::start].y, none, points[segment_data::point::end].y, none}, unknown); + part->m_paths.front() = pieces.front(); + } + editor_track::commit({&Track, created}); push_track_snapshot({{&Track, before}}, {created}); straight_refresh(); } @@ -1147,7 +1163,7 @@ void editor_mode::render_track_context() ImGui::EndMenu(); } ImGui::Separator(); - if (ImGui::MenuItem(STR_C("Split here"), "K", false, normal)) + if (ImGui::MenuItem(STR_C("Split here, a break of the grade"), "K", false, normal)) split_track_at(*track, point); ImGui::Separator(); if (ImGui::MenuItem(STR_C("Switch"), "T", false, normal || track->eType == tt_Switch)) diff --git a/lang/editor_pl.po b/lang/editor_pl.po index aeaf3758..69b45229 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -240,8 +240,8 @@ msgstr "zastosuj" msgid "release the vertex" msgstr "puszcza wierzchołek" -msgid "split the path under the cursor" -msgstr "podziel tor pod kursorem" +msgid "split the path under the cursor, a break of the grade at the height of the ground" +msgstr "podziel tor pod kursorem, załamanie niwelety na wysokości terenu" msgid "top view" msgstr "widok z góry" @@ -1743,8 +1743,8 @@ msgstr "Rozstaw torów (m)" msgid "Speed check of the line" msgstr "Sprawdź prędkość linii" -msgid "Split here" -msgstr "Podziel tutaj" +msgid "Split here, a break of the grade" +msgstr "Podziel tutaj, załamanie niwelety" msgid "Step (m)" msgstr "Uskok (m)" @@ -4083,8 +4083,8 @@ msgstr "Przyciąganie do kroku z ustawień gizma" msgid "Split the road at the cursor, or make a point there" msgstr "Podziel drogę przy kursorze albo zrób tam punkt" -msgid "Split the selected track at the cursor" -msgstr "Podziel zaznaczony tor przy kursorze" +msgid "Split the selected track at the cursor, a break of the grade at the height of the ground" +msgstr "Podziel zaznaczony tor przy kursorze, załamanie niwelety na wysokości terenu" msgid "Takes the last change back" msgstr "Cofa ostatnią zmianę"