From 2beae153907967db92965145e94c1c60f6dddabb Mon Sep 17 00:00:00 2001 From: maj00r Date: Sun, 11 Oct 2026 12:32:03 +0200 Subject: [PATCH] feat(editor): laying with no ground under the cursor takes the height of the ground around - with nothing under the cursor the height is the mean of the ground found on the nearest ring around the point, 10 to 400 m out, plus the depth of the ballast, instead of 0; the ray of the cursor meets that height - the ground under the cursor is looked for up to the height of the camera, not only 50 m over the last point --- application/editormode.h | 2 ++ application/editormodetrack.cpp | 47 +++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/application/editormode.h b/application/editormode.h index 2a40a3f0..d3b35297 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1146,6 +1146,8 @@ class editor_mode : public application_mode, private editor_track::observer glm::dvec3 cursor_level(double const Height) const; glm::dvec3 cursor_terrain(double const Height); double bed_height(glm::dvec3 const &Point, glm::dvec2 const &Direction, TTrack const *Style) const; + double nearby_ground(glm::dvec3 const &Point) const; + static std::pair trackbed(TTrack const *Style); std::vector bed_heights(std::vector const &Points, std::vector const &Directions, TTrack const *Style) const; void follow_ground(std::vector &Pieces, double const Height0, double const Grade0, double const Height1, double const Grade1, TTrack const *Style) const; glm::dvec3 lay_bed(glm::dvec3 const &Point); diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 16de5cda..7b6ea0b9 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -3994,21 +3994,55 @@ glm::dvec3 editor_mode::cursor_terrain(double const Height) for (int i = 0; i < 5 && std::isfinite(point.x) && std::isfinite(point.z); ++i) { std::vector found; - auto const heights{ground_heights({point}, true, &found)}; + auto ground{ground_heights({glm::dvec3{point.x, std::max(point.y, static_cast(Global.pCamera.Pos.y)), point.z}}, true, &found).front()}; if (found[0] == 0) + ground = nearby_ground(point); + if (std::isnan(ground)) return point; - auto const next{cursor_level(heights[0])}; + auto const next{cursor_level(ground)}; auto const settled{plan_distance(next, point) < 0.01}; - point = {next.x, heights[0], next.z}; + point = {next.x, ground, next.z}; if (settled) break; } return point; } +double editor_mode::nearby_ground(glm::dvec3 const &Point) const +{ + auto const ceiling{std::max(Point.y, static_cast(Global.pCamera.Pos.y))}; + for (double const radius : {10.0, 25.0, 50.0, 100.0, 200.0, 400.0}) + { + std::vector probes; + for (int i = 0; i < 12; ++i) + { + auto const angle{glm::two_pi() * i / 12.0}; + probes.push_back({Point.x + radius * std::cos(angle), ceiling, Point.z + radius * std::sin(angle)}); + } + std::vector found; + auto const heights{ground_heights(probes, true, &found)}; + double sum{0.0}; + int count{0}; + for (std::size_t i = 0; i < probes.size(); ++i) + if (found[i] != 0) + { + sum += heights[i]; + ++count; + } + if (count > 0) + return sum / count; + } + return std::numeric_limits::quiet_NaN(); +} + +std::pair editor_mode::trackbed(TTrack const *Style) +{ + return Style != nullptr ? profile_ballast(*Style) : std::pair{0.2, 0.5 * 1.435 + 0.5 + 1.1}; +} + std::vector editor_mode::bed_heights(std::vector const &Points, std::vector const &Directions, TTrack const *Style) const { - auto const [depth, half]{Style != nullptr ? profile_ballast(*Style) : std::pair{0.2, 0.5 * 1.435 + 0.5 + 1.1}}; + auto const [depth, half]{trackbed(Style)}; std::vector probes; probes.reserve(Points.size() * 3); for (std::size_t i = 0; i < Points.size(); ++i) @@ -4040,7 +4074,10 @@ std::vector editor_mode::bed_heights(std::vector const &Poin double editor_mode::bed_height(glm::dvec3 const &Point, glm::dvec2 const &Direction, TTrack const *Style) const { auto const height{bed_heights({Point}, {Direction}, Style).front()}; - return std::isnan(height) ? Point.y : height; + if (false == std::isnan(height)) + return height; + auto const nearby{nearby_ground(Point)}; + return std::isnan(nearby) ? Point.y : nearby + trackbed(Style).first; } void editor_mode::follow_ground(std::vector &Pieces, double const Height0, double const Grade0, double const Height1, double const Grade1, TTrack const *Style) const