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

feat(editor): a switch laid into a curve is checked by ST-T1-A6 as it's placed: the radii of its main and diverging tracks at its start and its end shown at it; warnings where the curvature of a track turns from one side to the other within it (KZW II, 9.7 pkt 12), where the diverging track is sharper or the main track bent more than table 11.9 allows the basic switch (the values allowed by way of exception named), where a switch of 1:9.403 or steeper is bent (11.4 pkt 4), where the cant changes within it (11.4 pkt 7), where a cant ramp starts or ends within it or under 6 m off it (9.6 pkt 16-17) and where the cant is over 100 mm (table 9.6); a note on a transition curve, which only an exception allows. The ends of the cant ramps are marked on the curve, and the start of the switch pressed within 3 m of where it starts or ends at an end of a ramp, or keeps the 6 m off it, is drawn there. The warnings stay in the status once it's laid. The checks stand on their own in editor/editorSwitchCurve, with unit tests

This commit is contained in:
maj00r
2026-10-25 00:29:05 +02:00
parent aeef2cebb3
commit ece61056ff
9 changed files with 633 additions and 12 deletions

View File

@@ -20,6 +20,8 @@ add_executable(${UNIT_TESTS_NAME}
# and the heights of the tracks laid
"${CMAKE_SOURCE_DIR}/editor/editorGroundFollow.cpp"
"${CMAKE_SOURCE_DIR}/editor/editorProfile.cpp"
# and the switches laid into the curves
"${CMAKE_SOURCE_DIR}/editor/editorSwitchCurve.cpp"
${UNIT_TEST_CASES})
# the core library brings the game's build settings along

View File

@@ -0,0 +1,102 @@
#include "stdafx.h"
#include "doctest.h"
#include "editor/editorSwitchCurve.hpp"
#include <algorithm>
#include <cmath>
#include <string>
namespace {
// a line every half metre: a straight, a transition curve from it to the arc of the radius, with a straight cant ramp along it, and
// the arc, each of the lengths given
std::vector<switch_curve::track_point> line(double const Straight, double const Transition, double const Arc, double const Radius, double const Cant) {
std::vector<switch_curve::track_point> points;
double heading{0.0};
auto const curvature = [&](double const S) { return S <= Straight ? 0.0 : S <= Straight + Transition ? (S - Straight) / Transition / Radius : 1.0 / Radius; };
auto const cant = [&](double const S) { return S <= Straight ? 0.0 : S <= Straight + Transition ? Cant * (S - Straight) / Transition : Cant; };
for (double s{0.0}; s <= Straight + Transition + Arc + 1e-9; s += 0.5) {
if (s > 0.0)
heading += 0.5 * (curvature(s - 0.5) + curvature(s)) * 0.5;
points.push_back({s, heading, cant(s)});
}
return points;
}
// the tracks of a switch Length long laid into the line from the station: the main one along it, the diverging one turning off it
// to the side by the curvature of the basic switch
std::pair<std::vector<switch_curve::track_point>, std::vector<switch_curve::track_point>> laid(std::vector<switch_curve::track_point> const &Line, double const From, double const Length, double const Radius, int const Side) {
std::vector<switch_curve::track_point> main;
std::vector<switch_curve::track_point> branch;
auto const first{std::lower_bound(Line.begin(), Line.end(), From, [](auto const &Point, double const Value) { return Point.station < Value; })};
for (auto point{first}; point != Line.end() && point->station <= From + Length + 1e-9; ++point) {
auto const s{point->station - From};
main.push_back({s, point->heading - first->heading, 0.0});
branch.push_back({s, point->heading - first->heading + Side * s / Radius, 0.0});
}
return {main, branch};
}
bool says(std::vector<std::string> const &Lines, char const *Text) {
return std::any_of(Lines.begin(), Lines.end(), [&](std::string const &Line) { return Line.find(Text) != std::string::npos; });
}
} // namespace
TEST_CASE("switch on a curve: the curvatures of its tracks on a transition curve, read the way the line turns") {
auto const track{line(100.0, 120.0, 200.0, 1000.0, 60.0)};
auto const [main, branch] {laid(track, 150.0, 30.0, 500.0, -1)};
auto const report{switch_curve::check(main, branch, track, 150.0, 180.0, 500.0, 12.0)};
CHECK(report.curved);
CHECK(report.transition);
CHECK(report.main_start == doctest::Approx(51.0 / 120.0 / 1000.0).epsilon(0.02));
CHECK(report.main_end == doctest::Approx(79.0 / 120.0 / 1000.0).epsilon(0.02));
// turning off to the outside of the curve: against it all along, the case KZW I
CHECK(report.branch_start < 0.0);
CHECK(report.branch_end < 0.0);
CHECK(false == says(report.warnings, "KZW II"));
CHECK(says(report.notes, "transition curve"));
// laid on the ramp, the cant changing under it
CHECK(report.cant_start == doctest::Approx(25.0).epsilon(0.02));
CHECK(report.cant_end == doctest::Approx(40.0).epsilon(0.02));
CHECK(says(report.warnings, "The cant changes within the switch"));
}
TEST_CASE("switch on a curve: the diverging track turning from one side to the other is the case KZW II") {
// a transition growing past the curvature of the basic switch along the switch
auto const track{line(100.0, 60.0, 100.0, 300.0, 0.0)};
auto const [main, branch] {laid(track, 125.0, 30.0, 500.0, -1)};
auto const report{switch_curve::check(main, branch, track, 125.0, 155.0, 500.0, 12.0)};
CHECK(report.branch_start < 0.0);
CHECK(report.branch_end > 0.0);
CHECK(says(report.warnings, "KZW II"));
}
TEST_CASE("switch on a curve: the ends of a cant ramp at the ends of the switch or 6 m off it") {
auto const track{line(100.0, 120.0, 200.0, 1000.0, 60.0)};
auto const ramps{switch_curve::ramp_ends(track)};
REQUIRE(ramps.size() == 2);
CHECK(ramps[0] == doctest::Approx(100.0).epsilon(0.01));
CHECK(ramps[1] == doctest::Approx(220.0).epsilon(0.01));
auto const at = [&](double const From) {
auto const [main, branch] {laid(track, From, 30.0, 500.0, 1)};
return switch_curve::check(main, branch, track, From, From + 30.0, 500.0, 12.0);
};
CHECK(says(at(210.0).warnings, "within the switch"));
CHECK(says(at(222.0).warnings, "6 m at least"));
CHECK(false == says(at(220.0).warnings, "within the switch"));
CHECK(says(at(220.0).notes, "at an end of the switch"));
CHECK(false == says(at(230.0).warnings, "cant ramp"));
// the start pressed near those places drawn to them
std::string what;
CHECK(switch_curve::snapped_start(ramps, 218.5, 30.0, 1, 3.0, &what) == doctest::Approx(220.0));
CHECK(what.find("starts at an end") != std::string::npos);
CHECK(switch_curve::snapped_start(ramps, 228.0, 30.0, 1, 3.0, &what) == doctest::Approx(226.0));
CHECK(what.find("6 m off") != std::string::npos);
CHECK(switch_curve::snapped_start(ramps, 72.0, 30.0, 1, 3.0, &what) == doctest::Approx(70.0));
CHECK(what.find("ends at an end") != std::string::npos);
CHECK(switch_curve::snapped_start(ramps, 160.0, 30.0, 1, 3.0, &what) == doctest::Approx(160.0));
CHECK(what.empty());
}