mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 02:57:28 +01:00
fix(editor): the plan warns of the curved track adjoining a curve only where the curvature jumps there: a curve going on from the diverging track of a switch at its radius (R 300 after R 301 in wsd) no longer has it. The side the adjoining track turns to is taken with its radius into the chain and the design, and the curvature the design meets it with, signed by its turn, compared with it, within 5%; a design kept without the side is taken for turning its way. Unit test: R 300 from the very start after R 301 turning the same way gives no warning, turning the other way or starting with a straight does
This commit is contained in:
@@ -79,6 +79,8 @@ void editor_mode::route_bind_ends()
|
||||
design.end_grade = grade_of(chain.end_direction);
|
||||
design.start_radius = chain.start_radius;
|
||||
design.end_radius = chain.end_radius;
|
||||
design.start_turn = chain.start_turn;
|
||||
design.end_turn = chain.end_turn;
|
||||
design.start_reserve = editor_track::run_reserve(editor_track::straight_beyond(chain, false, m_straights.tolerance));
|
||||
design.end_reserve = editor_track::run_reserve(editor_track::straight_beyond(chain, true, m_straights.tolerance));
|
||||
}
|
||||
@@ -450,6 +452,8 @@ bool editor_mode::digitize_chain(editor_track::chain const &Chain, std::string *
|
||||
design.end_grade = grade_of(Chain.end_direction);
|
||||
design.start_radius = Chain.start_radius;
|
||||
design.end_radius = Chain.end_radius;
|
||||
design.start_turn = Chain.start_turn;
|
||||
design.end_turn = Chain.end_turn;
|
||||
auto const preferred{m_route.design.shape};
|
||||
auto const other{preferred == alignment::transition_shape::clothoid ? alignment::transition_shape::cubic_parabola : alignment::transition_shape::clothoid};
|
||||
alignment::result result;
|
||||
|
||||
@@ -1088,9 +1088,37 @@ result fit_between(design const &Design)
|
||||
auto const gradeafter{(r.profile[i + 1].elevation - point.elevation) / (r.profile[i + 1].chainage - point.chainage)};
|
||||
point.tangent = point.radius * std::abs(gradeafter - gradebefore) / 2.0;
|
||||
}
|
||||
if (Design.start_radius > 0.0 && Design.start_radius < 10000.0)
|
||||
// a curved track adjoining is a jump of the curvature only where the design meets it at another one: a curve going on from
|
||||
// the diverging track of a switch at its radius isn't. The curvature of the design there is signed by the side it turns to, a
|
||||
// piece shorter than 1 cm, as a straight the fit leaves before the curve, passed over
|
||||
auto const curvature_at = [&](bool const End) {
|
||||
for (std::size_t n = 0; n < r.elements.size(); ++n)
|
||||
{
|
||||
auto const &e{r.elements[End ? r.elements.size() - 1 - n : n]};
|
||||
if (e.length < 0.01)
|
||||
continue;
|
||||
auto const arc{e.radius > 0.0 ? 1.0 / e.radius : 0.0};
|
||||
switch (e.kind)
|
||||
{
|
||||
case element_kind::arc: return arc * e.turn;
|
||||
case element_kind::transition_in: return End ? arc * e.turn : 0.0;
|
||||
case element_kind::transition_out: return End ? 0.0 : arc * e.turn;
|
||||
case element_kind::spiral: return (End ? e.curvature_end : e.curvature_start) * e.turn;
|
||||
default: return 0.0;
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
};
|
||||
auto const abrupt = [](double const Radius, int const Turn, double const Own) {
|
||||
if (Radius <= 0.0 || Radius >= 10000.0)
|
||||
return false;
|
||||
// the side not known, as of a design kept in the scenery before it was: taken for the one the design turns to
|
||||
auto const theirs{(Turn != 0 ? Turn : Own < 0.0 ? -1 : 1) / Radius};
|
||||
return std::abs(theirs - Own) > 0.05 * std::max(1.0 / Radius, std::abs(Own));
|
||||
};
|
||||
if (abrupt(Design.start_radius, Design.start_turn, curvature_at(false)))
|
||||
r.warnings.emplace_back(format(STR_C("The adjoining track at the start is curved (R %.0f m), the curvature changes abruptly"), Design.start_radius));
|
||||
if (Design.end_radius > 0.0 && Design.end_radius < 10000.0)
|
||||
if (abrupt(Design.end_radius, Design.end_turn, curvature_at(true)))
|
||||
r.warnings.emplace_back(format(STR_C("The adjoining track at the end is curved (R %.0f m), the curvature changes abruptly"), Design.end_radius));
|
||||
make_cants(Design, r);
|
||||
|
||||
|
||||
@@ -94,6 +94,10 @@ struct design
|
||||
double end_grade{0.0};
|
||||
double start_radius{0.0};
|
||||
double end_radius{0.0};
|
||||
// the side the adjoining track turns to at the start and at the end, going from the one to the other: 1 left, -1 right, 0 not
|
||||
// known; a design going on at the curvature of the adjoining track doesn't change it abruptly
|
||||
int start_turn{0};
|
||||
int end_turn{0};
|
||||
// length of the straight beyond the start and the end, which the curves can take over
|
||||
double start_reserve{0.0};
|
||||
double end_reserve{0.0};
|
||||
|
||||
@@ -97,7 +97,7 @@ double path_radius(segment_data const &Path, double const T)
|
||||
return curvature > 1e-7 ? 1.0 / curvature : 0.0;
|
||||
}
|
||||
|
||||
bool adjoining_direction(TTrack const *Neighbour, glm::dvec3 const &Joint, bool const Leaving, glm::dvec3 &Direction, double &Radius)
|
||||
bool adjoining_direction(TTrack const *Neighbour, glm::dvec3 const &Joint, bool const Leaving, glm::dvec3 &Direction, double &Radius, int &Turn)
|
||||
{
|
||||
if (Neighbour == nullptr)
|
||||
return false;
|
||||
@@ -109,8 +109,18 @@ bool adjoining_direction(TTrack const *Neighbour, glm::dvec3 const &Joint, bool
|
||||
if (glm::distance(point, Joint) > kSamePoint)
|
||||
continue;
|
||||
auto const tangent{glm::normalize(path_tangent(path, atend))};
|
||||
Direction = (Leaving != atend) ? tangent : -tangent;
|
||||
auto const along{Leaving != atend};
|
||||
Direction = along ? tangent : -tangent;
|
||||
Radius = path_radius(path, atend ? 1.0 : 0.0);
|
||||
// the side it turns to as the chain runs, the path gone against its points turning the other way
|
||||
Turn = 0;
|
||||
if (Radius > 0.0)
|
||||
{
|
||||
bezier const curve{path};
|
||||
auto const first{curve.first(atend ? 1.0 : 0.0)};
|
||||
auto const second{curve.second(atend ? 1.0 : 0.0)};
|
||||
Turn = (first.x * second.z - first.z * second.x > 0.0) == along ? 1 : -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1335,14 +1345,14 @@ bool editor_track::complete_chain(chain &Chain, std::string &Error)
|
||||
auto const firstforward{Chain.forward.front()};
|
||||
Chain.start = first.points[firstforward ? segment_data::point::start : segment_data::point::end];
|
||||
Chain.start_direction = firstforward ? path_tangent(first, false) : -path_tangent(first, true);
|
||||
adjoining_direction(firstforward ? from->trPrev : from->trNext, Chain.start, false, Chain.start_direction, Chain.start_radius);
|
||||
adjoining_direction(firstforward ? from->trPrev : from->trNext, Chain.start, false, Chain.start_direction, Chain.start_radius, Chain.start_turn);
|
||||
Chain.start_direction = glm::normalize(Chain.start_direction);
|
||||
|
||||
auto const &last{to->m_paths.front()};
|
||||
auto const lastforward{Chain.forward.back()};
|
||||
Chain.end = last.points[lastforward ? segment_data::point::end : segment_data::point::start];
|
||||
Chain.end_direction = lastforward ? path_tangent(last, true) : -path_tangent(last, false);
|
||||
adjoining_direction(lastforward ? to->trNext : to->trPrev, Chain.end, true, Chain.end_direction, Chain.end_radius);
|
||||
adjoining_direction(lastforward ? to->trNext : to->trPrev, Chain.end, true, Chain.end_direction, Chain.end_radius, Chain.end_turn);
|
||||
Chain.end_direction = glm::normalize(Chain.end_direction);
|
||||
|
||||
Error.clear();
|
||||
|
||||
@@ -272,6 +272,9 @@ class editor_track
|
||||
glm::dvec3 end_direction{0.0};
|
||||
double start_radius{0.0};
|
||||
double end_radius{0.0};
|
||||
// the side the adjoining track turns to there, going from the start to the end: 1 left, -1 right, 0 straight
|
||||
int start_turn{0};
|
||||
int end_turn{0};
|
||||
double length{0.0};
|
||||
double velocity{-1.0};
|
||||
double radius{0.0};
|
||||
|
||||
@@ -129,6 +129,36 @@ TEST_CASE("alignment: a sharp bend between short straights is laid where clicked
|
||||
CHECK(line.vertices.front().x == doctest::Approx(120.0));
|
||||
}
|
||||
|
||||
TEST_CASE("alignment: a curve going on at the radius of the curved track before it doesn't change the curvature abruptly") {
|
||||
auto const adjoining = [](alignment::result const &Line) {
|
||||
return std::any_of(Line.warnings.begin(), Line.warnings.end(), [](std::string const &Warning) { return Warning.find("adjoining track at the start") != std::string::npos; });
|
||||
};
|
||||
// R 300 with no transition from the very start, as a curve after the diverging track of a switch, R 301 there
|
||||
auto const tangent{300.0 * std::tan(10.0 * pi / 180.0)};
|
||||
auto design{straights({tangent, 200.0}, {20.0 * pi / 180.0}, 40.0)};
|
||||
auto &vertex{design.vertices.front()};
|
||||
vertex.radius = 300.0;
|
||||
vertex.transition_in = 0.0;
|
||||
vertex.transition_out = 0.0;
|
||||
design.start_radius = 301.0;
|
||||
design.start_turn = 1;
|
||||
auto const line{alignment::compute(design)};
|
||||
REQUIRE(line.valid);
|
||||
REQUIRE_FALSE(line.elements.empty());
|
||||
CHECK(line.elements.front().kind == alignment::element_kind::arc);
|
||||
CHECK_FALSE(adjoining(line));
|
||||
// the track before turning the other way, or the curve starting with a straight: the curvature jumps
|
||||
design.start_turn = -1;
|
||||
CHECK(adjoining(alignment::compute(design)));
|
||||
design.start_turn = 1;
|
||||
auto later{straights({tangent + 80.0, 200.0}, {20.0 * pi / 180.0}, 40.0)};
|
||||
later.vertices.front() = vertex;
|
||||
later.vertices.front().position = {tangent + 80.0, 0.0};
|
||||
later.start_radius = 301.0;
|
||||
later.start_turn = 1;
|
||||
CHECK(adjoining(alignment::compute(later)));
|
||||
}
|
||||
|
||||
TEST_CASE("alignment: two bends share the straight between them") {
|
||||
auto design{straights({600.0, 250.0, 600.0}, {4.0 * pi / 180.0, -5.0 * pi / 180.0}, 120.0)};
|
||||
std::vector<char> corners{1, 1};
|
||||
|
||||
Reference in New Issue
Block a user