mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 22:47:28 +01:00
Vendor the maj0sted track layout library and link it into the editor
Drop-in copy of C:\Users\maj00r\Projects\maj0sted-master minus its web/ directory - the WASM frontend is not being ported, the editor drives the same C++ API natively. What is left is plain C++20 with no dependencies: domain model (niweleta, plan and profile geometry, fitting, parallelism), project serialization, rail sampling and the editor document. src/web/ribbon.cpp was missing from the library source list; added, since without it the ribbon symbols never make it into the archive.
This commit is contained in:
132
maj0sted/tests/test_plan_alignment.cpp
Normal file
132
maj0sted/tests/test_plan_alignment.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "check.hpp"
|
||||
#include "maj0sted/maj0sted.hpp"
|
||||
|
||||
using namespace maj0sted::domain;
|
||||
|
||||
namespace {
|
||||
|
||||
void straight_computes_azimuth_and_length() {
|
||||
// Going east (+x): azimuth = 90 deg (clockwise from north).
|
||||
const Straight east{CartesianPosition{0.0, 0.0}, CartesianPosition{100.0, 0.0}};
|
||||
CHECK(std::abs(east.length().metres() - 100.0) < 1e-9);
|
||||
CHECK(std::abs(east.azimuth().degrees() - 90.0) < 1e-9);
|
||||
|
||||
// Going north (+y): azimuth = 0 deg.
|
||||
const Straight north{CartesianPosition{0.0, 0.0}, CartesianPosition{0.0, 50.0}};
|
||||
CHECK(std::abs(north.azimuth().degrees() - 0.0) < 1e-9);
|
||||
CHECK(std::abs(north.length().metres() - 50.0) < 1e-9);
|
||||
|
||||
// A zero-length straight has no azimuth and is rejected.
|
||||
CHECK_THROWS(Straight(CartesianPosition{1.0, 1.0}, CartesianPosition{1.0, 1.0}));
|
||||
}
|
||||
|
||||
void arc_carries_radius_direction_and_optional_length() {
|
||||
const CircularArc without_length{Radius::from_metres(300.0), TurnDirection::Left};
|
||||
CHECK(!without_length.length().has_value());
|
||||
|
||||
const CircularArc with_length{Radius::from_metres(300.0), TurnDirection::Left,
|
||||
Length::from_metres(45.0)};
|
||||
CHECK(with_length.length().has_value());
|
||||
CHECK(with_length.length().value().metres() == 45.0);
|
||||
}
|
||||
|
||||
void adjacent_same_arcs_are_rejected() {
|
||||
HorizontalAlignment same;
|
||||
same.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Left});
|
||||
// same radius + same direction -> forbidden
|
||||
CHECK_THROWS(
|
||||
same.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Left}));
|
||||
|
||||
HorizontalAlignment opposite;
|
||||
opposite.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Left});
|
||||
// same radius, different direction -> allowed (S-curve)
|
||||
opposite.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Right});
|
||||
CHECK(opposite.size() == 2);
|
||||
|
||||
HorizontalAlignment compound;
|
||||
compound.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Left});
|
||||
// same direction, different radius -> allowed (compound curve)
|
||||
compound.append(CircularArc{Radius::from_metres(500.0), TurnDirection::Left});
|
||||
CHECK(compound.size() == 2);
|
||||
}
|
||||
|
||||
void straight_to_straight_tangent_requires_equal_azimuth() {
|
||||
// Collinear straights, same azimuth, touching -> tangent OK.
|
||||
HorizontalAlignment collinear;
|
||||
collinear.append(
|
||||
Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
collinear.append(
|
||||
Straight{CartesianPosition{50.0, 0.0}, CartesianPosition{100.0, 0.0}});
|
||||
CHECK(collinear.size() == 2);
|
||||
CHECK(collinear.joint(0) == JointContinuity::Tangent);
|
||||
|
||||
// Touching but different azimuth with a Tangent joint -> must be a break.
|
||||
HorizontalAlignment unmarked;
|
||||
unmarked.append(
|
||||
Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
CHECK_THROWS(unmarked.append(
|
||||
Straight{CartesianPosition{50.0, 0.0}, CartesianPosition{50.0, 50.0}}));
|
||||
|
||||
// Non-touching tangent straights -> invalid.
|
||||
HorizontalAlignment gap;
|
||||
gap.append(Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
CHECK_THROWS(gap.append(
|
||||
Straight{CartesianPosition{60.0, 0.0}, CartesianPosition{100.0, 0.0}}));
|
||||
}
|
||||
|
||||
void azimuth_break_between_straights_must_be_marked() {
|
||||
// Corner marked as AzimuthBreak -> OK.
|
||||
HorizontalAlignment kink;
|
||||
kink.append(Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
kink.append(Straight{CartesianPosition{50.0, 0.0}, CartesianPosition{50.0, 50.0}},
|
||||
JointContinuity::AzimuthBreak);
|
||||
CHECK(kink.size() == 2);
|
||||
CHECK(kink.joint(0) == JointContinuity::AzimuthBreak);
|
||||
|
||||
// AzimuthBreak with equal azimuth is pointless -> invalid.
|
||||
HorizontalAlignment straight_break;
|
||||
straight_break.append(
|
||||
Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
CHECK_THROWS(straight_break.append(
|
||||
Straight{CartesianPosition{50.0, 0.0}, CartesianPosition{100.0, 0.0}},
|
||||
JointContinuity::AzimuthBreak));
|
||||
|
||||
// AzimuthBreak is only allowed between two straights.
|
||||
HorizontalAlignment arc_break;
|
||||
arc_break.append(
|
||||
Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
CHECK_THROWS(arc_break.append(
|
||||
CircularArc{Radius::from_metres(300.0), TurnDirection::Left},
|
||||
JointContinuity::AzimuthBreak));
|
||||
}
|
||||
|
||||
void straight_curve_joints_are_accepted_pending_fit() {
|
||||
// prosta -> klotoida -> łuk -> klotoida -> prosta
|
||||
HorizontalAlignment plan;
|
||||
plan.append(Straight{CartesianPosition{0.0, 0.0}, CartesianPosition{50.0, 0.0}});
|
||||
plan.append(TransitionCurve{Length::from_metres(30.0), std::nullopt,
|
||||
Radius::from_metres(300.0), TurnDirection::Left});
|
||||
plan.append(CircularArc{Radius::from_metres(300.0), TurnDirection::Left,
|
||||
Length::from_metres(40.0)});
|
||||
plan.append(TransitionCurve{Length::from_metres(30.0),
|
||||
Radius::from_metres(300.0), std::nullopt,
|
||||
TurnDirection::Left});
|
||||
plan.append(Straight{CartesianPosition{200.0, 0.0}, CartesianPosition{260.0, 0.0}});
|
||||
CHECK(plan.size() == 5);
|
||||
// Known lengths: 50 + 30 + 40 + 30 + 60.
|
||||
CHECK(plan.total_length().metres() == 210.0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
RUN(straight_computes_azimuth_and_length);
|
||||
RUN(arc_carries_radius_direction_and_optional_length);
|
||||
RUN(adjacent_same_arcs_are_rejected);
|
||||
RUN(straight_to_straight_tangent_requires_equal_azimuth);
|
||||
RUN(azimuth_break_between_straights_must_be_marked);
|
||||
RUN(straight_curve_joints_are_accepted_pending_fit);
|
||||
return REPORT();
|
||||
}
|
||||
Reference in New Issue
Block a user