mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-31 22:49:05 +01:00
feat(editor): a warning of the sudden change of the cant deficiency right behind a switch, as ST-T1-A6 sees it (9.11): a track laid on from the end of the diverging track of a switch, or into it, is checked by switch_curve::check_exit from the end of the curve of the switch, a straight frog's length before its end, to the first sudden change of the curvature of the track laid. Two of them nearer than the intermediate element of table 9.16 (6 m in track connections up to 60 km/h) are taken together, else each one alone, against table 9.15 (130 mm up to 60 km/h), at the speed of the laying or of the diverging track of the switch, the lower one. The view tells of it by the cursor while the track is extended or laid, the status once it's laid; a transition out of the frog straight makes no sudden change. Selftest: from a Rz S42-190-1:7,5 with a frog straight of 1.66 m a curve the other way of R 200 m warned of 194 mm together, the same way none; from a Rz 60E1-190-1:9 with 6.09 m a curve the other way of R 200 m none, of R 120 m warned of 157 mm
This commit is contained in:
@@ -1792,6 +1792,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
// the tracks the laying under way goes on from and to
|
// the tracks the laying under way goes on from and to
|
||||||
std::pair<TTrack const *, TTrack const *> laying_ends() const;
|
std::pair<TTrack const *, TTrack const *> laying_ends() const;
|
||||||
std::string design_speed_of(TTrack const *From, TTrack const *To) const;
|
std::string design_speed_of(TTrack const *From, TTrack const *To) const;
|
||||||
|
// what ST-T1-A6 says of the sudden changes of the cant deficiency right behind a switch the pieces laid come out of at Start (From),
|
||||||
|
// or go into at End (To): of the end of its curve and the first sudden change of the pieces (9.11, tables 9.15, 9.16)
|
||||||
|
std::vector<std::string> switch_exit_warnings(TTrack const *From, glm::dvec3 const &Start, TTrack const *To, glm::dvec3 const &End, std::vector<segment_data> const &Pieces) const;
|
||||||
void give_own_speed(std::vector<TTrack *> const &Created) const;
|
void give_own_speed(std::vector<TTrack *> const &Created) const;
|
||||||
std::vector<segment_data> join_pieces(TTrack const *From, editor_track::point_ref const &Frompoint, glm::dvec3 const &Start, glm::dvec2 const &Direction, editor_track::snap_target const &End, double &Length,
|
std::vector<segment_data> join_pieces(TTrack const *From, editor_track::point_ref const &Frompoint, glm::dvec3 const &Start, glm::dvec2 const &Direction, editor_track::snap_target const &End, double &Length,
|
||||||
std::string &Error) const;
|
std::string &Error) const;
|
||||||
|
|||||||
@@ -612,6 +612,61 @@ std::string editor_mode::design_speed_of(TTrack const *From, TTrack const *To) c
|
|||||||
return format(STR_C("design speed %.0f km/h, set for the laying"), speed);
|
return format(STR_C("design speed %.0f km/h, set for the laying"), speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> editor_mode::switch_exit_warnings(TTrack const *From, glm::dvec3 const &Start, TTrack const *To, glm::dvec3 const &End, std::vector<segment_data> const &Pieces) const
|
||||||
|
{
|
||||||
|
auto const *switched{From != nullptr && From->eType == tt_Switch ? From : To != nullptr && To->eType == tt_Switch ? To : nullptr};
|
||||||
|
if (switched == nullptr || Pieces.empty())
|
||||||
|
return {};
|
||||||
|
auto const &joint{switched == From ? Start : End};
|
||||||
|
// 1/m, positive to the left, as the piece runs
|
||||||
|
auto const curvature_at = [](segment_data const &Piece, double const T) {
|
||||||
|
bezier const curve{Piece};
|
||||||
|
auto const first{curve.first(T)};
|
||||||
|
auto const second{curve.second(T)};
|
||||||
|
auto const speed{std::hypot(first.x, first.z)};
|
||||||
|
return speed < 1e-9 ? 0.0 : (first.x * second.z - first.z * second.x) / (speed * speed * speed);
|
||||||
|
};
|
||||||
|
// the path of the switch ending at the joint, its pieces from the joint back into the switch, each with its curvature at its ends as
|
||||||
|
// the line runs on beyond the joint
|
||||||
|
std::vector<std::array<double, 3>> back;
|
||||||
|
for (auto const &path : switched->m_paths)
|
||||||
|
for (auto const atend : {false, true})
|
||||||
|
{
|
||||||
|
if (false == back.empty() || glm::distance(path.points[atend ? segment_data::point::end : segment_data::point::start], joint) > 0.05)
|
||||||
|
continue;
|
||||||
|
std::vector<segment_data> pieces{path.pieces.empty() ? std::vector<segment_data>{path} : path.pieces};
|
||||||
|
if (atend)
|
||||||
|
std::reverse(pieces.begin(), pieces.end());
|
||||||
|
for (auto const &piece : pieces)
|
||||||
|
back.push_back({bezier{piece}.plan_length(), atend ? curvature_at(piece, 1.0) : -curvature_at(piece, 0.0), atend ? curvature_at(piece, 0.0) : -curvature_at(piece, 1.0)});
|
||||||
|
}
|
||||||
|
// the curve the switch ends with, and the straight of a straight frog after it
|
||||||
|
double straight{0.0};
|
||||||
|
std::optional<double> curvature;
|
||||||
|
for (auto const &[length, inner, outer] : back)
|
||||||
|
{
|
||||||
|
if (std::abs(inner) > 1e-4 || std::abs(outer) > 1e-4)
|
||||||
|
{
|
||||||
|
curvature = inner;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
straight += length;
|
||||||
|
}
|
||||||
|
if (false == curvature.has_value())
|
||||||
|
return {};
|
||||||
|
// the pieces laid as the line runs on from the switch
|
||||||
|
std::vector<std::array<double, 3>> line;
|
||||||
|
if (switched == From)
|
||||||
|
for (auto const &piece : Pieces)
|
||||||
|
line.push_back({bezier{piece}.plan_length(), curvature_at(piece, 0.0), curvature_at(piece, 1.0)});
|
||||||
|
else
|
||||||
|
for (auto piece{Pieces.rbegin()}; piece != Pieces.rend(); ++piece)
|
||||||
|
line.push_back({bezier{*piece}.plan_length(), -curvature_at(*piece, 1.0), -curvature_at(*piece, 0.0)});
|
||||||
|
// no faster than the diverging track of the switch lets
|
||||||
|
auto const speed{std::min(design_speed(From, To), editor_track::diverging_speed(1.0 / std::abs(*curvature)))};
|
||||||
|
return switch_curve::check_exit(*curvature, straight, line, speed, laying_norms().gauge).warnings;
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::give_own_speed(std::vector<TTrack *> const &Created) const
|
void editor_mode::give_own_speed(std::vector<TTrack *> const &Created) const
|
||||||
{
|
{
|
||||||
if (false == m_lay.own_speed || m_lay.style.velocity <= 0.0)
|
if (false == m_lay.own_speed || m_lay.style.velocity <= 0.0)
|
||||||
@@ -725,6 +780,8 @@ void editor_mode::finish_extend()
|
|||||||
first_step_done(first_step::laid);
|
first_step_done(first_step::laid);
|
||||||
if (target.track != nullptr)
|
if (target.track != nullptr)
|
||||||
first_step_done(first_step::join);
|
first_step_done(first_step::join);
|
||||||
|
if (auto const warnings{switch_exit_warnings(style, pieces.front().points[segment_data::point::start], target.track, target.position, pieces)}; false == warnings.empty())
|
||||||
|
ui()->set_status(lines_of(warnings), true);
|
||||||
m_node = created.back();
|
m_node = created.back();
|
||||||
ui()->set_node(m_node);
|
ui()->set_node(m_node);
|
||||||
nmt_fit_laid(from, created.back()->m_paths.front().points[segment_data::point::end]);
|
nmt_fit_laid(from, created.back()->m_paths.front().points[segment_data::point::end]);
|
||||||
@@ -1610,6 +1667,8 @@ void editor_mode::lay_finish(editor_track::snap_target const &End)
|
|||||||
tool.status += "\n" + format(STR_C("Curve %d %s"), curve.vertex + 1, on.c_str());
|
tool.status += "\n" + format(STR_C("Curve %d %s"), curve.vertex + 1, on.c_str());
|
||||||
if (eased.has_value() && false == eased->note.empty())
|
if (eased.has_value() && false == eased->note.empty())
|
||||||
tool.status += "\n" + eased->note;
|
tool.status += "\n" + eased->note;
|
||||||
|
for (auto const &warning : switch_exit_warnings(tool.start.track, tool.points.front(), End.track, End.position, pieces))
|
||||||
|
tool.status += "\n" + warning;
|
||||||
{
|
{
|
||||||
std::vector<std::pair<TTrack *, bool>> run;
|
std::vector<std::pair<TTrack *, bool>> run;
|
||||||
if (tool.start.track != nullptr && tool.start.track->eType == tt_Normal)
|
if (tool.start.track != nullptr && tool.start.track->eType == tt_Normal)
|
||||||
|
|||||||
@@ -1980,6 +1980,8 @@ std::string editor_mode::track_readout() const
|
|||||||
text += "\n" + vertical;
|
text += "\n" + vertical;
|
||||||
if (snapped)
|
if (snapped)
|
||||||
text += "\n" + format(STR_C("joins %s"), name(target.track).c_str());
|
text += "\n" + format(STR_C("joins %s"), name(target.track).c_str());
|
||||||
|
for (auto const &warning : switch_exit_warnings(m_extend.track, m_extend.point, snapped ? target.track : nullptr, target.position, pieces))
|
||||||
|
text += "\n" + warning;
|
||||||
if (false == reason.empty())
|
if (false == reason.empty())
|
||||||
text += "\n" + reason;
|
text += "\n" + reason;
|
||||||
return text + "\n" + track_shaping(snapped);
|
return text + "\n" + track_shaping(snapped);
|
||||||
@@ -2052,6 +2054,8 @@ std::string editor_mode::track_readout() const
|
|||||||
if (auto const vertical{vertical_of(lay.preview)}; false == vertical.empty())
|
if (auto const vertical{vertical_of(lay.preview)}; false == vertical.empty())
|
||||||
text += "\n" + vertical;
|
text += "\n" + vertical;
|
||||||
}
|
}
|
||||||
|
for (auto const &warning : switch_exit_warnings(lay.start.track, lay.points.empty() ? lay.mouse : lay.points.front(), lay.mouse_snap.track, lay.mouse_snap.position, lay.preview))
|
||||||
|
text += "\n" + warning;
|
||||||
if (false == lay.points.empty() && lay.mouse_snap.track != nullptr)
|
if (false == lay.points.empty() && lay.mouse_snap.track != nullptr)
|
||||||
text += "\n" + format(STR_C("joins %s"), name(lay.mouse_snap.track).c_str());
|
text += "\n" + format(STR_C("joins %s"), name(lay.mouse_snap.track).c_str());
|
||||||
if (false == lay.preview_error.empty())
|
if (false == lay.preview_error.empty())
|
||||||
|
|||||||
@@ -254,6 +254,68 @@ slip_report check_slip(std::vector<std::vector<track_point>> const &Tracks, std:
|
|||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit_report check_exit(double const Curvature, double const Straight, std::vector<std::array<double, 3>> const &Line, double const Speed, double const Gauge)
|
||||||
|
{
|
||||||
|
exit_report report;
|
||||||
|
// table 9.15 and table 9.16, track connections
|
||||||
|
report.allowed = Speed <= 60.0 ? 130.0 : Speed <= 100.0 ? 100.0 : Speed <= 160.0 ? 80.0 : 60.0;
|
||||||
|
report.element = Speed <= 60.0 ? 6.0 : Speed <= 100.0 ? 0.15 * Speed : 0.25 * Speed;
|
||||||
|
// mm of the cant deficiency the change of the curvature makes at once: 11.8 V^2 / R at the standard gauge
|
||||||
|
auto const sudden = [&](double const Before, double const After) { return Gauge * Speed * Speed / (9.81 * 3.6 * 3.6) * std::abs(After - Before); };
|
||||||
|
// 1/m, a change of the curvature as large at once is a sudden one
|
||||||
|
constexpr double kSudden{1e-4};
|
||||||
|
struct change
|
||||||
|
{
|
||||||
|
double along; // from the end of the switch
|
||||||
|
double before;
|
||||||
|
double after;
|
||||||
|
};
|
||||||
|
std::vector<change> changes;
|
||||||
|
auto curvature{Curvature};
|
||||||
|
if (Straight > 0.0 && std::abs(Curvature) > kSudden)
|
||||||
|
{
|
||||||
|
changes.push_back({-Straight, Curvature, 0.0});
|
||||||
|
curvature = 0.0;
|
||||||
|
}
|
||||||
|
double along{0.0};
|
||||||
|
for (auto const &[length, start, end] : Line)
|
||||||
|
{
|
||||||
|
if (std::abs(start - curvature) > kSudden)
|
||||||
|
changes.push_back({along, curvature, start});
|
||||||
|
curvature = end;
|
||||||
|
along += length;
|
||||||
|
}
|
||||||
|
// the curve of the switch going on into the line: nothing of the switch to judge
|
||||||
|
if (changes.empty() || changes.front().along > 1e-6)
|
||||||
|
return report;
|
||||||
|
auto const &first{changes.front()};
|
||||||
|
auto const alone = [&](change const &Change) {
|
||||||
|
auto const value{sudden(Change.before, Change.after)};
|
||||||
|
report.change = std::max(report.change, value);
|
||||||
|
if (value > report.allowed)
|
||||||
|
report.warnings.emplace_back(format(STR_C("Behind the switch the curvature changes at once by a sudden change of the cant deficiency of %.0f mm, over the %.0f mm allowed at %.0f km/h (table 9.15)"), value, report.allowed, Speed));
|
||||||
|
};
|
||||||
|
if (changes.size() > 1)
|
||||||
|
{
|
||||||
|
auto const &next{changes[1]};
|
||||||
|
report.apart = next.along - first.along;
|
||||||
|
if (report.apart < report.element)
|
||||||
|
{
|
||||||
|
// taken together, from before the first one to after the next one (9.11 pkt 8b, 9)
|
||||||
|
report.change = sudden(first.before, next.after);
|
||||||
|
if (report.change > report.allowed)
|
||||||
|
report.warnings.emplace_back(format(STR_C("The curve behind the switch begins %.1f m after the end of its curve, closer than the %.1f m which take the sudden changes of the cant deficiency apart: together %.0f mm, over the %.0f mm allowed at %.0f km/h (tables 9.15, 9.16)"),
|
||||||
|
report.apart, report.element, report.change, report.allowed, Speed));
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
alone(next);
|
||||||
|
}
|
||||||
|
// the end of the curve of the switch at its end, not within it over a straight frog: that one is the switch's own
|
||||||
|
if (first.along > -1e-6)
|
||||||
|
alone(first);
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
double snapped_start(std::vector<double> const &Ramps, double const Pressed, double const Length, int const Direction, double const Reach, std::string *What)
|
double snapped_start(std::vector<double> const &Ramps, double const Pressed, double const Length, int const Direction, double const Reach, std::string *What)
|
||||||
{
|
{
|
||||||
auto const d{Direction < 0 ? -1.0 : 1.0};
|
auto const d{Direction < 0 ? -1.0 : 1.0};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -76,6 +77,21 @@ struct slip_report
|
|||||||
// From and To the stations of the ends of the first track through the slip along it
|
// From and To the stations of the ends of the first track through the slip along it
|
||||||
slip_report check_slip(std::vector<std::vector<track_point>> const &Tracks, std::vector<std::vector<track_point>> const &Curves, std::vector<track_point> const &Line, double const From, double const To);
|
slip_report check_slip(std::vector<std::vector<track_point>> const &Tracks, std::vector<std::vector<track_point>> const &Curves, std::vector<track_point> const &Line, double const From, double const To);
|
||||||
|
|
||||||
|
// a line laid on from the end of the diverging track of a switch, as ST-T1-A6 sees the sudden changes of the cant deficiency right behind
|
||||||
|
// the switch (9.11): Curvature the switch ends with (1/m, positive to the left as the line runs on), Straight metres before its end
|
||||||
|
// over a straight frog, then the pieces of the line, each its length and its curvature at its start and at its end. The first two
|
||||||
|
// sudden changes nearer than the intermediate element of table 9.16 taken together, else each one alone, against table 9.15 for track
|
||||||
|
// connections at the Speed (km/h); Gauge between the axes of the rails, mm
|
||||||
|
struct exit_report
|
||||||
|
{
|
||||||
|
double apart{-1.0}; // m, from the end of the curve of the switch to the next sudden change, -1 none
|
||||||
|
double change{0.0}; // mm, the largest sudden change of the cant deficiency judged
|
||||||
|
double allowed{0.0}; // mm, table 9.15
|
||||||
|
double element{0.0}; // m, the intermediate element of table 9.16
|
||||||
|
std::vector<std::string> warnings;
|
||||||
|
};
|
||||||
|
exit_report check_exit(double const Curvature, double const Straight, std::vector<std::array<double, 3>> const &Line, double const Speed, double const Gauge = 1500.0);
|
||||||
|
|
||||||
// the start of a switch Length long, going Direction along the line, drawn to where its start or its end meets an end of a cant ramp,
|
// the start of a switch Length long, going Direction along the line, drawn to where its start or its end meets an end of a cant ramp,
|
||||||
// or to where it keeps the 6 m off it, when the station pressed is within Reach of that; What receives which of them, empty for none
|
// or to where it keeps the 6 m off it, when the station pressed is within Reach of that; What receives which of them, empty for none
|
||||||
double snapped_start(std::vector<double> const &Ramps, double const Pressed, double const Length, int const Direction, double const Reach, std::string *What = nullptr);
|
double snapped_start(std::vector<double> const &Ramps, double const Pressed, double const Length, int const Direction, double const Reach, std::string *What = nullptr);
|
||||||
|
|||||||
@@ -12444,3 +12444,9 @@ msgstr "Tor przecinający rozjazdu krzyżowego jest dalej połączony: rozjazd z
|
|||||||
|
|
||||||
msgid "Slip %s moved %.2f m along its track, its crossing track with it"
|
msgid "Slip %s moved %.2f m along its track, its crossing track with it"
|
||||||
msgstr "Rozjazd krzyżowy %s przesunięty o %.2f m wzdłuż toru, razem z torem przecinającym"
|
msgstr "Rozjazd krzyżowy %s przesunięty o %.2f m wzdłuż toru, razem z torem przecinającym"
|
||||||
|
|
||||||
|
msgid "Behind the switch the curvature changes at once by a sudden change of the cant deficiency of %.0f mm, over the %.0f mm allowed at %.0f km/h (table 9.15)"
|
||||||
|
msgstr "Za rozjazdem krzywizna zmienia się skokowo: nagła zmiana niedomiaru przechyłki %.0f mm, ponad dopuszczalne %.0f mm przy %.0f km/h (tab. 9.15)"
|
||||||
|
|
||||||
|
msgid "The curve behind the switch begins %.1f m after the end of its curve, closer than the %.1f m which take the sudden changes of the cant deficiency apart: together %.0f mm, over the %.0f mm allowed at %.0f km/h (tables 9.15, 9.16)"
|
||||||
|
msgstr "Łuk za rozjazdem zaczyna się %.1f m za końcem jego łuku, bliżej niż %.1f m odcinka pośredniego, który rozdziela nagłe zmiany niedomiaru przechyłki: łącznie %.0f mm, ponad dopuszczalne %.0f mm przy %.0f km/h (tab. 9.15, 9.16)"
|
||||||
|
|||||||
@@ -167,3 +167,33 @@ TEST_CASE("slip bent into a curve: the cant of the side track, a track through i
|
|||||||
auto const report{switch_curve::check_slip({first, arc(33.2, angle, 1.0 / 1000.0)}, {arc(21.0, 0.0, 1.0 / 190.0)}, curve, 150.0, 183.2)};
|
auto const report{switch_curve::check_slip({first, arc(33.2, angle, 1.0 / 1000.0)}, {arc(21.0, 0.0, 1.0 / 190.0)}, curve, 150.0, 183.2)};
|
||||||
CHECK(says(report.warnings, "9.7 pkt 12"));
|
CHECK(says(report.warnings, "9.7 pkt 12"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("switch exit: a curve right behind a straight frog, its sudden changes of the cant deficiency apart or together") {
|
||||||
|
double const sw{1.0 / 190.0};
|
||||||
|
// R 190 on behind a frog straight for 6.09 m, at 40 km/h: apart, 99 mm at the end, within the 130 mm of table 9.15
|
||||||
|
auto const same{switch_curve::check_exit(sw, 6.092, {{40.0, sw, sw}}, 40.0)};
|
||||||
|
CHECK(same.apart == doctest::Approx(6.092));
|
||||||
|
CHECK(same.element == doctest::Approx(6.0));
|
||||||
|
CHECK(same.change == doctest::Approx(99.4).epsilon(0.01));
|
||||||
|
CHECK(same.warnings.empty());
|
||||||
|
// the other way behind a frog straight of 1.66 m only: together, 199 mm, over the 130 mm
|
||||||
|
auto const reverse{switch_curve::check_exit(sw, 1.662, {{40.0, -sw, -sw}}, 40.0)};
|
||||||
|
CHECK(reverse.apart == doctest::Approx(1.662));
|
||||||
|
CHECK(reverse.change == doctest::Approx(198.8).epsilon(0.01));
|
||||||
|
REQUIRE(reverse.warnings.size() == 1);
|
||||||
|
CHECK(says(reverse.warnings, "tables 9.15, 9.16"));
|
||||||
|
// the same way behind it: together the curvature hardly changes
|
||||||
|
CHECK(switch_curve::check_exit(sw, 1.662, {{40.0, sw, sw}}, 40.0).warnings.empty());
|
||||||
|
// a straight of 5 m laid on first: 6.66 m apart, the curve the other way alone, 99 mm
|
||||||
|
auto const later{switch_curve::check_exit(sw, 1.662, {{5.0, 0.0, 0.0}, {40.0, -sw, -sw}}, 40.0)};
|
||||||
|
CHECK(later.apart == doctest::Approx(6.662));
|
||||||
|
CHECK(later.warnings.empty());
|
||||||
|
// a sharp curve of R 100 alone: 189 mm
|
||||||
|
CHECK(says(switch_curve::check_exit(sw, 6.092, {{30.0, 0.01, 0.01}}, 40.0).warnings, "table 9.15"));
|
||||||
|
// a transition out of the frog straight: no sudden change behind it
|
||||||
|
CHECK(switch_curve::check_exit(sw, 1.662, {{20.0, 0.0, -sw}, {20.0, -sw, -sw}}, 40.0).warnings.empty());
|
||||||
|
// the curve of a switch with a curved frog going on: nothing of the switch to judge
|
||||||
|
auto const on{switch_curve::check_exit(1.0 / 300.0, 0.0, {{30.0, 1.0 / 300.0, 1.0 / 300.0}}, 50.0)};
|
||||||
|
CHECK(on.apart < 0.0);
|
||||||
|
CHECK(on.warnings.empty());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user