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

feat(editor): the whole-scenery grade fit keeps the tracks a station shares at one height, lets the switches lie on the vertical curves the regulation allows, runs straight through the double slips and leaves the bridges out of the faults

A switch may lie on a concave vertical curve, and on a convex one no sharper than 2000 m (Dz.U. 2026 poz. 1225 § 58 ust. 16): the fit bends over the switches and their shared timbers where the ground does, a curve on a switch is a warning, and only a sharper convex one an error. A sharp crest of a hump keeps its curve off the switch zones. The zone of a crossing reaches only as far as the path crossed has rails, so the middle of a double slip keeps to itself.

A line runs through a switch along its main path, and through the quarters of a double slip straight on, so the long lines go through the slips and the connections between them are fitted after. Rails of the lines fitted already nearer than a sleeper is long are taken at their height, as both lie on the same timbers. A short line between two lines whose end grades can't be joined within the norms keeps only the heights of its ends, and the grade breaks at the joints. The norms speed of a line is the one most of its length is laid for, so a few tracks set much faster don't stiffen the curves of all of it.

The fault finder leaves out the places over the terrain model on a bridge or a viaduct, the ground falling away under them by the abutments. A formation modifier may be open at its start or end.
This commit is contained in:
maj00r
2026-10-22 01:48:04 +02:00
parent 9fedbaf6a8
commit f361bc406b
11 changed files with 1020 additions and 186 deletions

View File

@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "application/editorprojection.h"
#include "editor/editorFormat.hpp"
#include "editor/editorGeometry.hpp"
#include "editor/editorProfile.hpp"
#include "scene/scene.h"
#include "scene/scenelayers.h"
@@ -45,6 +46,12 @@ double const kModelStep{5.0}; // m between the places of the tracks compared wit
std::size_t const kModelRun{200}; // places of a path whose model is asked for at once
double const kModelPoll{0.25}; // s between the looks whether the model is in
double const kUnfitted{30.0}; // m; a scenery whose tracks lie this far from the model as a whole isn't fitted to it
// a track over the model by more than the depth goes on a bridge or a viaduct the model leaves out where the model falls away by
// the abutments, steeper than the banks, within the reach along the track both ways; as the grade lines fitted to the model
// tell them. By the abutments the track is over the model by less
double const kBridgeDepth{1.0}; // m
double const kAbutment{100.0}; // per mille
double const kBridgeReach{200.0}; // m
using kind = joints_tool::joint_issue::kind;
@@ -198,8 +205,8 @@ bool joints_tool::joints_model()
for (auto i = Run.first; i < Run.second; ++i)
{
glm::dvec2 const at{state.places[i].position.x, state.places[i].position.z};
Min = glm::min(Min, at - 2.0);
Max = glm::max(Max, at + 2.0);
Min = glm::min(Min, at - kBridgeReach);
Max = glm::max(Max, at + kBridgeReach);
}
};
glm::dvec2 low, high;
@@ -235,6 +242,37 @@ bool joints_tool::joints_model()
if (std::abs(known[known.size() / 2]) > kUnfitted)
shift = known[known.size() / 2];
}
// a place on a bridge or a viaduct the model leaves out isn't off it: the route through its track sampled both ways, the
// stretches over the model as on a bridge found along it
std::map<TTrack const *, std::pair<std::vector<editor_track::route_sample>, std::vector<profile::departure>>> routes;
auto const on_bridge = [&](nmt_place const &Place) {
auto found{routes.find(Place.track)};
if (found == routes.end())
{
auto route{editor_track::run_route(*Place.track, kBridgeReach)};
auto samples{editor_track::sample_route(route, 1.0)};
std::vector<double> chainages, heights, ground;
for (auto const &sample : samples)
{
chainages.push_back(sample.chainage);
heights.push_back(sample.position.y - route.spans[sample.span].track->rail_height());
double height;
ground.push_back(m_ground.terrain_model().height(sample.position.x, sample.position.z, height) ? height + m_ground.terrain_model_offset() + shift : std::numeric_limits<double>::quiet_NaN());
}
auto spans{profile::bridged(chainages, heights, ground, kBridgeDepth, kAbutment)};
found = routes.emplace(Place.track, std::make_pair(std::move(samples), std::move(spans))).first;
}
auto const &[samples, spans]{found->second};
auto nearest{std::numeric_limits<double>::max()};
double at{0.0};
for (auto const &sample : samples)
if (auto const distance{geometry::plan_distance(sample.position, Place.position)}; distance < nearest)
{
nearest = distance;
at = sample.chainage;
}
return nearest <= 1.0 && std::any_of(spans.begin(), spans.end(), [&](profile::departure const &Span) { return at >= Span.from - kModelStep && at <= Span.to + kModelStep; });
};
// the place of each path the farthest from the model
std::map<std::pair<TTrack *, int>, std::size_t> worst;
for (std::size_t i = 0; i < state.places.size(); ++i)
@@ -242,7 +280,7 @@ bool joints_tool::joints_model()
if (false == std::isfinite(differences[i]))
continue;
differences[i] -= shift;
if (std::abs(differences[i]) <= state.model)
if (std::abs(differences[i]) <= state.model || (differences[i] > 0.0 && on_bridge(state.places[i])))
continue;
auto const key{std::make_pair(state.places[i].track, state.places[i].path)};
auto const found{worst.find(key)};