mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 16:40:21 +01:00
Merge remote-tracking branch 'origin/feat/track-uneven' into feat/renderers-cleanup
This commit is contained in:
@@ -81,6 +81,10 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
|
||||
// poprawienie przechyłki
|
||||
fRoll1 = static_cast<float>(glm::radians(fNewRoll1)); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = static_cast<float>(glm::radians(fNewRoll2));
|
||||
m_designrolls[ 0 ] = fRoll1;
|
||||
m_designrolls[ 1 ] = fRoll2;
|
||||
m_joints[ 0 ].reset();
|
||||
m_joints[ 1 ].reset();
|
||||
bCurve = bIsCurve;
|
||||
if (Global.bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
@@ -175,6 +179,8 @@ bool TSegment::InitChain(std::vector<std::shared_ptr<TSegment>> Pieces)
|
||||
Point2 = last.Point2;
|
||||
fRoll1 = first.fRoll1;
|
||||
fRoll2 = last.fRoll2;
|
||||
m_designrolls[ 0 ] = first.m_designrolls[ 0 ];
|
||||
m_designrolls[ 1 ] = last.m_designrolls[ 1 ];
|
||||
bCurve = true;
|
||||
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
|
||||
fStoop = std::atan2(Point2.y - Point1.y, fLength);
|
||||
@@ -437,7 +443,7 @@ void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::
|
||||
// direction and slope stay as designed: the physics takes the curve radius and the grade from them
|
||||
auto const gauge { std::max( std::abs( pOwner->fTrackWidth ), 0.1f ) };
|
||||
glm::dvec3 const across { -std::cos( rotation.z ), 0.0, -std::sin( rotation.z ) };
|
||||
auto const amount { pOwner->uneven_at( fDistance ) };
|
||||
auto const amount { pOwner->uneven_at( fDistance, m_path ) };
|
||||
rotation.x += static_cast<float>( track_uneven::stray_per_mm * (
|
||||
amount.up * track_uneven::roll( position, across, gauge )
|
||||
+ amount.cross * track_uneven::level( position, across ) / gauge ) );
|
||||
@@ -445,7 +451,7 @@ void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::
|
||||
}
|
||||
|
||||
glm::dvec3 TSegment::stray( glm::dvec3 const &Point, double const Distance ) const {
|
||||
auto const amount { pOwner->uneven_at( Distance ) };
|
||||
auto const amount { pOwner->uneven_at( Distance, m_path ) };
|
||||
auto const field { track_uneven::field( Point ) };
|
||||
glm::dvec3 result { field.x * amount.side, field.y * amount.up, field.z * amount.side };
|
||||
result *= track_uneven::stray_per_mm;
|
||||
@@ -468,11 +474,12 @@ void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origi
|
||||
if( false == m_uneven ) {
|
||||
return;
|
||||
}
|
||||
// the rails settling apart turn about the middle of the track, what's outside them follows the rail
|
||||
// the rails settling apart turn about the middle of the track, what's outside them follows the rail; the foot of the ballast stays
|
||||
auto const gauge { std::max( std::abs( pOwner->fTrackWidth ), 0.1f ) };
|
||||
auto const across { std::clamp( glm::dot( Vertex.position - Position, Parallel ), -0.5f * gauge, 0.5f * gauge ) };
|
||||
Vertex.position.y -= static_cast<float>( track_uneven::stray_per_mm * pOwner->uneven_at( Distance ).cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge );
|
||||
Vertex.position += glm::vec3 { stray( Origin + glm::dvec3 { Vertex.position }, Distance ) };
|
||||
auto const share { pOwner->uneven_bed_share( Position.y - Vertex.position.y ) };
|
||||
Vertex.position.y -= static_cast<float>( share * track_uneven::stray_per_mm * pOwner->uneven_at( Distance, m_path ).cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge );
|
||||
Vertex.position += glm::vec3 { share * stray( Origin + glm::dvec3 { Vertex.position }, Distance ) };
|
||||
}
|
||||
|
||||
void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
|
||||
|
||||
@@ -9,12 +9,13 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "utilities/Classes.h"
|
||||
#include "rendering/geometrybank.h"
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include "world/Knots.h"
|
||||
|
||||
struct map_colored_paths {
|
||||
@@ -101,7 +102,11 @@ class TSegment
|
||||
glm::dvec3 Point2;
|
||||
float fRoll1 { 0.f };
|
||||
float fRoll2 { 0.f }; // przechyłka na końcach
|
||||
float m_designrolls[ 2 ] { 0.f, 0.f }; // as entered; the two above can differ at a joint
|
||||
bool m_uneven { false }; // see TrackUneven.h
|
||||
int m_path { 0 }; // which path of a switch
|
||||
// where the path meets the next one: the middle of their ends and their common vector across
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> m_joints[ 2 ];
|
||||
double fLength { -1.0 }; // długość policzona
|
||||
std::vector<double> fTsBuffer; // wartości parametru krzywej t dla równych odcinków s
|
||||
std::vector<double> fTsSlope; // nachylenie dt/du (= dt/ds * fStep) w tych samych punktach
|
||||
@@ -115,7 +120,6 @@ class TSegment
|
||||
TTrack *pOwner = nullptr; // wskaźnik na właściciela
|
||||
std::vector<std::shared_ptr<TSegment>> m_pieces; // parts of a path made of several curves, parametrized by distance
|
||||
std::vector<double> m_starts; // distance from Point1 to the start of each part
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> m_joints[ 2 ];
|
||||
double m_dense { 0.0 };
|
||||
// a switch makes the profiles of its rails and its bed at the mean of the rolls of its paths: lofted along a path, they're turned
|
||||
// from it to the roll of the path there, so a switch on a cant ramp follows it; none for the other paths
|
||||
@@ -188,8 +192,16 @@ public:
|
||||
void RaPositionGet(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const;
|
||||
// call before Init, it sets the density of the geometry
|
||||
void
|
||||
set_uneven( bool const Uneven ) {
|
||||
m_uneven = Uneven; }
|
||||
set_uneven( bool const Uneven, int const Path = 0 ) {
|
||||
m_uneven = Uneven;
|
||||
m_path = Path; }
|
||||
float
|
||||
design_roll( int const End ) const {
|
||||
return m_designrolls[ End ]; }
|
||||
void
|
||||
set_joint( int const End, std::optional<std::pair<glm::dvec3, glm::dvec3>> const &Joint, float const Roll ) {
|
||||
m_joints[ End ] = Joint;
|
||||
( End == 0 ? fRoll1 : fRoll2 ) = Roll; }
|
||||
// second derivative of the displacement along the path; times speed squared: acceleration of an axle
|
||||
glm::dvec3
|
||||
uneven_bend( double const Distance ) const;
|
||||
@@ -227,9 +239,6 @@ public:
|
||||
// point of the path and the unit vector across it towards the right rail profile, at a distance from Point1
|
||||
void
|
||||
plan_frame( double const Distance, glm::dvec3 &Point, glm::dvec3 &Across ) const;
|
||||
void
|
||||
set_joint( int const End, std::optional<std::pair<glm::dvec3, glm::dvec3>> const &Joint ) {
|
||||
m_joints[ End ] = Joint; }
|
||||
void
|
||||
set_dense( double const Distance ) {
|
||||
m_dense = Distance; }
|
||||
|
||||
217
world/Track.cpp
217
world/Track.cpp
@@ -87,6 +87,9 @@ TTrack::profiles_array TTrack::m_profiles;
|
||||
TTrack::profiles_map TTrack::m_profilesmap;
|
||||
int TTrack::s_layoutstamp { 0 };
|
||||
|
||||
// how near an end of a path counts as being at a point, m
|
||||
static double const switch_end_reach { 0.3 };
|
||||
|
||||
TSwitchExtension::TSwitchExtension(TTrack *owner, int const what)
|
||||
{ // na początku wszystko puste
|
||||
pNexts[0] = nullptr; // wskaźniki do kolejnych odcinków ruchu
|
||||
@@ -737,24 +740,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
}
|
||||
}
|
||||
else if( str == "uneven" ) {
|
||||
// uneven <mm>: see TrackUneven.h
|
||||
auto const uneven { parser->getToken<float>() };
|
||||
// uneven <mm>[;<mm>...]: see read_uneven and TrackUneven.h. The semicolons stay in the token
|
||||
auto const values { parser->getToken<std::string>( false, "\n\r\t " ) };
|
||||
if( ( eType == tt_Normal || eType == tt_Switch ) && iCategoryFlag == 1 ) {
|
||||
m_uneven = std::clamp( uneven, 0.f, track_uneven::most );
|
||||
}
|
||||
}
|
||||
else if( str == "unevenup" || str == "unevenside" || str == "unevencross" ) {
|
||||
// the components of uneven set apart, mm
|
||||
auto const value { parser->getToken<float>() };
|
||||
if( ( eType == tt_Normal || eType == tt_Switch ) && iCategoryFlag == 1 ) {
|
||||
( str == "unevenup" ? m_unevenup : str == "unevenside" ? m_unevenside : m_unevencross ) = std::clamp( value, 0.f, track_uneven::most );
|
||||
}
|
||||
}
|
||||
else if( str == "jointdip" ) {
|
||||
// jointdip <mm>: depth of the dip at rail joints, with or without uneven
|
||||
auto const jointdip { parser->getToken<float>() };
|
||||
if( eType == tt_Normal && iCategoryFlag == 1 ) {
|
||||
m_jointdip = std::clamp( jointdip, 0.f, track_uneven::most );
|
||||
read_uneven( values );
|
||||
}
|
||||
}
|
||||
else if( str == "friction" ) {
|
||||
@@ -833,75 +822,166 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
// to a stale origin and the renderer would draw sleepers in the wrong place).
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_declared() const {
|
||||
void TTrack::read_uneven( std::string const &Text ) {
|
||||
|
||||
return {
|
||||
auto const fields { track_uneven::read_fields<6>( Text ) };
|
||||
m_uneven = std::max( fields[ 0 ], 0.f );
|
||||
if( eType == tt_Switch ) {
|
||||
m_unevenbranch = fields[ 1 ];
|
||||
m_unevenup = fields[ 2 ];
|
||||
m_unevenside = fields[ 3 ];
|
||||
m_unevenbranchup = fields[ 4 ];
|
||||
m_unevenbranchside = fields[ 5 ];
|
||||
}
|
||||
else {
|
||||
m_unevenup = fields[ 1 ];
|
||||
m_unevenside = fields[ 2 ];
|
||||
m_unevencross = fields[ 3 ];
|
||||
m_jointdip = fields[ 4 ];
|
||||
}
|
||||
}
|
||||
|
||||
std::string TTrack::uneven_text() const {
|
||||
|
||||
auto const fields { eType == tt_Switch ?
|
||||
std::array<float, 6> { m_uneven, m_unevenbranch, m_unevenup, m_unevenside, m_unevenbranchup, m_unevenbranchside } :
|
||||
std::array<float, 6> { m_uneven, m_unevenup, m_unevenside, m_unevencross, m_jointdip, -1.f } };
|
||||
if( m_uneven <= 0.f && std::all_of( fields.begin() + 1, fields.end(), []( float const Field ) { return Field < 0.f; } ) ) {
|
||||
return {};
|
||||
}
|
||||
return "uneven " + track_uneven::write_fields( fields ) + ' ';
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_declared( int const Path ) const {
|
||||
|
||||
track_uneven::amounts result {
|
||||
m_unevenup >= 0.f ? m_unevenup : m_uneven,
|
||||
m_unevenside >= 0.f ? m_unevenside : m_uneven,
|
||||
eType != tt_Normal ? 0.f : m_unevencross >= 0.f ? m_unevencross : m_uneven };
|
||||
if( Path == 1 ) {
|
||||
auto const branch = [ this ]( float const Part, double const Straight ) -> double {
|
||||
return Part >= 0.f ? Part : m_unevenbranch >= 0.f ? m_unevenbranch : Straight; };
|
||||
result.up = branch( m_unevenbranchup, result.up );
|
||||
result.side = branch( m_unevenbranchside, result.side );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TTrack::is_uneven() const {
|
||||
|
||||
auto const declared { uneven_declared() };
|
||||
return declared.up > 0.0 || declared.side > 0.0 || declared.cross > 0.0 || joint_depth() > 0.0;
|
||||
auto const any = []( track_uneven::amounts const &Amount ) {
|
||||
return Amount.up > 0.0 || Amount.side > 0.0 || Amount.cross > 0.0; };
|
||||
return any( uneven_declared( 0 ) ) || any( uneven_declared( 1 ) ) || joint_depth() > 0.0;
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_at( double const Distance ) const {
|
||||
double TTrack::uneven_bed_share( double const Depth ) const {
|
||||
|
||||
return track_uneven::bed_share( Depth, std::abs( track_rail_profile( m_profile1.second ).front().position.y ), fTexHeight1 );
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_at( double const Distance, int const Path ) const {
|
||||
|
||||
auto const along = [ Distance ]( track_uneven::amounts const &Own, track_uneven::amounts const &Start, track_uneven::amounts const &End, double const Length ) -> track_uneven::amounts {
|
||||
return {
|
||||
track_uneven::along( Own.up, Start.up, End.up, Distance, Length ),
|
||||
track_uneven::along( Own.side, Start.side, End.side, Distance, Length ),
|
||||
track_uneven::along( Own.cross, Start.cross, End.cross, Distance, Length ) }; };
|
||||
if( eType == tt_Switch ) {
|
||||
return switch_uneven();
|
||||
auto const &stray { switch_uneven() };
|
||||
return along( stray.paths[ Path ], stray.ends[ Path ][ 0 ], stray.ends[ Path ][ 1 ], SwitchExtension->Segments[ Path ]->GetLength() );
|
||||
}
|
||||
auto const own { uneven_declared() };
|
||||
auto const atend = [&]( TTrack const *Other ) -> track_uneven::amounts {
|
||||
auto const atend = [&]( TTrack const *Other, glm::dvec3 const &Point ) -> track_uneven::amounts {
|
||||
if( Other == nullptr ) {
|
||||
return {};
|
||||
}
|
||||
if( Other->eType == tt_Switch ) {
|
||||
return Other->switch_uneven();
|
||||
return Other->switch_uneven_at( Point );
|
||||
}
|
||||
auto const theirs { Other->uneven_declared() };
|
||||
return { std::min( own.up, theirs.up ), std::min( own.side, theirs.side ), std::min( own.cross, theirs.cross ) }; };
|
||||
auto const start { atend( trPrev ) };
|
||||
auto const end { atend( trNext ) };
|
||||
return {
|
||||
track_uneven::along( own.up, start.up, end.up, Distance, Length() ),
|
||||
track_uneven::along( own.side, start.side, end.side, Distance, Length() ),
|
||||
track_uneven::along( own.cross, start.cross, end.cross, Distance, Length() ) };
|
||||
return track_uneven::least( own, Other->uneven_declared() ); };
|
||||
return along( own, atend( trPrev, Segment->FastGetPoint_0() ), atend( trNext, Segment->FastGetPoint_1() ), Length() );
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::switch_uneven() const {
|
||||
TTrack::switch_stray const &TTrack::switch_uneven() const {
|
||||
|
||||
if( m_switchstray.stamp == s_layoutstamp ) {
|
||||
return m_switchstray.value;
|
||||
return m_switchstray;
|
||||
}
|
||||
std::vector<TTrack const *> group { this };
|
||||
auto least { uneven_declared() };
|
||||
std::array<track_uneven::amounts, 2> least { uneven_declared( 0 ), uneven_declared( 1 ) };
|
||||
for( std::size_t index = 0; index < group.size(); ++index ) {
|
||||
auto const &extension { *group[ index ]->SwitchExtension };
|
||||
for( auto const *other : { extension.pPrevs[ 0 ], extension.pPrevs[ 1 ], extension.pNexts[ 0 ], extension.pNexts[ 1 ] } ) {
|
||||
if( other == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
auto const theirs { other->uneven_declared() };
|
||||
if( other->eType == tt_Switch && other->SwitchExtension ) {
|
||||
least.up = std::min( least.up, theirs.up );
|
||||
least.side = std::min( least.side, theirs.side );
|
||||
least[ 0 ] = track_uneven::least( least[ 0 ], other->uneven_declared( 0 ) );
|
||||
least[ 1 ] = track_uneven::least( least[ 1 ], other->uneven_declared( 1 ) );
|
||||
if( std::find( group.begin(), group.end(), other ) == group.end() ) {
|
||||
group.push_back( other );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// a track with none of a component keeps to its design in it, any other comes to the value of the switch
|
||||
if( theirs.up <= 0.0 ) { least.up = 0.0; }
|
||||
if( theirs.side <= 0.0 ) { least.side = 0.0; }
|
||||
auto const theirs { other->uneven_declared() };
|
||||
for( auto &path : least ) {
|
||||
if( theirs.up <= 0.0 ) { path.up = 0.0; }
|
||||
if( theirs.side <= 0.0 ) { path.side = 0.0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for( auto const *track : group ) {
|
||||
track->m_switchstray = { least, s_layoutstamp };
|
||||
track->m_switchstray.paths = least;
|
||||
track->m_switchstray.stamp = s_layoutstamp;
|
||||
}
|
||||
return least;
|
||||
// the lowest of the paths of a switch ending at a point
|
||||
auto const paths_at = []( TTrack const &Track, glm::dvec3 const &Point ) {
|
||||
auto result { track_uneven::least( Track.m_switchstray.paths[ 0 ], Track.m_switchstray.paths[ 1 ] ) };
|
||||
auto found { false };
|
||||
track_uneven::amounts ending { track_uneven::most, track_uneven::most, track_uneven::most };
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
auto const &segment { *Track.SwitchExtension->Segments[ path ] };
|
||||
if( glm::length( segment.FastGetPoint_0() - Point ) < switch_end_reach || glm::length( segment.FastGetPoint_1() - Point ) < switch_end_reach ) {
|
||||
ending = track_uneven::least( ending, Track.m_switchstray.paths[ path ] );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found ? ending : result; };
|
||||
for( auto const *track : group ) {
|
||||
auto const &extension { *track->SwitchExtension };
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
auto const &segment { *extension.Segments[ path ] };
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
auto const point { end == 0 ? segment.FastGetPoint_0() : segment.FastGetPoint_1() };
|
||||
auto value { paths_at( *track, point ) };
|
||||
auto const *other { end == 0 ? extension.pPrevs[ path ] : extension.pNexts[ path ] };
|
||||
if( other != nullptr && other->eType == tt_Switch && other->SwitchExtension ) {
|
||||
value = track_uneven::least( value, paths_at( *other, point ) );
|
||||
}
|
||||
track->m_switchstray.ends[ path ][ end ] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_switchstray;
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::switch_uneven_at( glm::dvec3 const &Point ) const {
|
||||
|
||||
auto const &stray { switch_uneven() };
|
||||
auto found { false };
|
||||
track_uneven::amounts result { track_uneven::most, track_uneven::most, track_uneven::most };
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
auto const &segment { *SwitchExtension->Segments[ path ] };
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
if( glm::length( ( end == 0 ? segment.FastGetPoint_0() : segment.FastGetPoint_1() ) - Point ) < switch_end_reach ) {
|
||||
result = track_uneven::least( result, stray.ends[ path ][ end ] );
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found ? result : track_uneven::least( stray.paths[ 0 ], stray.paths[ 1 ] );
|
||||
}
|
||||
|
||||
double TTrack::joint_depth() const {
|
||||
@@ -1007,7 +1087,7 @@ void TTrack::init_segments( bool const Initial ) {
|
||||
++s_layoutstamp;
|
||||
if( eType == tt_Switch && SwitchExtension ) {
|
||||
SwitchExtension->Segments[ 0 ]->set_uneven( is_uneven() );
|
||||
SwitchExtension->Segments[ 1 ]->set_uneven( is_uneven() );
|
||||
SwitchExtension->Segments[ 1 ]->set_uneven( is_uneven(), 1 );
|
||||
}
|
||||
else if( Segment ) {
|
||||
Segment->set_uneven( is_uneven() );
|
||||
@@ -1742,6 +1822,7 @@ void TTrack::share_joints() {
|
||||
}
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> joint;
|
||||
auto roll { segment->design_roll( end ) };
|
||||
auto *neighbour { track_rails::path_neighbour( *this, path, end ) };
|
||||
if( neighbour != nullptr && neighbour != this && ( neighbour->iCategoryFlag & 15 ) == ( iCategoryFlag & 15 ) ) {
|
||||
glm::dvec3 point;
|
||||
@@ -1766,10 +1847,35 @@ void TTrack::share_joints() {
|
||||
}
|
||||
closest = gap;
|
||||
joint.emplace( 0.5 * ( point + theirpoint ), glm::normalize( across + theiracross ) );
|
||||
if( iCategoryFlag & 1 ) {
|
||||
// the cant of a plain track is what was designed, a switch takes it; alike ones meet halfway
|
||||
auto const own { segment->design_roll( end ) };
|
||||
auto const their { theirend == end ? -theirs->design_roll( theirend ) : theirs->design_roll( theirend ) };
|
||||
roll = (
|
||||
( eType == tt_Switch ) == ( neighbour->eType == tt_Switch ) ? 0.5f * ( own + their ) :
|
||||
eType == tt_Switch ? their :
|
||||
own );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
segment->set_joint( end, joint );
|
||||
segment->set_joint( end, joint, roll );
|
||||
}
|
||||
}
|
||||
if( eType != tt_Switch && Segment && ( iCategoryFlag & 1 ) ) {
|
||||
float roll1, roll2;
|
||||
Segment->GetRolls( roll1, roll2 );
|
||||
if( roll1 != 0.f || roll2 != 0.f ) {
|
||||
iTrapezoid |= 1;
|
||||
}
|
||||
}
|
||||
if( eType == tt_Switch && SwitchExtension ) {
|
||||
// the profiles of the switch are made at the mean of the rolls of its paths as they meet the tracks joined, and turned from it
|
||||
// along each path (init_segments() bakes the mean of the rolls as designed)
|
||||
float mean1, mean2;
|
||||
profile_rolls( mean1, mean2 );
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
SwitchExtension->Segments[ path ]->set_baked_roll( mean1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3030,21 +3136,7 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
&& false == m_profile1.first.empty() ) {
|
||||
Output << "railprofile " << m_profile1.first << ' ';
|
||||
}
|
||||
if( m_uneven > 0.f ) {
|
||||
Output << "uneven " << m_uneven << ' ';
|
||||
}
|
||||
if( m_unevenup >= 0.f ) {
|
||||
Output << "unevenup " << m_unevenup << ' ';
|
||||
}
|
||||
if( m_unevenside >= 0.f ) {
|
||||
Output << "unevenside " << m_unevenside << ' ';
|
||||
}
|
||||
if( m_unevencross >= 0.f ) {
|
||||
Output << "unevencross " << m_unevencross << ' ';
|
||||
}
|
||||
if( m_jointdip >= 0.f ) {
|
||||
Output << "jointdip " << m_jointdip << ' ';
|
||||
}
|
||||
Output << uneven_text();
|
||||
if( false == m_friction.first.empty() ) {
|
||||
Output << "friction " << m_friction.first << ' ';
|
||||
}
|
||||
@@ -4314,6 +4406,11 @@ path_table::InitTracks() {
|
||||
isolated = isolated->Next();
|
||||
}
|
||||
|
||||
// the physics goes by the cant at the joints too, and comes before any geometry is made
|
||||
for( auto *track : m_items ) {
|
||||
track->share_joints();
|
||||
}
|
||||
|
||||
TTrack::fetch_default_profiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +292,10 @@ public:
|
||||
float m_unevenup { -1.f };
|
||||
float m_unevenside { -1.f };
|
||||
float m_unevencross { -1.f };
|
||||
// the diverging path of a switch, mm; negative: as the straight one
|
||||
float m_unevenbranch { -1.f };
|
||||
float m_unevenbranchup { -1.f };
|
||||
float m_unevenbranchside { -1.f };
|
||||
float m_jointdip { -1.f }; // depth of the dip at rail joints, mm; negative: from m_uneven; plain tracks only
|
||||
private:
|
||||
double fVelocity = -1.0; // ograniczenie prędkości // prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia)
|
||||
@@ -413,11 +417,19 @@ public:
|
||||
void VelocitySet(float v);
|
||||
double VelocityGet();
|
||||
float Friction() const;
|
||||
// the unevenness the track declares
|
||||
track_uneven::amounts uneven_declared() const;
|
||||
// the attribute of the entry. A plain track: the value;up and down;sideways;cross level;dip at the joints.
|
||||
// A switch: path p1-p2;path p3-p4;up and down of the first;sideways of the first;up and down of the second;sideways of the second
|
||||
void read_uneven( std::string const &Text );
|
||||
std::string uneven_text() const;
|
||||
// the unevenness the track declares, on a path of a switch
|
||||
track_uneven::amounts uneven_declared( int const Path = 0 ) const;
|
||||
bool is_uneven() const;
|
||||
// the unevenness at a distance along the track, meeting the tracks joined at its ends
|
||||
track_uneven::amounts uneven_at( double const Distance ) const;
|
||||
// the unevenness at a distance along a path, meeting the tracks joined at its ends
|
||||
track_uneven::amounts uneven_at( double const Distance, int const Path = 0 ) const;
|
||||
// how much of the displacement a point of the profile at the depth takes
|
||||
double uneven_bed_share( double const Depth ) const;
|
||||
// closes the gaps and steps of cant between the ends of joined paths
|
||||
void share_joints();
|
||||
double joint_depth() const; // mm
|
||||
double joint_dip( double const Distance ) const; // m
|
||||
// distance from the rail joint behind; negative: the track has no joints that dip
|
||||
@@ -453,7 +465,6 @@ private:
|
||||
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 );
|
||||
// rail joints run on across joined tracks, however the line is cut into them, so the clatter keeps its rhythm
|
||||
struct rail_run {
|
||||
@@ -463,13 +474,17 @@ private:
|
||||
};
|
||||
void settle_rail_run() const;
|
||||
mutable rail_run m_railrun;
|
||||
// one value along all paths of a switch: the lowest of the switches joined, 0 next to a track with none
|
||||
track_uneven::amounts switch_uneven() const;
|
||||
// the value along each path of a switch: the lowest of that path in the switches joined, 0 next to a track with none.
|
||||
// And at the ends of the paths, by what meets there: the other path at the common end, the path of a switch joined
|
||||
struct switch_stray {
|
||||
track_uneven::amounts value;
|
||||
std::array<track_uneven::amounts, 2> paths;
|
||||
std::array<std::array<track_uneven::amounts, 2>, 2> ends;
|
||||
int stamp { -1 };
|
||||
};
|
||||
mutable switch_stray m_switchstray;
|
||||
switch_stray const &switch_uneven() const;
|
||||
// the value of a switch where a track joined to it meets it
|
||||
track_uneven::amounts switch_uneven_at( glm::dvec3 const &Point ) const;
|
||||
static int s_layoutstamp; // bumped when tracks are joined or changed, invalidates the two above
|
||||
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 );
|
||||
|
||||
@@ -11,7 +11,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
@@ -34,6 +37,11 @@ struct amounts {
|
||||
double cross { 0.0 };
|
||||
};
|
||||
|
||||
inline amounts least( amounts const &Left, amounts const &Right ) {
|
||||
|
||||
return { std::min( Left.up, Right.up ), std::min( Left.side, Right.side ), std::min( Left.cross, Right.cross ) };
|
||||
}
|
||||
|
||||
struct wave {
|
||||
double x;
|
||||
double z;
|
||||
@@ -41,6 +49,44 @@ struct wave {
|
||||
double share;
|
||||
};
|
||||
|
||||
// the numbers of an entry like "uneven 14;35", negative where left out
|
||||
template <std::size_t Count>
|
||||
std::array<float, Count> read_fields( std::string const &Text ) {
|
||||
|
||||
std::array<float, Count> result;
|
||||
result.fill( -1.f );
|
||||
std::size_t start { 0 };
|
||||
for( std::size_t index = 0; index < Count && start < Text.size(); ++index ) {
|
||||
auto const end { std::min( Text.find( ';', start ), Text.size() ) };
|
||||
auto value { 0.f };
|
||||
if( end > start && std::from_chars( Text.data() + start, Text.data() + end, value ).ec == std::errc {} ) {
|
||||
result[ index ] = std::clamp( value, 0.f, most );
|
||||
}
|
||||
start = end + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// and back, with the ones left out at the end dropped
|
||||
template <std::size_t Count>
|
||||
std::string write_fields( std::array<float, Count> const &Fields ) {
|
||||
|
||||
auto count { Count };
|
||||
while( count > 1 && Fields[ count - 1 ] < 0.f ) {
|
||||
--count;
|
||||
}
|
||||
std::ostringstream text;
|
||||
for( std::size_t index = 0; index < count; ++index ) {
|
||||
if( index > 0 ) {
|
||||
text << ';';
|
||||
}
|
||||
if( Fields[ index ] >= 0.f ) {
|
||||
text << Fields[ index ];
|
||||
}
|
||||
}
|
||||
return text.str();
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
using wave_set = std::array<wave, Count>;
|
||||
|
||||
@@ -109,6 +155,13 @@ inline double along( double const Full, double const Atstart, double const Atend
|
||||
return ends + ( Full - ends ) * std::min( smooth( Distance / fade ), smooth( ( Length - Distance ) / fade ) );
|
||||
}
|
||||
|
||||
// how much of the displacement a point of the profile takes, by its depth under the rail top: all of it down to the foot of the rail,
|
||||
// none at the foot of the ballast, which stays on the ground as designed
|
||||
inline double bed_share( double const Depth, double const Rail, double const Height ) {
|
||||
|
||||
return Height > 0.0 ? std::clamp( 1.0 - ( Depth - Rail ) / Height, 0.0, 1.0 ) : 1.0;
|
||||
}
|
||||
|
||||
// distance from the joint behind the point
|
||||
inline double rail_phase( double const Along, double const Rail ) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user