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

fix(track): what Sonar reports on the unevenness

The blockers are in the EP brake of a vehicle, older than this work: its
arrays made with new[] are vectors now, which also removes the deletes.

- The caches of the unevenness of a track are no longer mutable: what fills
  them isn't const any more.
- TSegment gets back to RaPositionGet in one piece, with what the path has
  to do with the others in one struct.
- Less nesting in the group of switches and in the fields of the editor,
  nested conditionals written out, and the attribute is read from a
  string_view. A test no longer counts in floating point.

No change in behaviour.
This commit is contained in:
maj00r
2026-10-31 20:17:47 +01:00
parent 56d389e2df
commit 9364b03e1a
9 changed files with 223 additions and 207 deletions

View File

@@ -69,10 +69,8 @@ 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();
m_setting.designrolls = { fRoll1, fRoll2 };
m_setting.joints = {};
bCurve = bIsCurve;
if (Global.bRollFix)
{ // Ra: poprawianie przechyłki
@@ -122,7 +120,7 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
fStoop = std::atan2(Point2.y - Point1.y, fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
fStep = fNewStep;
if( m_uneven && pOwner->eType != tt_Switch ) {
if( m_setting.uneven && pOwner->eType != tt_Switch ) {
// dense enough for the waves; a switch keeps its division, the blades depend on it
fStep = std::min( fStep, 2.0 );
}
@@ -373,21 +371,6 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const
};
*/
void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
design_position( fDistance, position, rotation );
if( false == m_uneven ) {
return;
}
// 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, 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 ) );
position += track_uneven::across_only( stray( position, amount, fDistance ), across );
}
glm::dvec3 TSegment::stray( glm::dvec3 const &Point, track_uneven::amounts const &Amount, double const Distance ) const {
auto const field { track_uneven::field( Point ) };
glm::dvec3 result { field.x * Amount.side, field.y * Amount.up, field.z * Amount.side };
@@ -397,30 +380,25 @@ glm::dvec3 TSegment::stray( glm::dvec3 const &Point, track_uneven::amounts const
}
glm::dvec3 TSegment::uneven_bend( double const Distance ) const {
if( false == m_uneven ) {
if( false == m_setting.uneven ) {
return glm::dvec3 { 0.0 };
}
// over about a bogie
auto const reach { 1.5 };
auto const strayed = [&]( double const At ) {
return stray( point_extended( At ), pOwner->uneven_at( At, m_path ), At ); };
auto const strayed = [ this ]( double const At ) {
// past the ends of the path straight on: the polynomial would run off on a short curved one
auto const on { std::clamp( At, 0.0, fLength ) };
auto const t { FastGetTFromS( on ) };
auto point { FastGetPoint( t ) };
if( auto const direction { FastGetDirection( t, 0.1 / fLength ) }; on != At && glm::length( direction ) > 0.0 ) {
point += direction * ( ( At - on ) / glm::length( direction ) );
}
return stray( point, pOwner->uneven_at( At, m_setting.path ), At ); };
return ( strayed( Distance + reach ) - 2.0 * strayed( Distance ) + strayed( Distance - reach ) ) / ( reach * reach );
}
glm::dvec3 TSegment::point_extended( double const Distance ) const {
auto const on { std::clamp( Distance, 0.0, fLength ) };
auto const t { FastGetTFromS( on ) };
auto const point { FastGetPoint( t ) };
if( on == Distance ) {
return point;
}
auto const direction { FastGetDirection( t, 0.1 / fLength ) };
auto const size { glm::length( direction ) };
return size > 0.0 ? point + direction * ( ( Distance - on ) / size ) : point;
}
void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origin, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const {
if( false == m_uneven ) {
if( false == m_setting.uneven ) {
return;
}
// the rails settling apart turn about the middle of the track, what's outside them follows the rail; the foot of the ballast stays
@@ -430,12 +408,12 @@ void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origi
if( share <= 0.0 ) {
return;
}
auto const amount { pOwner->uneven_at( Distance, m_path ) };
auto const amount { pOwner->uneven_at( Distance, m_setting.path ) };
Vertex.position.y -= static_cast<float>( share * track_uneven::stray_per_mm * amount.cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge );
Vertex.position += glm::vec3 { share * stray( Origin + glm::dvec3 { Vertex.position }, amount, Distance ) };
}
void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
if (bCurve) {
// można by wprowadzić uproszczony wzór dla okręgów płaskich
auto const t = FastGetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
@@ -458,6 +436,17 @@ void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm
rotation.y = static_cast<float>(fStoop); // pochylenie toru prostego
rotation.z = static_cast<float>(fDirection); // kierunek toru w planie
}
if( false == m_setting.uneven ) {
return;
}
// 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, m_setting.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 ) );
position += track_uneven::across_only( stray( position, amount, fDistance ), across );
};
void TSegment::plan_frame( double const Distance, glm::dvec3 &Point, glm::dvec3 &Across ) const {
@@ -523,9 +512,9 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
parallel1 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
}
parallel1 = glm::normalize( parallel1 );
if( iSkip == 0 && m_joints[ 0 ] ) {
pos1 = glm::vec3{ m_joints[ 0 ]->first - Origin };
parallel1 = glm::vec3{ m_joints[ 0 ]->second };
if( iSkip == 0 && m_setting.joints[ 0 ] ) {
pos1 = glm::vec3{ m_setting.joints[ 0 ]->first - Origin };
parallel1 = glm::vec3{ m_setting.joints[ 0 ]->second };
}
if( iEnd == 0 )
iEnd = iSegCount;
@@ -572,9 +561,9 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
parallel2 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
}
parallel2 = glm::normalize( parallel2 );
if( i == iSegCount && m_joints[ 1 ] ) {
pos2 = glm::vec3{ m_joints[ 1 ]->first - Origin };
parallel2 = glm::vec3{ m_joints[ 1 ]->second };
if( i == iSegCount && m_setting.joints[ 1 ] ) {
pos2 = glm::vec3{ m_setting.joints[ 1 ]->first - Origin };
parallel2 = glm::vec3{ m_setting.joints[ 1 ]->second };
}
// TODO: refactor the loop, there's no need to calculate starting points for each segment when we can copy the end points of the previous one

View File

@@ -9,7 +9,9 @@ http://mozilla.org/MPL/2.0/.
#pragma once
#include <array>
#include <optional>
#include <utility>
#include "utilities/Classes.h"
#include "rendering/geometrybank.h"
@@ -50,11 +52,14 @@ 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 ];
// how the path sits among the others
struct setting {
std::array<float, 2> designrolls { 0.f, 0.f }; // as entered; fRoll1 and fRoll2 can differ at a joint
bool uneven { false }; // see TrackUneven.h
int 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::array<std::optional<std::pair<glm::dvec3, glm::dvec3>>, 2> joints;
} m_setting;
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
@@ -79,9 +84,6 @@ class TSegment
void settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origin, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const;
// displacement of a point by the unevenness, at a distance along the path
glm::dvec3 stray( glm::dvec3 const &Point, track_uneven::amounts const &Amount, double const Distance ) const;
// a point of the path at a distance, past its ends straight on: the polynomial would run off on a short curved path
glm::dvec3 point_extended( double const Distance ) const;
void design_position( double const fDistance, glm::dvec3 &position, glm::vec3 &rotation ) const;
public:
bool bCurve = false;
@@ -125,20 +127,17 @@ public:
// call before Init, it sets the density of the geometry
void
set_uneven( bool const Uneven, int const Path = 0 ) {
m_uneven = Uneven;
m_path = Path; }
glm::dvec3
end_point( int const End ) const {
return End == 0 ? Point1 : Point2; }
m_setting.uneven = Uneven;
m_setting.path = Path; }
// a point of the path and the unit vector across it in the plan
void
plan_frame( double const Distance, glm::dvec3 &Point, glm::dvec3 &Across ) const;
float
design_roll( int const End ) const {
return m_designrolls[ End ]; }
return m_setting.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;
m_setting.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

View File

@@ -349,15 +349,15 @@ public:
track_uneven::amounts uneven_declared( int const Path = 0 ) const;
bool is_uneven() 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;
track_uneven::amounts uneven_at( double const Distance, int const Path = 0 );
// 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
double joint_dip( double const Distance ); // m
// distance from the rail joint behind; negative: the track has no joints that dip
double rail_phase( double const Distance ) const;
double rail_phase( double const Distance );
void ConnectionsLog();
bool DoubleSlip() const;
static void fetch_default_profiles();
@@ -395,8 +395,8 @@ private:
double way { 1.0 }; // direction of the path along the run
int stamp { -1 };
};
void settle_rail_run() const;
mutable rail_run m_railrun;
void settle_rail_run();
rail_run m_railrun;
// 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 {
@@ -404,15 +404,16 @@ private:
std::array<std::array<track_uneven::amounts, 2>, 2> ends;
int stamp { -1 };
};
mutable switch_stray m_switchstray;
switch_stray const &switch_uneven() const;
void settle_switch_stray() const;
switch_stray m_switchstray;
switch_stray const &switch_uneven();
void settle_switch_stray();
void settle_switch_ends();
// the lowest value of the paths ending at the point
track_uneven::amounts switch_paths_at( glm::dvec3 const &Point ) const;
// what a plain track comes to at its end, where it meets the other one
track_uneven::amounts uneven_met( TTrack const *Other, glm::dvec3 const &Point ) const;
track_uneven::amounts uneven_met( TTrack *Other, glm::dvec3 const &Point );
// the value of a switch where a track joined to it meets it
track_uneven::amounts switch_uneven_at( glm::dvec3 const &Point ) const;
track_uneven::amounts switch_uneven_at( glm::dvec3 const &Point );
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 );

