17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-04 16:05:51 +01:00

feat(track): rails are cut where they cross other rails: a switch with the key frogs draws its frog, wing rails and check rails from its rails, tracks crossing other tracks get acute frogs with wing rails and check rails, obtuse points, guard rails along the quadrilateral of a crossing between 20 and 45 degrees and broken rails with guard rails at wider angles, the track going through chosen by name; sizes come from the rail profile, only for the profiles default, s60, uic60 and s39, others are laid whole; rail ends left open are closed with their cross-section; switches of older sceneries, with check rails in their includes and no key, are drawn as before

This commit is contained in:
maj00r
2026-10-13 18:30:16 +02:00
parent f067824014
commit 16672e81cc
7 changed files with 1766 additions and 44 deletions

View File

@@ -99,6 +99,7 @@ class TSwitchExtension
glm::dvec3 vTrans; // docelowa translacja przesuwnicy
material_handle m_material3 = 0; // texture of auto generated switch trackbed
gfx::geometry_handle Geometry3; // geometry of auto generated switch trackbed
bool m_frogs { false }; // the frog and check rails are made from the rails, for switches with no model of them in their includes
gfx::geometrybank_handle map_geometry[6]; // geometry for map visualisation
};
@@ -184,9 +185,14 @@ public:
using geometryhandle_sequence = std::vector<gfx::geometry_handle>;
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
material_handle m_materialcut1 = 0; // matte variant of texture 1, for the cut faces of rails
material_handle m_materialcut2 = 0; // matte variant of texture 2, for the cut faces of rails of the other switch path
geometryhandle_sequence GeometryCut1; // cut faces of rails textured with texture 1, the blade tip first for a switch
geometryhandle_sequence GeometryCut2; // cut faces of rails textured with texture 2, the blade tip first
std::vector<segment_data> m_paths; // source data for owned paths
bool m_editorremoved { false };
std::vector<TTrack *> m_crossings; // tracks whose rails cross the rails of this one, found when its geometry was made
scene::basic_node *m_road { nullptr }; // road or road junction which generated this path. such path is one-way, and isn't saved nor edited on its own
std::array<float, 3> m_routeweights { 0.f, 0.f, 0.f }; // odds of each route through a crossroads being picked by a driver, by the number of the route. all zero: even odds
int iterate_stamp = 0;
@@ -286,6 +292,80 @@ public:
int RouteDraw() const;
void Load(cParser *parser, glm::dvec3 const &pOrigin);
void init_segments( bool const Initial );
// where the inner rails of the two paths of a switch cross, found from their gauge lines behind the blades
struct switch_frog {
bool valid { false };
int side[ 2 ] {}; // rail profile of the crossing rail of each path, 1 right, -1 left
double at[ 2 ] {}; // distance of the crossing along each path
double blades[ 2 ] {}; // distance the blades take along each path
double angle { 0.0 };
};
switch_frog frog() const;
// where a rail of this track crosses a rail of another one, found from their gauge lines
struct rail_crossing {
TTrack *track { nullptr };
int path { 0 };
int side { 0 }; // rail profile of the crossing rail, 1 right, -1 left
double at { 0.0 }; // distance of the crossing along the path, past the ends where the track goes on
double angle { 0.0 };
double into { 0.0 }; // the path direction against the gauge normal of the other rail, above zero: going into the other track
double facing { 0.0 }; // the gauge normals of both rails against each other, below zero: an acute frog
bool nose { false }; // at an acute frog the rail goes on as the nose rail, the other one as the rail beside it
int otherpath { 0 };
int otherside { 0 }; // rail profile of the other rail, 1 right, -1 left
double otherat { 0.0 }; // distance of the crossing along the other path
bool aligned { true }; // both paths run the same way at the crossing
};
std::vector<rail_crossing> rail_crossings( bool const Joined = true );
// the size of the rail profile, out from the gauge face: positive outwards, the side of the head away from the track
struct rail_size {
double head { 0.0735 }; // how far the head reaches out
double height { 0.172 };
double low { -0.0385 }; // the reach of the profile inwards
double high { 0.1115 }; // the reach of the profile outwards
};
rail_size rail_dimensions() const;
// a check rail beside a rail, how far its ends turn away from the running rail
struct check_rail {
double from { 0.0 };
double to { 0.0 };
double flarefrom { 0.0 };
double flareto { 0.0 };
};
using check_rail_set = std::array<std::array<std::vector<check_rail>, 2>, 2>; // path, right side
// the check rails beside the rails of each path, kept clear of the blades and the rails of other paths running inside them
check_rail_set check_rails( std::vector<rail_crossing> const &Crossings );
// a rail broken where another one crosses it: the part coming from below ends at end, the part going on starts at start
struct rail_cut {
double at { 0.0 };
double end { 0.0 };
double start { 0.0 };
std::vector<glm::dvec2> endoffsets, endextents, startoffsets, startextents;
std::vector<glm::dvec2> endrolled, startrolled; // how far out from the gauge line the wheels roll on the head, of the part coming from below and of the part going on
glm::dvec2 endmiter { 0.0 };
glm::dvec2 startmiter { 0.0 };
};
struct rail_plan {
std::vector<rail_cut> cuts;
};
// guard rails of a crossing at a wide angle: the rail profile laid inside the running rail across the flangeway, broken like the rails
struct guard_rail {
double from { 0.0 };
double to { 0.0 };
rail_plan plan;
bool flarefrom { true };
bool flareto { true };
glm::dvec2 frommiter { 0.0 };
glm::dvec2 tomiter { 0.0 };
};
struct rail_layout {
rail_plan plans[ 2 ][ 2 ]; // path, right side
std::vector<guard_rail> guards[ 2 ][ 2 ];
std::vector<glm::dvec2> wingends[ 2 ][ 2 ]; // ends of the wing rails of other rails running along each rail, and which way they run there
check_rail_set checks;
std::vector<TTrack *> crossed; // tracks whose rails cross the rails of this one
};
rail_layout plan_rails( bool const Crossings );
void update_location();
bool AssignEvents();
bool AssignForcedEvents(basic_event *NewEventPlus, basic_event *NewEventMinus);
@@ -367,8 +447,10 @@ private:
float texture_length( material_handle const Material );
// creates profile for a part of current path
void create_switch_trackbed( gfx::vertex_array &Output );
void create_track_rail_profile( gfx::vertex_array &Right, gfx::vertex_array &Left );
void create_track_rail_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const *Shape = nullptr );
void create_track_blade_profile( gfx::vertex_array &Right, gfx::vertex_array &Left );
void profile_rolls( float &Roll1, float &Roll2 ) const;
void share_joints();
void create_track_bed_profile( gfx::vertex_array &Output, TTrack const *Previous, TTrack const *Next );
void create_road_profile( gfx::vertex_array &Output, bool const Forcetransition = false );
void create_road_side_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const &Road, bool const Forcetransition = false );
@@ -378,6 +460,15 @@ private:
/// Safe to call multiple times; clears any previously cached transforms first.
/// </summary>
void build_sleeper_transforms();
struct rail_drawing {
gfx::geometrybank_handle bank;
rail_size size;
float halfwidth { 0.f };
gfx::vertex_array checkshapes[ 2 ];
};
rail_drawing make_rail_drawing( gfx::geometrybank_handle const &Bank );
// a rail along a path from a distance on, in parts where other rails cross it, and the check rails beside it. false: no crossing, the rail is laid whole as before
bool lay_rail( rail_layout const &Layout, rail_drawing const &Drawing, int const Path, gfx::vertex_array const &Profile, int const Side, float const Texturelength, double const From, bool const Openstart, bool const Openend, geometryhandle_sequence &Geometry, geometryhandle_sequence &Cuts );
// members
static profiles_array m_profiles; // shared database of path element profiles
static profiles_map m_profilesmap;