From 133ba9cb45a0561b79dd9e1a6917ad47a80deb63 Mon Sep 17 00:00:00 2001 From: maj00r Date: Sat, 24 Oct 2026 22:28:43 +0200 Subject: [PATCH] fix(editor): the heights from point to point broke the grade only at the bends of straights which stay bends, a curve traced or bends clicked close along a curve going at one grade from one of its ends to the other, attached there; and two tracks laid no longer meet at two heights where a point was clicked within 5 m of their joint, each end of a piece not cut there taking the height of its own stretch, not of the one the middle of the piece lies on (steps of 0.6 m on a steep grade in abc). Unit tests of the heights from point to point --- application/editormode.h | 3 +++ application/editormodelay.cpp | 16 +++++++++++-- editor/editorGroundFollow.cpp | 7 ++++-- lang/editor_pl.po | 3 +++ tests/unit/CMakeLists.txt | 3 +++ tests/unit/test_heights.cpp | 42 +++++++++++++++++++++++++++++++++++ 6 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_heights.cpp diff --git a/application/editormode.h b/application/editormode.h index 72f02054..390aa04e 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1409,6 +1409,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri std::vector traces; // the straights of a fixed direction the next bend slides along: from a free end, out of a curve traced std::vector> guides; + // where the grade breaks from point to point: the bends kept as such, at the heights clicked; a curve traced, or bends made + // one curve, goes at one grade from end to end + std::vector knots; }; // lays new track through the clicked points, with no path needed to start from struct lay_tool diff --git a/application/editormodelay.cpp b/application/editormodelay.cpp index 0161a1a5..9d794a3f 100644 --- a/application/editormodelay.cpp +++ b/application/editormodelay.cpp @@ -1029,7 +1029,7 @@ std::vector editor_mode::lay_pieces(std::vector const if (EditorSettings.heights() == editorSettings::lay_heights::fitted) follow_ground(pieces, Points.front().y, grade0, Points.back().y, grade1, style); else - ground_follow::follow_points(pieces, std::vector(Points.begin() + 1, Points.end() - 1), {Points.front().y, grade0, Points.back().y, grade1}); + ground_follow::follow_points(pieces, plan.knots, {Points.front().y, grade0, Points.back().y, grade1}); if (Plan != nullptr) *Plan = std::move(plan); return pieces; @@ -1279,6 +1279,18 @@ bool editor_mode::lay_line(std::vector const &Points, std::vector(EditorSettings.heights())}; segmented("layheights", heights, {{0, STR_C("Fitted"), "The grades fitted to the ground as Tracks onto the terrain fits them: vertical curves of the norms, the bumps of the ground gone past; the terrain is left as it is. On the terrain model the whole track laid in a row is fitted again at each click"}, - {1, STR_C("Point to point"), "Each point clicked at the height of the ground, an even grade between them: the grade changes only where you click"}, + {1, STR_C("Point to point"), "Each bend of the straights clicked at the height of the ground, an even grade between them: the grade changes only at the bends. A curve traced, or bends clicked close along a curve, goes at an even grade from one end of it to the other"}, {2, STR_C("Flat"), "The track goes on at the height it's laid from, whatever the ground; the first point on the ground"}})) { EditorSettings.heights(static_cast(heights)); diff --git a/editor/editorGroundFollow.cpp b/editor/editorGroundFollow.cpp index 19220bb4..dcedfb0c 100644 --- a/editor/editorGroundFollow.cpp +++ b/editor/editorGroundFollow.cpp @@ -427,10 +427,13 @@ void follow_points(std::vector &Pieces, std::vector co knots.push_back(total); heights.push_back(Ends.height1); auto const last{knots.size() - 1}; - // the height at the chainage on the stretch Middle is on, an end of it taken at a knot + // the height at the chainage on its stretch; at a knot itself on the one Middle is on, for the grade of the piece there. A piece + // not cut at a knot too near its end lies on two stretches, each of its ends on its own auto const at = [&](double const Chainage, double const Middle, double &Grade) { std::size_t stretch{0}; - while (stretch + 1 < last && Middle > knots[stretch + 1]) + while (stretch + 1 < last && Chainage > knots[stretch + 1] + 1e-6) + ++stretch; + if (stretch + 1 < last && std::abs(Chainage - knots[stretch + 1]) <= 1e-6 && Middle > knots[stretch + 1]) ++stretch; auto const span{knots[stretch + 1] - knots[stretch]}; auto const even{(heights[stretch + 1] - heights[stretch]) / span}; diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 7fe7761b..48ca9766 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -11902,3 +11902,6 @@ msgstr "Dwie krzywe przejściowe, bez łuku" msgid "The bend eased the way the lines are drawn: two transition curves meeting at the radius, with no arc between them and no cant; their lengths follow from the radius and the angle" msgstr "Załamanie wyokrąglone tak, jak projektuje się linie: dwie krzywe przejściowe stykające się przy promieniu, bez łuku między nimi i bez przechyłki; ich długości wynikają z promienia i kąta" + +msgid "Each bend of the straights clicked at the height of the ground, an even grade between them: the grade changes only at the bends. A curve traced, or bends clicked close along a curve, goes at an even grade from one end of it to the other" +msgstr "Każde kliknięte załamanie prostych na wysokości terenu, między nimi równe pochylenie: pochylenie zmienia się tylko na załamaniach. Łuk odrysowany albo załamania kliknięte gęsto wzdłuż łuku idą jednym pochyleniem od jego początku do końca" diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 38bf6cb2..c91f7ebf 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -17,6 +17,9 @@ add_executable(${UNIT_TESTS_NAME} editor_stubs.cpp # the geometry of the lines the track editor designs, standing on its own "${CMAKE_SOURCE_DIR}/editor/editorAlignment.cpp" + # and the heights of the tracks laid + "${CMAKE_SOURCE_DIR}/editor/editorGroundFollow.cpp" + "${CMAKE_SOURCE_DIR}/editor/editorProfile.cpp" ${UNIT_TEST_CASES}) # the core library brings the game's build settings along diff --git a/tests/unit/test_heights.cpp b/tests/unit/test_heights.cpp new file mode 100644 index 00000000..78b761bd --- /dev/null +++ b/tests/unit/test_heights.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "doctest.h" +#include "editor/editorGroundFollow.hpp" + +#include +#include + +namespace { + +segment_data straight(double const From, double const To) { + segment_data piece; + piece.points[segment_data::point::start] = {From, 0.0, 0.0}; + piece.points[segment_data::point::end] = {To, 0.0, 0.0}; + return piece; +} + +} // namespace + +TEST_CASE("heights: from point to point the tracks meet at one height where a point is clicked just past a joint") { + // three tracks of 40 m, the grade breaking 3 m past the first joint and 2 m short of the second one, steeply + std::vector pieces{straight(0.0, 40.0), straight(40.0, 80.0), straight(80.0, 120.0)}; + auto const unknown{std::numeric_limits::quiet_NaN()}; + + ground_follow::follow_points(pieces, {{43.0, -5.0, 0.0}, {78.0, 3.0, 0.0}}, {0.0, unknown, 0.0, unknown}); + + REQUIRE(pieces.size() >= 3); + for (std::size_t i = 0; i + 1 < pieces.size(); ++i) + CHECK(pieces[i].points[segment_data::point::end].y == doctest::Approx(pieces[i + 1].points[segment_data::point::start].y).epsilon(1e-9)); + CHECK(pieces.front().points[segment_data::point::start].y == doctest::Approx(0.0)); + CHECK(pieces.back().points[segment_data::point::end].y == doctest::Approx(0.0)); +} + +TEST_CASE("heights: with no point between the ends the grade is even from one end to the other") { + std::vector pieces{straight(0.0, 50.0), straight(50.0, 100.0)}; + auto const unknown{std::numeric_limits::quiet_NaN()}; + + ground_follow::follow_points(pieces, {}, {10.0, unknown, 12.0, unknown}); + + REQUIRE(pieces.size() == 2); + CHECK(pieces[0].points[segment_data::point::end].y == doctest::Approx(11.0)); + CHECK(pieces[1].points[segment_data::point::start].y == doctest::Approx(11.0)); +}