17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 22:54:54 +01:00

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

This commit is contained in:
maj00r
2026-10-24 22:28:43 +02:00
parent 4602f727bb
commit 133ba9cb45
6 changed files with 70 additions and 4 deletions

View File

@@ -1409,6 +1409,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri
std::vector<lay_trace> traces;
// the straights of a fixed direction the next bend slides along: from a free end, out of a curve traced
std::vector<std::pair<glm::dvec3, glm::dvec3>> 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<glm::dvec3> knots;
};
// lays new track through the clicked points, with no path needed to start from
struct lay_tool

View File

@@ -1029,7 +1029,7 @@ std::vector<segment_data> editor_mode::lay_pieces(std::vector<glm::dvec3> 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<glm::dvec3>(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<glm::dvec3> const &Points, std::vector<la
Error = Plan.shape.errors.empty() ? std::string{STR_C("The track can't be laid through these points")} : Plan.shape.errors.front();
return false;
}
// the grade breaks at the bends which stayed bends; along a curve, traced or made of bends, it goes on even from end to end
for (std::size_t k = 0; k < design.vertices.size() && k < Plan.corners.size(); ++k)
{
if (Plan.corners[k] != 1)
continue;
for (auto const &bend : bends)
if (bend.corner && glm::distance(plan_of(bend.position), design.vertices[k].position) < 1e-3)
{
Plan.knots.push_back(bend.position);
break;
}
}
return true;
}
@@ -1739,7 +1751,7 @@ void editor_mode::render_lay_ui()
if (int heights{static_cast<int>(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<editorSettings::lay_heights>(heights));

View File

@@ -427,10 +427,13 @@ void follow_points(std::vector<segment_data> &Pieces, std::vector<glm::dvec3> 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};

View File

@@ -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"

View File

@@ -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

View File

@@ -0,0 +1,42 @@
#include "stdafx.h"
#include "doctest.h"
#include "editor/editorGroundFollow.hpp"
#include <cmath>
#include <limits>
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<segment_data> pieces{straight(0.0, 40.0), straight(40.0, 80.0), straight(80.0, 120.0)};
auto const unknown{std::numeric_limits<double>::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<segment_data> pieces{straight(0.0, 50.0), straight(50.0, 100.0)};
auto const unknown{std::numeric_limits<double>::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));
}