View File

@@ -24,42 +24,55 @@ bool is_switch( TTrack const *Track ) {
return Track != nullptr && Track->eType == tt_Switch && Track->SwitchExtension;
}
std::array<TTrack const *, 4> joined_to_switch( TTrack const &Switch ) {
glm::dvec3 end_point( TSegment const &Segment, int const End ) {
return End == 0 ? Segment.FastGetPoint_0() : Segment.FastGetPoint_1();
}
std::array<TTrack *, 4> joined_to_switch( TTrack const &Switch ) {
auto const &extension { *Switch.SwitchExtension };
return { extension.pPrevs[ 0 ], extension.pPrevs[ 1 ], extension.pNexts[ 0 ], extension.pNexts[ 1 ] };
}
// the switch and the switches joined directly to it, and to those
std::vector<TTrack const *> switch_group( TTrack const &Switch ) {
std::vector<TTrack *> switch_group( TTrack &Switch ) {
std::vector<TTrack const *> group { &Switch };
for( std::size_t index = 0; index < group.size(); ++index ) {
for( auto const *other : joined_to_switch( *group[ index ] ) ) {
if( is_switch( other ) && std::find( group.begin(), group.end(), other ) == group.end() ) {
std::vector group { &Switch };
std::vector pending { &Switch };
while( false == pending.empty() ) {
auto const *track { pending.back() };
pending.pop_back();
for( auto *other : joined_to_switch( *track ) ) {
if( is_switch( other ) && std::ranges::find( group, other ) == group.end() ) {
group.push_back( other );
pending.push_back( other );
}
}
}
return group;
}
// a plain track with none of a component keeps the switch to its design in it, any other comes to the value of the switch
void keep_to_plain_track( std::array<track_uneven::amounts, 2> &Values, TTrack const &Plain ) {
auto const theirs { Plain.uneven_declared() };
for( auto &path : Values ) {
if( theirs.up <= 0.0 ) { path.up = 0.0; }
if( theirs.side <= 0.0 ) { path.side = 0.0; }
}
}
// the value along each path: the lowest of that path in the group, 0 in a component that a plain track joined has none of
std::array<track_uneven::amounts, 2> group_path_values( std::vector<TTrack const *> const &Group ) {
std::array<track_uneven::amounts, 2> group_path_values( std::vector<TTrack *> const &Group ) {
std::array<track_uneven::amounts, 2> values { Group.front()->uneven_declared( 0 ), Group.front()->uneven_declared( 1 ) };
for( auto const *track : Group ) {
values[ 0 ] = track_uneven::least( values[ 0 ], track->uneven_declared( 0 ) );
values[ 1 ] = track_uneven::least( values[ 1 ], track->uneven_declared( 1 ) );
for( auto const *other : joined_to_switch( *track ) ) {
if( other == nullptr || is_switch( other ) ) {
continue;
}
// any other comes to the value of the switch
auto const theirs { other->uneven_declared() };
for( auto &path : values ) {
if( theirs.up <= 0.0 ) { path.up = 0.0; }
if( theirs.side <= 0.0 ) { path.side = 0.0; }
if( other != nullptr && false == is_switch( other ) ) {
keep_to_plain_track( values, *other );
}
}
}
@@ -74,7 +87,7 @@ track_uneven::amounts least_at_ends( TTrack const &Switch, glm::dvec3 const &Poi
track_uneven::amounts result { track_uneven::most, track_uneven::most, track_uneven::most };
for( int path = 0; path < 2; ++path ) {
for( int end = 0; end < 2; ++end ) {
if( glm::length( Switch.path_segment( path )->end_point( end ) - Point ) < switch_end_reach ) {
if( glm::length( end_point( *Switch.path_segment( path ), end ) - Point ) < switch_end_reach ) {
result = track_uneven::least( result, Value( path, end ) );
found = true;
}
@@ -165,16 +178,16 @@ 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 {
track_uneven::amounts TTrack::uneven_at( double const Distance, int const Path ) {
if( eType == tt_Switch ) {
auto const &stray { switch_uneven() };
return track_uneven::along( stray.paths[ Path ], stray.ends[ Path ][ 0 ], stray.ends[ Path ][ 1 ], Distance, path_segment( Path )->GetLength() );
}
return track_uneven::along( uneven_declared(), uneven_met( trPrev, Segment->end_point( 0 ) ), uneven_met( trNext, Segment->end_point( 1 ) ), Distance, Length() );
return track_uneven::along( uneven_declared(), uneven_met( trPrev, end_point( *Segment, 0 ) ), uneven_met( trNext, end_point( *Segment, 1 ) ), Distance, Length() );
}
track_uneven::amounts TTrack::uneven_met( TTrack const *Other, glm::dvec3 const &Point ) const {
track_uneven::amounts TTrack::uneven_met( TTrack *Other, glm::dvec3 const &Point ) {
if( Other == nullptr ) {
return {};
@@ -182,7 +195,7 @@ track_uneven::amounts TTrack::uneven_met( TTrack const *Other, glm::dvec3 const
return Other->eType == tt_Switch ? Other->switch_uneven_at( Point ) : track_uneven::least( uneven_declared(), Other->uneven_declared() );
}
TTrack::switch_stray const &TTrack::switch_uneven() const {
TTrack::switch_stray const &TTrack::switch_uneven() {
if( m_switchstray.stamp != s_layoutstamp ) {
settle_switch_stray();
@@ -190,26 +203,30 @@ TTrack::switch_stray const &TTrack::switch_uneven() const {
return m_switchstray;
}
void TTrack::settle_switch_stray() const {
void TTrack::settle_switch_stray() {
auto const group { switch_group( *this ) };
auto const values { group_path_values( group ) };
for( auto const *track : group ) {
for( auto *track : group ) {
track->m_switchstray.paths = values;
track->m_switchstray.stamp = s_layoutstamp;
}
// at the ends of the paths, with the paths known in all of the group
for( auto const *track : group ) {
for( int path = 0; path < 2; ++path ) {
for( int end = 0; end < 2; ++end ) {
auto const point { track->path_segment( path )->end_point( end ) };
auto value { track->switch_paths_at( point ) };
auto const *other { track->path_neighbour( path, end ) };
if( is_switch( other ) ) {
value = track_uneven::least( value, other->switch_paths_at( point ) );
}
track->m_switchstray.ends[ path ][ end ] = value;
// with the paths known in all of the group
for( auto *track : group ) {
track->settle_switch_ends();
}
}
void TTrack::settle_switch_ends() {
for( int path = 0; path < 2; ++path ) {
for( int end = 0; end < 2; ++end ) {
auto const point { end_point( *path_segment( path ), end ) };
auto value { switch_paths_at( point ) };
if( auto const *other { path_neighbour( path, end ) }; is_switch( other ) ) {
value = track_uneven::least( value, other->switch_paths_at( point ) );
}
m_switchstray.ends[ path ][ end ] = value;
}
}
}
@@ -217,13 +234,13 @@ void TTrack::settle_switch_stray() const {
track_uneven::amounts TTrack::switch_paths_at( glm::dvec3 const &Point ) const {
auto const &paths { m_switchstray.paths };
return least_at_ends( *this, Point, track_uneven::least( paths[ 0 ], paths[ 1 ] ), [ & ]( int const Path, int ) { return paths[ Path ]; } );
return least_at_ends( *this, Point, track_uneven::least( paths[ 0 ], paths[ 1 ] ), [ &paths ]( int const Path, int ) { return paths[ Path ]; } );
}
track_uneven::amounts TTrack::switch_uneven_at( glm::dvec3 const &Point ) const {
track_uneven::amounts TTrack::switch_uneven_at( glm::dvec3 const &Point ) {
auto const &stray { switch_uneven() };
return least_at_ends( *this, Point, track_uneven::least( stray.paths[ 0 ], stray.paths[ 1 ] ), [ & ]( int const Path, int const End ) { return stray.ends[ Path ][ End ]; } );
return least_at_ends( *this, Point, track_uneven::least( stray.paths[ 0 ], stray.paths[ 1 ] ), [ &stray ]( int const Path, int const End ) { return stray.ends[ Path ][ End ]; } );
}
double TTrack::joint_depth() const {
@@ -234,7 +251,7 @@ double TTrack::joint_depth() const {
return ( m_uneven.dip >= 0.f ? m_uneven.dip : track_uneven::dip_share * uneven_declared().up );
}
double TTrack::joint_dip( double const Distance ) const {
double TTrack::joint_dip( double const Distance ) {
auto const phase { rail_phase( Distance ) };
if( phase < 0.0 ) {
@@ -245,12 +262,12 @@ double TTrack::joint_dip( double const Distance ) const {
return 0.0;
}
auto const depth { joint_depth() };
auto const atend = [&]( TTrack const *Other ) {
auto const atend = [ this, depth ]( 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 {
double TTrack::rail_phase( double const Distance ) {
if( joint_depth() <= 0.0 || fSoundDistance <= 2.0 * track_uneven::dip_reach ) {
return -1.0;
@@ -261,22 +278,22 @@ double TTrack::rail_phase( double const Distance ) const {
return track_uneven::rail_phase( m_railrun.origin + m_railrun.way * Distance, fSoundDistance );
}
void TTrack::settle_rail_run() const {
void TTrack::settle_rail_run() {
// 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 };
auto const onward = []( TTrack const &Track, int const End, int &Joined ) -> TTrack * {
auto *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 };
auto const walk = [ this, &onward ]( int &End ) {
auto *track { this };
int joined { 0 };
for( int step = 0; step < 1000000; ++step ) {
auto const *next { onward( *track, End, joined ) };
auto *next { onward( *track, End, joined ) };
if( next == nullptr || next == this ) {
break;
}
@@ -285,15 +302,14 @@ void TTrack::settle_rail_run() const {
}
return track; };
auto const place = []( TTrack const &Track, int const End ) {
auto const point { Track.Segment->end_point( End ) };
auto const point { end_point( *Track.Segment, End ) };
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 ) ) {
auto *track { walk( end ) };
if( auto *other { walk( otherend ) }; place( *other, otherend ) < place( *track, end ) ) {
track = other;
end = otherend;
}
@@ -327,7 +343,8 @@ void TTrack::share_joints() {
}
}
if( eType != tt_Switch && Segment && ( iCategoryFlag & 1 ) ) {
float roll1, roll2;
float roll1 { 0.f };
float roll2 { 0.f };
Segment->GetRolls( roll1, roll2 );
if( roll1 != 0.f || roll2 != 0.f ) {
iTrapezoid |= 1;

View File

@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
#include <cmath>
#include <sstream>
#include <string>
#include <string_view>
#include <glm/glm.hpp>
#include <glm/gtc/constants.hpp>
@@ -51,18 +52,20 @@ struct wave {
// 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> read_fields( std::string_view 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 );
auto rest { Text };
for( auto &field : result ) {
auto const end { std::min( rest.find( ';' ), rest.size() ) };
if( auto value { 0.f }; end > 0 && std::from_chars( rest.data(), rest.data() + end, value ).ec == std::errc {} ) {
field = std::clamp( value, 0.f, most );
}
start = end + 1;
if( end == rest.size() ) {
break;
}
rest.remove_prefix( end + 1 );
}
return result;
}
@@ -100,7 +103,7 @@ struct attribute {
};
// a plain track: value;up;side;cross;dip. A switch: p1-p2;p3-p4;up of p1-p2;side of p1-p2;up of p3-p4;side of p3-p4
inline attribute read_attribute( std::string const &Text, bool const Switch ) {
inline attribute read_attribute( std::string_view const Text, bool const Switch ) {
auto const fields { read_fields<6>( Text ) };
attribute result;
@@ -136,15 +139,15 @@ inline std::string write_attribute( attribute const &Values, bool const Switch )
// what a path comes to from the values: what's not given takes the first value, p3-p4 those of p1-p2. Cross level on plain tracks only
inline amounts declared( attribute const &Values, bool const Plain, int const Path ) {
auto const given = []( float const Part, double const Otherwise ) {
return Part >= 0.f ? static_cast<double>( Part ) : Otherwise; };
amounts result {
Values.up >= 0.f ? Values.up : Values.value,
Values.side >= 0.f ? Values.side : Values.value,
false == Plain ? 0.f : Values.cross >= 0.f ? Values.cross : Values.value };
given( Values.up, Values.value ),
given( Values.side, Values.value ),
Plain ? given( Values.cross, Values.value ) : 0.0 };
if( Path == 1 ) {
auto const branch = [ &Values ]( float const Part, double const Straight ) -> double {
return Part >= 0.f ? Part : Values.branch >= 0.f ? Values.branch : Straight; };
result.up = branch( Values.branchup, result.up );
result.side = branch( Values.branchside, result.side );
result.up = given( Values.branchup, given( Values.branch, result.up ) );
result.side = given( Values.branchside, given( Values.branch, result.side ) );
}
return result;
}
@@ -160,8 +163,9 @@ wave_set<Count> make_waves( double const Turn, std::array<double, Count> const &
wave_set<Count> result {};
for( std::size_t i = 0; i < Count; ++i ) {
auto const number { glm::two_pi<double>() / Lengths[ i ] };
auto const heading { Turn + golden * i };
result[ i ] = { number * std::cos( heading ), number * std::sin( heading ), golden * ( i + 1 ) * ( 1.0 + 3.0 * Turn ), Shares[ i ] };
auto const place { static_cast<double>( i ) };
auto const heading { Turn + golden * place };
result[ i ] = { number * std::cos( heading ), number * std::sin( heading ), golden * ( place + 1.0 ) * ( 1.0 + 3.0 * Turn ), Shares[ i ] };
}
return result;
}
@@ -246,7 +250,10 @@ inline glm::dvec3 across_of( glm::dvec3 const &Direction, glm::dvec3 const &Chor
// the cant where two paths meet, theirs turned to the way of this one: a switch takes that of a plain track, alike ones meet halfway
inline float joint_roll( float const Own, float const Their, bool const Switch, bool const Theirswitch ) {
return Switch == Theirswitch ? 0.5f * ( Own + Their ) : Switch ? Their : Own;
if( Switch == Theirswitch ) {
return 0.5f * ( Own + Their );
}
return Switch ? Their : Own;
}
// each component the same way