17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 02:49:19 +02:00

feat: structure gauge along the line of the selected path in the OpenGL view

This commit is contained in:
maj00r
2026-10-04 01:27:41 +02:00
parent 661c211b2e
commit b0c363b586
12 changed files with 696 additions and 1 deletions

110
editor/editorGauge.cpp Normal file
View File

@@ -0,0 +1,110 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "editor/editorGauge.hpp"
#include <fstream>
#include <sstream>
namespace gauge
{
std::vector<profile> default_profiles()
{
std::vector<profile::point> const lower{{1.645, 0.05}, {1.645, 0.30}, {1.720, 0.30}, {1.720, 1.10}, {2.200, 1.10}, {2.200, 3.85}, {1.900, 4.25}};
profile plain{"A (bez sieci)", lower};
plain.outline.insert(plain.outline.end(), {{1.400, 4.85}, {0.0, 4.85}});
profile electrified{"C (sieć trakcyjna)", lower};
electrified.outline.insert(electrified.outline.end(), {{1.700, 4.85}, {1.400, 5.60}, {1.000, 6.00}, {0.0, 6.00}});
return {plain, electrified};
}
// one outline per line: the name in quotes, then pairs of half-width and height
std::vector<profile> load_profiles(std::string const &File)
{
std::ifstream input{File};
std::vector<profile> profiles;
std::string line;
while (std::getline(input, line))
{
std::istringstream stream{line};
profile profile;
if (false == static_cast<bool>(stream >> std::quoted(profile.name)))
continue;
profile::point point;
while (stream >> point.half_width >> point.height)
profile.outline.push_back(point);
if (profile.outline.size() >= 2)
profiles.push_back(std::move(profile));
}
return profiles.empty() ? default_profiles() : profiles;
}
void save_profiles(std::string const &File, std::vector<profile> const &Profiles)
{
std::ofstream output{File};
for (auto const &profile : Profiles)
{
output << std::quoted(profile.name);
for (auto const &point : profile.outline)
output << ' ' << point.half_width << ' ' << point.height;
output << '\n';
}
}
double curve_widening(double const Radius)
{
// smallest radius of the class and its widening in mm; the radius between the classes takes the larger one
static constexpr std::pair<double, double> table[]{{3500, 10}, {2500, 15}, {1800, 20}, {1500, 25}, {1200, 30}, {1000, 35},
{900, 40}, {800, 45}, {700, 50}, {600, 60}, {500, 75}, {450, 80},
{400, 90}, {350, 105}, {300, 120}, {280, 130}, {260, 140}, {250, 145},
{240, 150}, {220, 165}, {200, 180}, {190, 190}, {180, 200}};
if (Radius <= 0.0 || Radius >= 4000.0)
return 0.0;
for (auto const &[radius, widening] : table)
if (Radius >= radius)
return widening * 0.001;
return 36.0 / Radius;
}
double cant_widening(double const Cant, double const Height)
{
return Height * Cant / 1.5;
}
double half_width(profile const &Profile, section const &Section, double const Height, int const Side)
{
double width{-1.0};
for (std::size_t i = 1; i < Profile.outline.size(); ++i)
{
auto const &a{Profile.outline[i - 1]};
auto const &b{Profile.outline[i]};
if (Height < std::min(a.height, b.height) || Height > std::max(a.height, b.height))
continue;
auto const span{b.height - a.height};
width = std::max(width, std::abs(span) < 1e-9 ? std::max(a.half_width, b.half_width) : a.half_width + (b.half_width - a.half_width) * (Height - a.height) / span);
}
if (width < 0.0)
return width;
width += curve_widening(Section.radius);
if (Section.inner != 0 && Side == Section.inner)
width += cant_widening(Section.cant, Height);
return width;
}
double intrusion(profile const &Profile, section const &Section, double const Lateral, double const Height)
{
auto const width{half_width(Profile, Section, Height, Lateral >= 0.0 ? 1 : -1)};
if (width < 0.0)
return 0.0;
return width - std::abs(Lateral);
}
} // namespace gauge

55
editor/editorGauge.hpp Normal file
View File

@@ -0,0 +1,55 @@
/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <string>
#include <vector>
// structure gauge (skrajnia budowli): the space along the track which has to stay clear of the objects
namespace gauge
{
// right half of the outline on a straight track, in metres: half-width from the axis and height above the rail top,
// listed from the bottom up; the left half is the mirror
struct profile
{
std::string name;
struct point
{
double half_width{0.0};
double height{0.0};
};
std::vector<point> outline;
};
// starting points of the outlines, approximations to verify against PN-69/K-02057
std::vector<profile> default_profiles();
// outlines kept in the file, the defaults when there's none
std::vector<profile> load_profiles(std::string const &File);
void save_profiles(std::string const &File, std::vector<profile> const &Profiles);
// widening of both sides in a curve, from the radius (table 1 of the D1 annex 11), metres
double curve_widening(double Radius);
// widening of the inner side of a curve from the tilt of the vehicles on the cant, at the height above the rail top, metres
double cant_widening(double Cant, double Height);
// place of the gauge across the track
struct section
{
double radius{0.0}; // 0: straight
int inner{0}; // side of the curve centre, +1 left or -1 right, 0 on a straight
double cant{0.0}; // metres
};
// half-width of the gauge at the height on the side (+1 left, -1 right), negative above or below the outline
double half_width(profile const &Profile, section const &Section, double Height, int Side);
// depth of the point inside the gauge, metres, not positive outside of it. Lateral positive to the left
double intrusion(profile const &Profile, section const &Section, double Lateral, double Height);
} // namespace gauge

View File

@@ -1406,7 +1406,8 @@ std::vector<editor_track::route_sample> editor_track::sample_route(route &Route,
for (std::size_t i = 0; i < Route.spans.size(); ++i)
{
auto &span{Route.spans[i]};
bezier const curve{span.track->m_paths[span.path]};
auto const &path{span.track->m_paths[span.path]};
bezier const curve{path};
auto const count{std::max(2, static_cast<int>(std::ceil(curve.plan_length(16) / std::max(0.1, Step))))};
span.from = chainage;
auto previous{plan_of(curve.point(span.forward ? 0.0 : 1.0))};
@@ -1425,6 +1426,7 @@ std::vector<editor_track::route_sample> editor_track::sample_route(route &Route,
sample.chainage = chainage;
sample.position = position;
sample.span = i;
sample.cant = 1.5 * std::sin(std::abs(glm::radians(path.rolls[0] + (path.rolls[1] - path.rolls[0]) * t)));
if (planar > 1e-9)
{
sample.direction = plan_of(derivative) / planar;

View File

@@ -175,6 +175,7 @@ class editor_track
glm::dvec2 direction{0.0, 1.0};
double grade{0.0};
double curvature{0.0}; // signed, 1/m, positive turning left
double cant{0.0}; // m, raise of the outer rail
std::size_t span{0};
};
static std::vector<route_sample> sample_route(route &Route, double const Step);