mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-02 06:59:13 +01:00
refactor(track): what goes with unevenness in one place, readable
The rules stay in TrackUneven.h with no dependence on the engine, as they can be tested. Their use on the tracks moves out of Track.cpp to TrackUneven.cpp, split into steps: the group of switches, the values of its paths, the meeting of two ends. One set of helpers for the paths of a track takes the place of the same conditions written out in several places, and the value at the ends of a switch is worked out in one place. The clatter of an axle leaves the long Update of a vehicle. The fields in the editor say themselves when they show. No change in behaviour.
This commit is contained in:
272
world/Track.cpp
272
world/Track.cpp
@@ -49,9 +49,6 @@ 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
|
||||
@@ -706,214 +703,6 @@ 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( int const Path ) const {
|
||||
|
||||
return track_uneven::declared( m_uneven, eType == tt_Normal, Path );
|
||||
}
|
||||
|
||||
bool TTrack::is_uneven() const {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 ) {
|
||||
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, glm::dvec3 const &Point ) -> track_uneven::amounts {
|
||||
if( Other == nullptr ) {
|
||||
return {};
|
||||
}
|
||||
if( Other->eType == tt_Switch ) {
|
||||
return Other->switch_uneven_at( Point );
|
||||
}
|
||||
return track_uneven::least( own, Other->uneven_declared() ); };
|
||||
return along( own, atend( trPrev, Segment->FastGetPoint_0() ), atend( trNext, Segment->FastGetPoint_1() ), Length() );
|
||||
}
|
||||
|
||||
TTrack::switch_stray const &TTrack::switch_uneven() const {
|
||||
|
||||
if( m_switchstray.stamp == s_layoutstamp ) {
|
||||
return m_switchstray;
|
||||
}
|
||||
std::vector<TTrack const *> group { this };
|
||||
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;
|
||||
}
|
||||
if( other->eType == tt_Switch && other->SwitchExtension ) {
|
||||
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
|
||||
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.paths = least;
|
||||
track->m_switchstray.stamp = s_layoutstamp;
|
||||
}
|
||||
// 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 {
|
||||
|
||||
if( eType != tt_Normal ) {
|
||||
return 0.0;
|
||||
}
|
||||
return ( m_uneven.dip >= 0.f ? m_uneven.dip : track_uneven::dip_share * uneven_declared().up );
|
||||
}
|
||||
|
||||
double TTrack::joint_dip( double const Distance ) const {
|
||||
|
||||
auto const phase { rail_phase( Distance ) };
|
||||
if( phase < 0.0 ) {
|
||||
return 0.0;
|
||||
}
|
||||
auto const fromjoint { std::min( phase, fSoundDistance - phase ) };
|
||||
if( fromjoint >= track_uneven::dip_reach ) {
|
||||
return 0.0;
|
||||
}
|
||||
auto const depth { joint_depth() };
|
||||
auto const atend = [&]( TTrack const *Other ) {
|
||||
return ( Other == nullptr || Other->fSoundDistance != fSoundDistance ? 0.0 : std::min( depth, Other->joint_depth() ) ); };
|
||||
return 0.001 * track_uneven::dip( fromjoint ) * track_uneven::along( depth, atend( trPrev ), atend( trNext ), Distance, Length() );
|
||||
}
|
||||
|
||||
double TTrack::rail_phase( double const Distance ) const {
|
||||
|
||||
if( joint_depth() <= 0.0 || fSoundDistance <= 2.0 * track_uneven::dip_reach ) {
|
||||
return -1.0;
|
||||
}
|
||||
if( m_railrun.stamp != s_layoutstamp ) {
|
||||
settle_rail_run();
|
||||
}
|
||||
return track_uneven::rail_phase( m_railrun.origin + m_railrun.way * Distance, fSoundDistance );
|
||||
}
|
||||
|
||||
void TTrack::settle_rail_run() const {
|
||||
|
||||
// the next track of the run past an end of a track, and which of its ends is joined there
|
||||
auto const onward = []( TTrack const &Track, int const End, int &Joined ) -> TTrack const * {
|
||||
auto const *other { End == 0 ? Track.trPrev : Track.trNext };
|
||||
if( other == nullptr || other == &Track || other->joint_depth() <= 0.0 || other->fSoundDistance != Track.fSoundDistance ) {
|
||||
return nullptr;
|
||||
}
|
||||
Joined = ( End == 0 ? Track.iPrevDirection : Track.iNextDirection ) & 1;
|
||||
return other; };
|
||||
// walks from this track to an end of the run
|
||||
auto const walk = [&]( int &End ) {
|
||||
auto const *track { this };
|
||||
int joined { 0 };
|
||||
for( int step = 0; step < 1000000; ++step ) {
|
||||
auto const *next { onward( *track, End, joined ) };
|
||||
if( next == nullptr || next == this ) {
|
||||
break;
|
||||
}
|
||||
track = next;
|
||||
End = 1 - joined;
|
||||
}
|
||||
return track; };
|
||||
auto const place = []( TTrack const &Track, int const End ) {
|
||||
auto const point { End == 0 ? Track.Segment->FastGetPoint_0() : Track.Segment->FastGetPoint_1() };
|
||||
return std::make_pair( point.x, point.z ); };
|
||||
|
||||
// start at the end with the lesser coordinates, to get the same joints from any track of the run
|
||||
int end { 0 };
|
||||
int otherend { 1 };
|
||||
auto const *track { walk( end ) };
|
||||
auto const *other { walk( otherend ) };
|
||||
if( place( *other, otherend ) < place( *track, end ) ) {
|
||||
track = other;
|
||||
end = otherend;
|
||||
}
|
||||
auto along { 0.0 };
|
||||
while( track != nullptr && track->m_railrun.stamp != s_layoutstamp ) {
|
||||
auto const length { track->Length() };
|
||||
track->m_railrun = { end == 0 ? along : along + length, end == 0 ? 1.0 : -1.0, s_layoutstamp };
|
||||
along += length;
|
||||
int joined { 0 };
|
||||
track = onward( *track, 1 - end, joined );
|
||||
end = joined;
|
||||
}
|
||||
// tracks joined one way only can leave this one out of the run: it stands on its own then, not to walk all of it again on every call
|
||||
if( m_railrun.stamp != s_layoutstamp ) {
|
||||
m_railrun = { 0.0, 1.0, s_layoutstamp };
|
||||
}
|
||||
}
|
||||
|
||||
void TTrack::update_location() {
|
||||
|
||||
location( (
|
||||
@@ -1600,67 +1389,6 @@ void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
create_geometry( Bank );
|
||||
}
|
||||
|
||||
void TTrack::share_joints() {
|
||||
|
||||
int const paths { eType == tt_Switch ? 2 : 1 };
|
||||
auto const segment_of = []( TTrack const &Track, int const Path ) -> TSegment * {
|
||||
return ( Track.eType == tt_Switch ? Track.SwitchExtension->Segments[ Path ].get() : Track.Segment.get() ); };
|
||||
for( int path = 0; path < paths; ++path ) {
|
||||
auto *segment { segment_of( *this, path ) };
|
||||
if( segment == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> joint;
|
||||
auto roll { segment->design_roll( end ) };
|
||||
auto const *neighbour { eType == tt_Switch ?
|
||||
( end ? SwitchExtension->pNexts[ path ] : SwitchExtension->pPrevs[ path ] ) :
|
||||
( end ? trNext : trPrev ) };
|
||||
if( neighbour != nullptr && neighbour != this && ( neighbour->iCategoryFlag & 15 ) == ( iCategoryFlag & 15 ) ) {
|
||||
glm::dvec3 point;
|
||||
glm::dvec3 across;
|
||||
segment->plan_frame( end ? segment->GetLength() : 0.0, point, across );
|
||||
auto closest { 0.2 };
|
||||
for( int theirpath = 0; theirpath < ( neighbour->eType == tt_Switch ? 2 : 1 ); ++theirpath ) {
|
||||
auto const *theirs { segment_of( *neighbour, theirpath ) };
|
||||
if( theirs == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
for( int theirend = 0; theirend < 2; ++theirend ) {
|
||||
glm::dvec3 theirpoint;
|
||||
glm::dvec3 theiracross;
|
||||
theirs->plan_frame( theirend ? theirs->GetLength() : 0.0, theirpoint, theiracross );
|
||||
if( theirend == end ) {
|
||||
theiracross = -theiracross;
|
||||
}
|
||||
auto const gap { glm::length( theirpoint - point ) };
|
||||
if( gap >= closest || glm::dot( across, theiracross ) < 0.9 ) {
|
||||
continue;
|
||||
}
|
||||
closest = gap;
|
||||
joint.emplace( 0.5 * ( point + theirpoint ), glm::normalize( across + theiracross ) );
|
||||
if( iCategoryFlag & 1 ) {
|
||||
roll = track_uneven::joint_roll(
|
||||
segment->design_roll( end ),
|
||||
theirend == end ? -theirs->design_roll( theirend ) : theirs->design_roll( theirend ),
|
||||
eType == tt_Switch,
|
||||
neighbour->eType == tt_Switch );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
gfx::userdata_array empty_userdata;
|
||||
share_joints();
|
||||
|
||||
Reference in New Issue
Block a user