diff --git a/application/editormode.h b/application/editormode.h index 3afb6341..1879ea1c 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1730,7 +1730,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri }; handle_drag m_handle_drag; void handle_drag_start(glm::dvec3 const &Anchor); - bool handle_drag_step(glm::dvec3 &Position); + // Ground: the handle goes onto the ground, at the height of the ballast of the track, unless Shift is held + bool handle_drag_step(glm::dvec3 &Position, TTrack const *Ground = nullptr); void point_drag_start(editor_track::point_ref const &Point); void point_drag_update(); void point_drag_finish(); diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index 6ba7c998..65877b5e 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -283,7 +283,7 @@ void editor_mode::handle_drag_start(glm::dvec3 const &Anchor) m_handle_drag.offset = {Anchor.x - level.x, 0.0, Anchor.z - level.z}; } -bool editor_mode::handle_drag_step(glm::dvec3 &Position) +bool editor_mode::handle_drag_step(glm::dvec3 &Position, TTrack const *Ground) { auto &drag{m_handle_drag}; auto const &io{ImGui::GetIO()}; @@ -301,7 +301,13 @@ bool editor_mode::handle_drag_step(glm::dvec3 &Position) screen_projection const projection; glm::dvec3 level; if (projection.on_level(io.MousePos, drag.height, level) && (Global.editor_tracks || glm::distance(level, glm::dvec3{Global.pCamera.Pos}) <= static_cast(kMaxPlacementDistance))) + { drag.position = level + drag.offset; + if (Ground != nullptr && false == io.KeyShift) + drag.position.y = bed_height(drag.position, {0.0, 0.0}, Ground); + else + drag.position.y = drag.height; + } Position = drag.position; return true; } @@ -376,6 +382,13 @@ void editor_mode::point_drag_update() glm::dvec3 position; if (false == projection.on_level(io.MousePos, drag.height, position) || (false == Global.editor_tracks && glm::distance(position, glm::dvec3{Global.pCamera.Pos}) > static_cast(kMaxPlacementDistance))) return; + // an end goes onto the ground at the height of the ballast, as a point laid; with Shift it keeps its height + if (editor_track::is_end(m_track_point.kind) && false == io.KeyShift) + { + auto const &path{track->m_paths[m_track_point.path]}; + auto const tangent{geometry::bezier{path}.first(m_track_point.kind == editor_track::point_kind::end ? 1.0 : 0.0)}; + position.y = bed_height(position, plan_of(tangent), track); + } m_track_snap = {}; if (editor_track::is_end(m_track_point.kind) && m_track_drag_points.empty()) { diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index f1e529ad..52d74d2e 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 +// trackends logs the ends of the first path of the track against the ground under them // 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 diff --git a/application/editormodeselftestscene.cpp b/application/editormodeselftestscene.cpp index 49e550d2..771575bf 100644 --- a/application/editormodeselftestscene.cpp +++ b/application/editormodeselftestscene.cpp @@ -93,6 +93,26 @@ 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 == "trackends") + { + // the ends of the first path of the track, against the ground under them + std::string name; + words >> name; + auto const *track{simulation::Paths.find(name)}; + if (track == nullptr || track->m_paths.empty()) + { + WriteLog("SELFTEST trackends " + name + ": no such track"); + return selftest_result::handled; + } + for (auto const end : {segment_data::point::start, segment_data::point::end}) + { + auto const &point{track->m_paths.front().points[end]}; + std::vector found; + auto const ground{ground_heights({glm::dvec3{point.x, point.y + 50.0, point.z}}, true, &found).front()}; + WriteLog(format("SELFTEST trackends %s %s: %.2f %.3f %.2f, ground %.3f (found %d)", name.c_str(), end == segment_data::point::start ? "start" : "end", point.x, point.y, point.z, ground, found[0])); + } + 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 diff --git a/application/editormodestraights.cpp b/application/editormodestraights.cpp index d65d302c..e5f23c66 100644 --- a/application/editormodestraights.cpp +++ b/application/editormodestraights.cpp @@ -604,7 +604,8 @@ void editor_mode::render_straight_gizmo() glm::dvec3 const anchors[] = {line.start, line.end, (line.start + line.end) * 0.5}; glm::dvec3 handled{anchors[state.handle]}; - bool const held{handle_drag_step(handled)}; + // the ends go onto the ground, the middle moves the line in plan alone + bool const held{handle_drag_step(handled, state.handle == 2 ? nullptr : line.tracks.front())}; if (false == held && false == state.dragging) return; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index df0c751e..5b097ec7 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -1781,7 +1781,7 @@ std::vector editor_mode::track_key_hints(bool const All) action = "rings about the point: direction, grade, cant; the joined tracks follow"; else if (m_gizmo_op == gizmo_operation::scale && selected != nullptr && track_gizmo_operation(*selected, true) == gizmo_operation::scale) action = "lengthens the track at this end, the curve keeps its radius"; - hints = {{"Drag a point", "moves it, an end dropped on a free end joins it"}, {"Gizmo", action}, {"Q W E", "gizmo: move, turn, lengthen"}, {"Esc", "releases the point"}}; + hints = {{"Drag a point", "moves it, an end onto the ground (Shift: keeps its height), dropped on a free end joins it"}, {"Gizmo", action}, {"Q W E", "gizmo: move, turn, lengthen"}, {"Esc", "releases the point"}}; gizmo = true; } else diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 69b45229..f44ce4c6 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -2204,8 +2204,8 @@ msgstr "koniec się z nim łączy" msgid "done" msgstr "gotowe" -msgid "moves it, an end dropped on a free end joins it" -msgstr "przesuwa go, koniec upuszczony na wolny koniec łączy się" +msgid "moves it, an end onto the ground (Shift: keeps its height), dropped on a free end joins it" +msgstr "przesuwa go, koniec na teren (Shift: zostaje na swojej wysokości), upuszczony na wolny koniec łączy się" msgid "Gizmo" msgstr "Gizmo"