From 4db3dd70d3c4ccdc0a32e0644c7955c3837ecadc Mon Sep 17 00:00:00 2001 From: maj00r Date: Wed, 21 Oct 2026 17:34:36 +0200 Subject: [PATCH] feat(editor): the free ends of the tracks are marked red in the track mode Each end of a rail track joined to nothing, where a train would run off, gets a red dot next to the white dots of the joints, in the 3D view near the camera and from above over the whole view. The ends are looked for again after an edit or once the camera leaves the place they were found for, not every frame. --- application/editormode.h | 10 ++++++++++ application/editormodelay.cpp | 15 +++++++++++++++ application/editormodetrack.cpp | 10 ++++++++++ application/editormodetrackshared.h | 1 + 4 files changed, 36 insertions(+) diff --git a/application/editormode.h b/application/editormode.h index 10d20e32..19114605 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1593,6 +1593,16 @@ class editor_mode : public application_mode, private editor_track::observer, pri void draw_track_intent() const; editor_track::snap_target snap_free_end(glm::dvec3 const &Near, glm::vec2 const &Screen, TTrack const *Self, int const Category, std::vector const &Exclude) const; void draw_free_ends(TTrack const *Self, int const Category, std::vector const &Exclude) const; + // the free ends of the rail tracks around the camera, looked for again after an edit or once the camera leaves the place + struct free_end_cache + { + int edits{-1}; + glm::dvec3 centre{0.0}; + double reach{0.0}; + std::vector points; + }; + mutable free_end_cache m_free_end_cache; + std::vector const &free_end_points(glm::dvec3 const &Centre, double const Reach) const; struct point_drag { bool active{false}; diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index 8dd852d2..e6943593 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -219,6 +219,21 @@ editor_track::snap_target editor_mode::snap_free_end(glm::dvec3 const &Near, glm return result; } +std::vector const &editor_mode::free_end_points(glm::dvec3 const &Centre, double const Reach) const +{ + auto &cache{m_free_end_cache}; + if (cache.edits != m_track_edits || glm::distance(cache.centre, Centre) > cache.reach * 0.25 || Reach > cache.reach * 1.01 || Reach < cache.reach * 0.5) + { + cache.edits = m_track_edits; + cache.centre = Centre; + cache.reach = Reach * 1.25; + cache.points.clear(); + for (auto const &end : editor_track::free_ends(nullptr, kRailCategory, Centre, cache.reach, {})) + cache.points.push_back(end.position); + } + return cache.points; +} + void editor_mode::draw_free_ends(TTrack const *Self, int const Category, std::vector const &Exclude) const { screen_projection const projection; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index b7e01380..fa749cda 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -2122,6 +2122,16 @@ void editor_mode::draw_build_overlay() const drawlist->AddCircleFilled(screen, 3.5f, kJointColor); } } + // the ends joined to nothing, where a train would run off + for (auto const &point : free_end_points(eye, Global.EditorOrtho ? std::max(kDotsRange, static_cast(Global.EditorOrthoExtent) * 2.0) : kDotsRange)) + { + ImVec2 screen; + if (in_reach(point) && projection.project(point, screen) && screen.x >= 0.0f && screen.y >= 0.0f && screen.x <= display.x && screen.y <= display.y) + { + drawlist->AddCircleFilled(screen, 5.0f, kFreeEndColor); + drawlist->AddCircle(screen, 5.0f, IM_COL32(0, 0, 0, 160), 12, 1.0f); + } + } if (m_extend.active) { if (m_extend.track != nullptr) diff --git a/application/editormodetrackshared.h b/application/editormodetrackshared.h index 9e60c62f..a3278716 100644 --- a/application/editormodetrackshared.h +++ b/application/editormodetrackshared.h @@ -151,6 +151,7 @@ double const kDrawnReach{100000.0}; double const kJointRange{400.0}; // the ends of the paths are drawn for the tracks this close to the camera double const kDotsRange{500.0}; // m, the dots of the ends of the tracks are drawn this close to the camera in the 3D view ImU32 const kJointColor{IM_COL32(255, 255, 255, 200)}; +ImU32 const kFreeEndColor{IM_COL32(240, 60, 60, 235)}; int const kRailCategory{1}; inline editor_track::branch_end branch_start(segment_data const &Diverging)