17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-01 03:29:03 +01:00

feat(editor): the work of the editor sessions not committed yet, as it stands: a curve traced on from the end of the diverging track of a switch goes on at its radius with no transition in, or from a straight right at the switch (alignment start_held, fit_going_on), the plan taking an end adjoining R 10 km or more for a straight; the switches and slips laid into curves, slid along them and laid alone on one straight (frame_path, switch slide); the route plan reading curves going on from the tracks adjoining, the kept designs taken or forgotten; the orthophoto and terrain model settings, downloads and layers, the tracks onto the terrain; the curvature of a path in the plan (bezier::plan_curvature); the Polish texts of all of it. Not built as committed

This commit is contained in:
maj00r
2026-10-29 22:19:06 +01:00
parent 2eda26b94c
commit 80379b991c
49 changed files with 4718 additions and 1114 deletions

View File

@@ -949,3 +949,198 @@ TEST_CASE("alignment: curves turning the same way with straights between them, t
CHECK(fit.rms < 0.02 + each.noise);
}
}
// the points along a line from the origin along x through the segments, every 10 m, the last one at its end
std::vector<glm::dvec2> points_to_end(std::vector<std::array<double, 3>> const &Segments, line_end &End) {
auto points{walked_points(Segments, 10.0, End)};
points.resize(points.size() - 2);
End.position -= heading_of(End.heading) * 60.0;
if (false == points.empty() && glm::distance(points.back(), End.position) < 2.0)
points.pop_back();
points.push_back(End.position);
return points;
}
// the stretch from the end of the diverging track of a switch of R 300 turning to the left, at the origin along x
alignment::design from_switch(line_end const &End, double const Speed) {
alignment::design base;
base.speed = Speed;
base.start = {0.0, 0.0, 0.0};
base.start_direction = heading(0.0);
base.start_radius = 300.0;
base.start_turn = 1;
base.start_curved = true;
base.end = {End.position.x, 0.0, End.position.y};
base.end_direction = heading(End.heading);
return base;
}
TEST_CASE("alignment: a curve traced on from the diverging track of a switch is a compound curve with it, ending at the last point") {
double const k{1.0 / 300.0};
double const m{1.0 / 150.0};
line_end end;
auto const points{points_to_end({{k, m, 20.0}, {m, m, 30.0}, {m, 0.0, 25.0}}, end)};
auto const base{from_switch(end, 60.0)};
auto const fit{alignment::fit_going_on(base, points)};
REQUIRE(fit.valid);
REQUIRE(fit.vertices.size() == 1);
CHECK(fit.vertices.front().radius == doctest::Approx(150.0).epsilon(0.03));
CHECK(fit.vertices.front().transition_in == doctest::Approx(20.0).epsilon(0.15));
CHECK(fit.vertices.front().transition_out == doctest::Approx(25.0).epsilon(0.15));
CHECK(fit.rms < 0.02);
// laid from the curvature of the switch, no jump at the joint; ending right at the last point, heading as the line does there
auto laid{base};
laid.vertices = fit.vertices;
laid.end_direction = fit.leaving;
auto const line{alignment::compute(laid)};
REQUIRE(line.valid);
CHECK(curvature_of(line, 0.25) == doctest::Approx(k).epsilon(0.05));
auto const last{alignment::evaluate(line, line.length)};
CHECK(glm::distance(glm::dvec2{last.position.x, last.position.z}, end.position) < 0.01);
CHECK(std::atan2(fit.leaving.y, fit.leaving.x) == doctest::Approx(end.heading).epsilon(0.01));
CHECK(curvature_of(line, line.length - 0.25) == doctest::Approx(0.0).epsilon(1e-3));
// two points only, the radius between them unknown: the transitions as long as the norms ask for, the curvature going on from the
// switch all the same
std::vector<glm::dvec2> const two{points[points.size() / 2], points.back()};
auto const few{alignment::fit_going_on(base, two)};
REQUIRE(few.valid);
auto shortlaid{base};
shortlaid.vertices = few.vertices;
shortlaid.end_direction = few.leaving;
auto const shortline{alignment::compute(shortlaid)};
REQUIRE(shortline.valid);
CHECK(curvature_of(shortline, 0.25) == doctest::Approx(k).epsilon(0.05));
CHECK(few.worst < 0.05);
CHECK(few.vertices.front().transition_in > 5.0);
}
TEST_CASE("alignment: a curve traced on from a switch turning hard at its end takes two arcs, a flatter one first") {
double const k{1.0 / 300.0};
double const m{1.0 / 400.0};
double const n{1.0 / 40.0};
line_end end;
auto const points{points_to_end({{k, m, 15.0}, {m, m, 40.0}, {m, n, 20.0}, {n, n, 30.0}, {n, 0.0, 20.0}}, end)};
auto const base{from_switch(end, 40.0)};
auto const fit{alignment::fit_going_on(base, points)};
REQUIRE(fit.valid);
REQUIRE(fit.vertices.size() == 1);
REQUIRE(fit.vertices.front().compound);
REQUIRE(fit.vertices.front().arcs.size() == 1);
CHECK(fit.vertices.front().radius > 250.0);
CHECK(fit.vertices.front().arcs.front().radius == doctest::Approx(40.0).epsilon(0.1));
CHECK(fit.rms < 0.1);
auto laid{base};
laid.vertices = fit.vertices;
laid.end_direction = fit.leaving;
auto const line{alignment::compute(laid)};
REQUIRE(line.valid);
CHECK(curvature_of(line, 0.25) == doctest::Approx(k).epsilon(0.05));
auto const last{alignment::evaluate(line, line.length)};
CHECK(glm::distance(glm::dvec2{last.position.x, last.position.z}, end.position) < 0.01);
}
TEST_CASE("alignment: a curve traced on from a switch with points clicked on the straight after it ends where the straight begins") {
double const k{1.0 / 300.0};
double const m{1.0 / 200.0};
line_end end;
auto const along{walked_points({{k, m, 20.0}, {m, m, 40.0}, {m, 0.0, 30.0}}, 10.0, end)};
auto const base{from_switch(end, 60.0)};
auto const fit{alignment::fit_going_on(base, along)};
REQUIRE(fit.valid);
CHECK(fit.vertices.front().radius == doctest::Approx(200.0).epsilon(0.03));
CHECK(fit.rms < 0.02);
CHECK(std::atan2(fit.leaving.y, fit.leaving.x) == doctest::Approx(end.heading).epsilon(0.01));
}
TEST_CASE("alignment: no curve goes on from a switch to a point on the other side of its heading") {
line_end end;
end.position = {60.0, -3.0};
end.heading = -0.1;
auto const base{from_switch(end, 60.0)};
CHECK_FALSE(alignment::fit_going_on(base, {{30.0, -1.0}, {60.0, -3.0}}).valid);
}
// held: the curve going on from the diverging track of a switch keeps its radius, with no transition between them
alignment::design held_from_switch(line_end const &End, double const Speed) {
auto base{from_switch(End, Speed)};
base.start_held = true;
return base;
}
TEST_CASE("alignment: a curve going on from a switch at its radius begins right there by the transition out of it") {
double const k{1.0 / 300.0};
// R 300 on for 40 m, then a transition of 30 m out to the straight: the radius whatever the vertex was given, none in, the one out found
auto design{curved_from(300.0, {{k, k, 40.0}, {k, 0.0, 30.0}}, 40.0)};
design.start_held = true;
auto &vertex{design.vertices.front()};
vertex.radius = 1000.0;
vertex.transition_in = 20.0;
auto const line{alignment::compute(design)};
REQUIRE(line.valid);
REQUIRE(line.curves.size() == 1);
auto const &curve{line.curves.front()};
CHECK(curve.radius == doctest::Approx(300.0).epsilon(1e-9));
CHECK(curve.transition_in == doctest::Approx(0.0));
CHECK(curve.transition_out == doctest::Approx(30.0).epsilon(0.05));
CHECK(curvature_of(line, 0.25) == doctest::Approx(k).epsilon(0.01));
auto const start{alignment::evaluate(line, 0.0)};
CHECK(std::abs(start.position.x) < 1e-6);
CHECK(std::abs(start.position.z) < 1e-6);
auto const end{alignment::evaluate(line, line.length)};
CHECK(glm::distance(glm::dvec2{end.position.x, end.position.z}, glm::dvec2{design.end.x, design.end.z}) < 1e-3);
// a vertex nearer than the arc of the switch reaches with no transition: no such curve
auto nearer{curved_from(300.0, {{k, k, 40.0}, {k, 0.0, 30.0}}, 40.0)};
nearer.start_held = true;
nearer.end = {nearer.end.x, 0.0, nearer.end.z + 5.0};
CHECK_FALSE(alignment::compute(nearer).valid);
}
TEST_CASE("alignment: a curve traced on from a switch goes on at its radius, not through a transition into another") {
double const k{1.0 / 300.0};
line_end end;
auto const points{points_to_end({{k, k, 60.0}, {k, 0.0, 25.0}}, end)};
auto const base{held_from_switch(end, 100.0)};
auto const fit{alignment::fit_going_on(base, points)};
REQUIRE(fit.valid);
REQUIRE(fit.vertices.size() == 1);
CHECK_FALSE(fit.vertices.front().compound);
CHECK(fit.vertices.front().radius == doctest::Approx(300.0).epsilon(1e-9));
CHECK(fit.vertices.front().transition_in == doctest::Approx(0.0));
CHECK(fit.rms < 0.05);
auto laid{base};
laid.vertices = fit.vertices;
laid.end_direction = fit.leaving;
auto const line{alignment::compute(laid)};
REQUIRE(line.valid);
CHECK(line.curves.front().radius == doctest::Approx(300.0).epsilon(1e-6));
CHECK(curvature_of(line, 0.25) == doctest::Approx(k).epsilon(0.01));
auto const last{alignment::evaluate(line, line.length)};
CHECK(glm::distance(glm::dvec2{last.position.x, last.position.z}, end.position) < 0.01);
// the points along its arc alone, as they're clicked: the arc of the switch as far as abreast of the last of them, no transition out
line_end on;
auto const arc{points_to_end({{k, k, 50.0}}, on)};
auto const alone{alignment::fit_going_on(held_from_switch(on, 100.0), arc)};
REQUIRE(alone.valid);
REQUIRE(alone.vertices.size() == 1);
CHECK(alone.vertices.front().radius == doctest::Approx(300.0).epsilon(1e-9));
CHECK(alone.vertices.front().transition_out == doctest::Approx(0.0));
CHECK(alone.rms < 0.01);
CHECK(glm::distance(alone.ending, on.position) < 0.01);
// the points along a flatter curve after it: the arc of the switch first, then the flatter one
double const m{1.0 / 600.0};
line_end flatter;
auto const along{points_to_end({{k, m, 30.0}, {m, m, 60.0}, {m, 0.0, 30.0}}, flatter)};
auto const two{alignment::fit_going_on(held_from_switch(flatter, 60.0), along)};
REQUIRE(two.valid);
REQUIRE(two.vertices.size() == 1);
REQUIRE(two.vertices.front().compound);
REQUIRE(two.vertices.front().arcs.size() == 1);
CHECK(two.vertices.front().radius == doctest::Approx(300.0).epsilon(1e-9));
CHECK(two.vertices.front().transition_in == doctest::Approx(0.0));
CHECK(two.vertices.front().arcs.front().radius == doctest::Approx(600.0).epsilon(0.1));
CHECK(two.rms < 0.1);
}