mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-06 09:18:36 +01:00
refactor(track): the crossings of the rails are found in steps, the tracks nearby, the meeting of two rails with its refined place and the crossing made of it, and the crossings of the neighbours mapped on this track, and the check rails are planned, merged, kept clear of blocks and cut in separate functions instead of two long functions; path_count and path_neighbour replace the repeated choice of the paths and the ends of a switch or a plain track
This commit is contained in:
@@ -161,36 +161,46 @@ void rail_offset( TTrack const &Track, int const Path, int const Side, glm::dvec
|
|||||||
Lateral = lateral( line, Side, Point, Distance );
|
Lateral = lateral( line, Side, Point, Distance );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int path_count( TTrack const &Track ) {
|
||||||
|
|
||||||
|
return ( Track.eType == tt_Switch ? 2 : 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TTrack *path_neighbour( TTrack const &Track, int const Path, int const End ) {
|
||||||
|
|
||||||
|
if( Track.eType == tt_Switch ) {
|
||||||
|
return ( End ? Track.SwitchExtension->pNexts[ Path ] : Track.SwitchExtension->pPrevs[ Path ] );
|
||||||
|
}
|
||||||
|
return ( End ? Track.trNext : Track.trPrev );
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace track_rails
|
} // namespace track_rails
|
||||||
|
|
||||||
std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joined ) {
|
namespace {
|
||||||
|
|
||||||
|
struct rail_run {
|
||||||
|
TTrack *track { nullptr };
|
||||||
|
int path { 0 };
|
||||||
|
int side { 0 };
|
||||||
|
gauge_line const *line { nullptr };
|
||||||
|
double from { 0.0 };
|
||||||
|
double length { 0.0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<TTrack *> nearby_rails( TTrack &Track ) {
|
||||||
|
|
||||||
std::vector<rail_crossing> result;
|
|
||||||
if( false == cut_rails( *this ) || simulation::Region == nullptr ) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
auto &memo { memo_of( *this ) };
|
|
||||||
if( Joined && memo.joined.has_value() ) {
|
|
||||||
return *memo.joined;
|
|
||||||
}
|
|
||||||
auto const extension { 10.0 };
|
|
||||||
auto const paths { eType == tt_Switch ? 2 : 1 };
|
|
||||||
if( memo.own.has_value() ) {
|
|
||||||
result = *memo.own;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto const sections { simulation::Region->sections( location(), static_cast<float>( radius() + 50.0 ) ) };
|
|
||||||
std::vector<TTrack *> others;
|
std::vector<TTrack *> others;
|
||||||
|
auto const sections { simulation::Region->sections( Track.location(), static_cast<float>( Track.radius() + 50.0 ) ) };
|
||||||
for( auto *section : sections ) {
|
for( auto *section : sections ) {
|
||||||
for( auto const &cell : section->m_cells ) {
|
for( auto const &cell : section->m_cells ) {
|
||||||
if( glm::length( cell.area().center - location() ) > cell.area().radius + radius() + 1.0 ) {
|
if( glm::length( cell.area().center - Track.location() ) > cell.area().radius + Track.radius() + 1.0 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for( auto *other : cell.m_directories.paths ) {
|
for( auto *other : cell.m_directories.paths ) {
|
||||||
if( other == nullptr || other == this || false == cut_rails( *other ) ) {
|
if( other == nullptr || other == &Track || false == cut_rails( *other ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( glm::length( other->location() - location() ) > other->radius() + radius() + 1.0 ) {
|
if( glm::length( other->location() - Track.location() ) > other->radius() + Track.radius() + 1.0 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( std::find( others.begin(), others.end(), other ) == others.end() ) {
|
if( std::find( others.begin(), others.end(), other ) == others.end() ) {
|
||||||
@@ -199,30 +209,77 @@ std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto const bend = [&]( gauge_line const &Line, double const At ) {
|
return others;
|
||||||
|
}
|
||||||
|
|
||||||
|
double line_bend( gauge_line const &Line, double const At ) {
|
||||||
|
|
||||||
glm::dvec3 point, before, after;
|
glm::dvec3 point, before, after;
|
||||||
Line.at( At - 1.0, point, before );
|
Line.at( At - 1.0, point, before );
|
||||||
Line.at( At + 1.0, point, after );
|
Line.at( At + 1.0, point, after );
|
||||||
return std::abs( cross( plan( before ), plan( after ) ) ); };
|
return std::abs( cross( plan( before ), plan( after ) ) );
|
||||||
auto const heading = []( glm::dvec2 const &Tangent ) {
|
}
|
||||||
|
|
||||||
|
double heading( glm::dvec2 const &Tangent ) {
|
||||||
|
|
||||||
auto const angle { std::atan2( Tangent.y, Tangent.x ) };
|
auto const angle { std::atan2( Tangent.y, Tangent.x ) };
|
||||||
return ( angle < 0.0 ? angle + M_PI : angle ); };
|
return ( angle < 0.0 ? angle + M_PI : angle );
|
||||||
auto const overlap = []( gauge_line const &A, gauge_line const &B ) {
|
}
|
||||||
return A.low.x <= B.high.x && B.low.x <= A.high.x && A.low.y <= B.high.y && B.low.y <= A.high.y; };
|
|
||||||
for( auto *other : others ) {
|
bool overlap( gauge_line const &A, gauge_line const &B ) {
|
||||||
auto const otherpaths { other->eType == tt_Switch ? 2 : 1 };
|
|
||||||
for( int otherpath = 0; otherpath < otherpaths; ++otherpath ) {
|
return A.low.x <= B.high.x && B.low.x <= A.high.x && A.low.y <= B.high.y && B.low.y <= A.high.y;
|
||||||
auto const &othersegment { path_segment( *other, otherpath ) };
|
}
|
||||||
auto const otherfrom { other->eType == tt_Switch ? blade_length( *other, otherpath ) : 0.0 };
|
|
||||||
auto const otherlength { othersegment.GetLength() };
|
bool same_place( rail_crossing const &Crossing, int const Path, int const Side, double const At ) {
|
||||||
for( int otherside = 0; otherside < 2; ++otherside ) {
|
|
||||||
auto const &theirs { rail_line( *other, otherpath, otherside, true ) };
|
return Crossing.path == Path && Crossing.side == Side && std::abs( Crossing.at - At ) < 0.05;
|
||||||
for( int path = 0; path < paths; ++path ) {
|
}
|
||||||
auto const length { path_segment( *this, path ).GetLength() };
|
|
||||||
for( int side = 0; side < 2; ++side ) {
|
void refine_meeting( gauge_line const &Ours, gauge_line const &Theirs, double &S, double &T ) {
|
||||||
auto const &line { rail_line( *this, path, side, false ) };
|
|
||||||
|
glm::dvec3 p, tp, q, tq;
|
||||||
|
for( int step = 0; step < 6; ++step ) {
|
||||||
|
Ours.at( S, p, tp );
|
||||||
|
Theirs.at( T, q, tq );
|
||||||
|
auto const d { cross( plan( tp ), plan( tq ) ) };
|
||||||
|
if( std::abs( d ) < 1e-9 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto const offset { plan( q ) - plan( p ) };
|
||||||
|
S += cross( offset, plan( tq ) ) / d;
|
||||||
|
T += cross( offset, plan( tp ) ) / d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rail_crossing make_crossing( rail_run const &Ours, rail_run const &Theirs, double const S, double const T, glm::dvec2 const &Tangent, glm::dvec2 const &Othertangent, double const Angle ) {
|
||||||
|
|
||||||
|
auto const normal { glm::normalize( plan( Ours.line->normal( S, Ours.side ) ) ) };
|
||||||
|
auto const othernormal { glm::normalize( plan( Theirs.line->normal( T, Theirs.side ) ) ) };
|
||||||
|
rail_crossing crossing;
|
||||||
|
crossing.track = Theirs.track;
|
||||||
|
crossing.path = Ours.path;
|
||||||
|
crossing.side = Ours.side;
|
||||||
|
crossing.at = S;
|
||||||
|
crossing.angle = Angle;
|
||||||
|
crossing.into = glm::dot( Tangent, othernormal );
|
||||||
|
crossing.facing = glm::dot( normal, othernormal );
|
||||||
|
auto const ourbend { line_bend( *Ours.line, S ) };
|
||||||
|
auto const theirbend { line_bend( *Theirs.line, T ) };
|
||||||
|
crossing.nose = ( std::abs( ourbend - theirbend ) > 1e-4 ? ourbend < theirbend : heading( Tangent ) < heading( Othertangent ) );
|
||||||
|
crossing.otherpath = Theirs.path;
|
||||||
|
crossing.otherside = Theirs.side;
|
||||||
|
crossing.otherat = T;
|
||||||
|
crossing.aligned = glm::dot( Tangent, Othertangent ) > 0.0;
|
||||||
|
return crossing;
|
||||||
|
}
|
||||||
|
|
||||||
|
void meet_rails( rail_run const &Ours, rail_run const &Theirs, std::vector<rail_crossing> &Result ) {
|
||||||
|
|
||||||
|
auto const &line { *Ours.line };
|
||||||
|
auto const &theirs { *Theirs.line };
|
||||||
if( false == overlap( line, theirs ) ) {
|
if( false == overlap( line, theirs ) ) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
for( std::size_t i = 1; i < line.points.size(); ++i ) {
|
for( std::size_t i = 1; i < line.points.size(); ++i ) {
|
||||||
auto const a0 { plan( line.points[ i - 1 ] ) };
|
auto const a0 { plan( line.points[ i - 1 ] ) };
|
||||||
@@ -249,29 +306,19 @@ std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joine
|
|||||||
}
|
}
|
||||||
auto s { glm::mix( line.distances[ i - 1 ], line.distances[ i ], u ) };
|
auto s { glm::mix( line.distances[ i - 1 ], line.distances[ i ], u ) };
|
||||||
auto t { glm::mix( theirs.distances[ j - 1 ], theirs.distances[ j ], v ) };
|
auto t { glm::mix( theirs.distances[ j - 1 ], theirs.distances[ j ], v ) };
|
||||||
|
refine_meeting( line, theirs, s, t );
|
||||||
glm::dvec3 p, tp, q, tq;
|
glm::dvec3 p, tp, q, tq;
|
||||||
for( int step = 0; step < 6; ++step ) {
|
|
||||||
line.at( s, p, tp );
|
|
||||||
theirs.at( t, q, tq );
|
|
||||||
auto const d { cross( plan( tp ), plan( tq ) ) };
|
|
||||||
if( std::abs( d ) < 1e-9 ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const offset { plan( q ) - plan( p ) };
|
|
||||||
s += cross( offset, plan( tq ) ) / d;
|
|
||||||
t += cross( offset, plan( tp ) ) / d;
|
|
||||||
}
|
|
||||||
line.at( s, p, tp );
|
line.at( s, p, tp );
|
||||||
theirs.at( t, q, tq );
|
theirs.at( t, q, tq );
|
||||||
if( glm::length( plan( p ) - plan( q ) ) > 0.01
|
if( glm::length( plan( p ) - plan( q ) ) > 0.01
|
||||||
|| s < 0.0 || s > length
|
|| s < 0.0 || s > Ours.length
|
||||||
|| t < otherfrom || t > otherlength ) {
|
|| t < Theirs.from || t > Theirs.length ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( std::abs( p.y - q.y ) > 0.5 ) {
|
if( std::abs( p.y - q.y ) > 0.5 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( ( s < 0.5 || s > length - 0.5 ) && ( t < 0.5 || t > otherlength - 0.5 ) && joined( *this, *other ) ) {
|
if( ( s < 0.5 || s > Ours.length - 0.5 ) && ( t < 0.5 || t > Theirs.length - 0.5 ) && joined( *Ours.track, *Theirs.track ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const tangent { glm::normalize( plan( tp ) ) };
|
auto const tangent { glm::normalize( plan( tp ) ) };
|
||||||
@@ -280,54 +327,53 @@ std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joine
|
|||||||
if( angle < 0.03 ) {
|
if( angle < 0.03 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const sidevalue { side ? 1 : -1 };
|
if( std::any_of( Result.begin(), Result.end(), [&]( rail_crossing const &Crossing ) { return same_place( Crossing, Ours.path, Ours.side, s ); } ) ) {
|
||||||
if( std::any_of( result.begin(), result.end(), [&]( rail_crossing const &Crossing ) {
|
|
||||||
return Crossing.path == path && Crossing.side == sidevalue && std::abs( Crossing.at - s ) < 0.05; } ) ) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const normal { glm::normalize( plan( line.normal( s, sidevalue ) ) ) };
|
Result.push_back( make_crossing( Ours, Theirs, s, t, tangent, othertangent, angle ) );
|
||||||
auto const othernormal { glm::normalize( plan( theirs.normal( t, otherside ? 1 : -1 ) ) ) };
|
}
|
||||||
rail_crossing crossing;
|
}
|
||||||
crossing.track = other;
|
}
|
||||||
crossing.path = path;
|
|
||||||
crossing.side = sidevalue;
|
std::vector<rail_crossing> own_crossings( TTrack &Track ) {
|
||||||
crossing.at = s;
|
|
||||||
crossing.angle = angle;
|
std::vector<rail_crossing> result;
|
||||||
crossing.into = glm::dot( tangent, othernormal );
|
for( auto *other : nearby_rails( Track ) ) {
|
||||||
crossing.facing = glm::dot( normal, othernormal );
|
for( int otherpath = 0; otherpath < path_count( *other ); ++otherpath ) {
|
||||||
auto const ourbend { bend( line, s ) };
|
rail_run theirs { other, otherpath };
|
||||||
auto const theirbend { bend( theirs, t ) };
|
theirs.from = ( other->eType == tt_Switch ? blade_length( *other, otherpath ) : 0.0 );
|
||||||
crossing.nose = ( std::abs( ourbend - theirbend ) > 1e-4 ? ourbend < theirbend : heading( tangent ) < heading( othertangent ) );
|
theirs.length = path_segment( *other, otherpath ).GetLength();
|
||||||
crossing.otherpath = otherpath;
|
for( int otherside = 0; otherside < 2; ++otherside ) {
|
||||||
crossing.otherside = ( otherside ? 1 : -1 );
|
theirs.side = ( otherside ? 1 : -1 );
|
||||||
crossing.otherat = t;
|
theirs.line = &rail_line( *other, otherpath, otherside, true );
|
||||||
crossing.aligned = glm::dot( tangent, othertangent ) > 0.0;
|
for( int path = 0; path < path_count( Track ); ++path ) {
|
||||||
result.push_back( crossing );
|
auto const length { path_segment( Track, path ).GetLength() };
|
||||||
|
for( int side = 0; side < 2; ++side ) {
|
||||||
|
meet_rails( { &Track, path, side ? 1 : -1, &rail_line( Track, path, side, false ), 0.0, length }, theirs, result );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
memo.own = result;
|
|
||||||
}
|
|
||||||
if( false == Joined ) {
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// crossings of the tracks going on from the ends, near enough for their check rails and wings to reach this one
|
|
||||||
auto const owncount { result.size() };
|
// crossings of the tracks going on from the ends, near enough for their check rails and wings to reach this one
|
||||||
for( int path = 0; path < paths; ++path ) {
|
void add_neighbour_crossings( TTrack &Track, std::vector<rail_crossing> &Result ) {
|
||||||
auto const &segment { path_segment( *this, path ) };
|
|
||||||
|
auto const extension { 10.0 };
|
||||||
|
auto const owncount { Result.size() };
|
||||||
|
for( int path = 0; path < path_count( Track ); ++path ) {
|
||||||
|
auto const &segment { path_segment( Track, path ) };
|
||||||
auto const length { segment.GetLength() };
|
auto const length { segment.GetLength() };
|
||||||
for( int end = 0; end < 2; ++end ) {
|
for( int end = 0; end < 2; ++end ) {
|
||||||
auto *neighbour { eType == tt_Switch ? ( end ? SwitchExtension->pNexts[ path ] : SwitchExtension->pPrevs[ path ] ) : ( end ? trNext : trPrev ) };
|
auto *neighbour { path_neighbour( Track, path, end ) };
|
||||||
if( neighbour == nullptr || neighbour == this || false == cut_rails( *neighbour ) ) {
|
if( neighbour == nullptr || neighbour == &Track || false == cut_rails( *neighbour ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const joint { end ? segment.FastGetPoint_1() : segment.FastGetPoint_0() };
|
auto const joint { end ? segment.FastGetPoint_1() : segment.FastGetPoint_0() };
|
||||||
auto const theirs { neighbour->rail_crossings( false ) };
|
auto const theirs { neighbour->rail_crossings( false ) };
|
||||||
for( int neighbourpath = 0; neighbourpath < ( neighbour->eType == tt_Switch ? 2 : 1 ); ++neighbourpath ) {
|
for( int neighbourpath = 0; neighbourpath < path_count( *neighbour ); ++neighbourpath ) {
|
||||||
auto const &neighboursegment { path_segment( *neighbour, neighbourpath ) };
|
auto const &neighboursegment { path_segment( *neighbour, neighbourpath ) };
|
||||||
auto const neighbourlength { neighboursegment.GetLength() };
|
auto const neighbourlength { neighboursegment.GetLength() };
|
||||||
auto const tostart { glm::length( neighboursegment.FastGetPoint_0() - joint ) };
|
auto const tostart { glm::length( neighboursegment.FastGetPoint_0() - joint ) };
|
||||||
@@ -338,7 +384,7 @@ std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joine
|
|||||||
auto const atstart { tostart <= toend };
|
auto const atstart { tostart <= toend };
|
||||||
auto const same { atstart == ( end == 1 ) };
|
auto const same { atstart == ( end == 1 ) };
|
||||||
for( auto const &crossing : theirs ) {
|
for( auto const &crossing : theirs ) {
|
||||||
if( crossing.path != neighbourpath || crossing.track == this ) {
|
if( crossing.path != neighbourpath || crossing.track == &Track ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const along { atstart ? crossing.at : neighbourlength - crossing.at };
|
auto const along { atstart ? crossing.at : neighbourlength - crossing.at };
|
||||||
@@ -354,21 +400,16 @@ std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joine
|
|||||||
mapped.into = -crossing.into;
|
mapped.into = -crossing.into;
|
||||||
mapped.aligned = !crossing.aligned;
|
mapped.aligned = !crossing.aligned;
|
||||||
}
|
}
|
||||||
if( std::none_of( result.begin(), result.begin() + owncount, [&]( rail_crossing const &Crossing ) {
|
if( std::none_of( Result.begin(), Result.begin() + owncount, [&]( rail_crossing const &Crossing ) { return same_place( Crossing, mapped.path, mapped.side, mapped.at ); } ) ) {
|
||||||
return Crossing.path == mapped.path && Crossing.side == mapped.side && std::abs( Crossing.at - mapped.at ) < 0.05; } ) ) {
|
Result.push_back( mapped );
|
||||||
result.push_back( mapped );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memo.joined = result;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
track_rails::check_rail_set TTrack::check_rails( std::vector<rail_crossing> const &Crossings ) {
|
struct planned_check {
|
||||||
|
|
||||||
struct planned {
|
|
||||||
double from { 0.0 };
|
double from { 0.0 };
|
||||||
double to { 0.0 };
|
double to { 0.0 };
|
||||||
bool flarefrom { true };
|
bool flarefrom { true };
|
||||||
@@ -377,23 +418,24 @@ track_rails::check_rail_set TTrack::check_rails( std::vector<rail_crossing> cons
|
|||||||
double flare { 0.02 };
|
double flare { 0.02 };
|
||||||
double frombend { 0.0 };
|
double frombend { 0.0 };
|
||||||
double tobend { 0.0 };
|
double tobend { 0.0 };
|
||||||
};
|
};
|
||||||
std::vector<planned> plans[ 2 ][ 2 ];
|
using planned_check_set = std::array<std::array<std::vector<planned_check>, 2>, 2>; // path, right side
|
||||||
check_rail_set result;
|
|
||||||
auto const size { rail_dimensions() };
|
void add_acute_check( std::vector<planned_check> &Checks, double const At, double const Toward, double const Slope, double const Flare ) {
|
||||||
if( size.grooved ) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
auto const acute = [&]( std::vector<planned> &Other, double const At, double const Toward, double const Slope, double const Flare ) {
|
|
||||||
auto const half { 0.5 * check_length( Slope ) };
|
auto const half { 0.5 * check_length( Slope ) };
|
||||||
Other.push_back( { At + Toward * 0.25 - half, At + Toward * 0.25 + half, true, true, 1.5, Flare } );
|
Checks.push_back( { At + Toward * 0.25 - half, At + Toward * 0.25 + half, true, true, 1.5, Flare } );
|
||||||
};
|
}
|
||||||
|
|
||||||
|
planned_check_set planned_checks( TTrack const &Track, std::vector<rail_crossing> const &Crossings ) {
|
||||||
|
|
||||||
|
planned_check_set plans;
|
||||||
for( auto const &crossing : Crossings ) {
|
for( auto const &crossing : Crossings ) {
|
||||||
if( crossing.angle > middle_angle || crossing.track->rail_dimensions().grooved ) {
|
if( crossing.angle > middle_angle || crossing.track->rail_dimensions().grooved ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( crossing.facing < 0.0 ) {
|
if( crossing.facing < 0.0 ) {
|
||||||
acute( plans[ crossing.path ][ crossing.side < 0 ], crossing.at, crossing.into > 0.0 ? 1.0 : -1.0, std::tan( crossing.angle ), 0.02 );
|
add_acute_check( plans[ crossing.path ][ crossing.side < 0 ], crossing.at, crossing.into > 0.0 ? 1.0 : -1.0, std::tan( crossing.angle ), 0.02 );
|
||||||
}
|
}
|
||||||
else if( crossing.into > 0.0 ) {
|
else if( crossing.into > 0.0 ) {
|
||||||
plans[ crossing.path ][ crossing.side > 0 ].push_back( { crossing.at, crossing.at + 1.2, false, true, 0.5, 0.02, -knuckle_bend( crossing.into ), 0.0 } );
|
plans[ crossing.path ][ crossing.side > 0 ].push_back( { crossing.at, crossing.at + 1.2, false, true, 0.5, 0.02, -knuckle_bend( crossing.into ), 0.0 } );
|
||||||
@@ -402,52 +444,70 @@ track_rails::check_rail_set TTrack::check_rails( std::vector<rail_crossing> cons
|
|||||||
plans[ crossing.path ][ crossing.side > 0 ].push_back( { crossing.at - 1.2, crossing.at, true, false, 0.5, 0.02, 0.0, knuckle_bend( crossing.into ) } );
|
plans[ crossing.path ][ crossing.side > 0 ].push_back( { crossing.at - 1.2, crossing.at, true, false, 0.5, 0.02, 0.0, knuckle_bend( crossing.into ) } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( eType == tt_Switch ) {
|
if( Track.eType == tt_Switch ) {
|
||||||
auto const frog { this->frog() };
|
auto const frog { Track.frog() };
|
||||||
if( frog.valid ) {
|
if( frog.valid ) {
|
||||||
for( int path = 0; path < 2; ++path ) {
|
for( int path = 0; path < 2; ++path ) {
|
||||||
acute( plans[ path ][ frog.side[ path ] < 0 ], frog.at[ path ], -1.0, std::tan( frog.angle ), 0.04 );
|
add_acute_check( plans[ path ][ frog.side[ path ] < 0 ], frog.at[ path ], -1.0, std::tan( frog.angle ), 0.04 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto const halfwidth { 0.5 * std::abs( fTrackWidth ) };
|
return plans;
|
||||||
auto const clearance { 0.046 + 0.04 * size.head / 0.0735 + size.head };
|
}
|
||||||
for( int path = 0; path < ( eType == tt_Switch ? 2 : 1 ); ++path ) {
|
|
||||||
auto const &segment { path_segment( *this, path ) };
|
void merge_checks( std::vector<planned_check> &Checks ) {
|
||||||
auto const length { segment.GetLength() };
|
|
||||||
for( int right = 0; right < 2; ++right ) {
|
std::sort( Checks.begin(), Checks.end(), []( planned_check const &A, planned_check const &B ) { return A.from < B.from; } );
|
||||||
auto const side { right ? 1 : -1 };
|
for( std::size_t i = 1; i < Checks.size(); ++i ) {
|
||||||
auto &checks { plans[ path ][ right ] };
|
if( Checks[ i ].from < Checks[ i - 1 ].to + 2.0 ) {
|
||||||
if( checks.empty() ) {
|
if( Checks[ i ].to > Checks[ i - 1 ].to ) {
|
||||||
|
Checks[ i - 1 ].to = Checks[ i ].to;
|
||||||
|
Checks[ i - 1 ].flareto = Checks[ i ].flareto;
|
||||||
|
Checks[ i - 1 ].tobend = Checks[ i ].tobend;
|
||||||
|
}
|
||||||
|
Checks[ i - 1 ].shortest = std::min( Checks[ i - 1 ].shortest, Checks[ i ].shortest );
|
||||||
|
Checks[ i - 1 ].flare = std::max( Checks[ i - 1 ].flare, Checks[ i ].flare );
|
||||||
|
Checks.erase( Checks.begin() + i-- );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blocked_by( std::vector<gauge_line> const &Others, glm::dvec2 const &Gauge, glm::dvec2 const &Inward, double const Clearance ) {
|
||||||
|
|
||||||
|
auto blocked { false };
|
||||||
|
for( auto const &other : Others ) {
|
||||||
|
for( std::size_t i = 1; i < other.points.size() && false == blocked; ++i ) {
|
||||||
|
auto const a { plan( other.points[ i - 1 ] ) };
|
||||||
|
auto const edge { plan( other.points[ i ] ) - a };
|
||||||
|
double t, u;
|
||||||
|
if( false == meet( Gauge, Inward, a, edge, 1e-9, t, u ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::sort( checks.begin(), checks.end(), []( planned const &A, planned const &B ) { return A.from < B.from; } );
|
blocked = ( u > -1e-6 && u < 1.0 + 1e-6 && t > -0.05 && t < Clearance );
|
||||||
for( std::size_t i = 1; i < checks.size(); ++i ) {
|
|
||||||
if( checks[ i ].from < checks[ i - 1 ].to + 2.0 ) {
|
|
||||||
if( checks[ i ].to > checks[ i - 1 ].to ) {
|
|
||||||
checks[ i - 1 ].to = checks[ i ].to;
|
|
||||||
checks[ i - 1 ].flareto = checks[ i ].flareto;
|
|
||||||
checks[ i - 1 ].tobend = checks[ i ].tobend;
|
|
||||||
}
|
|
||||||
checks[ i - 1 ].shortest = std::min( checks[ i - 1 ].shortest, checks[ i ].shortest );
|
|
||||||
checks[ i - 1 ].flare = std::max( checks[ i - 1 ].flare, checks[ i ].flare );
|
|
||||||
checks.erase( checks.begin() + i-- );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check rails keep clear of the blades and the rails of the other path of a switch running inside the rail, here and in a switch joined at an end, and of the blade tips
|
return blocked;
|
||||||
std::vector<glm::dvec2> blocks;
|
}
|
||||||
|
|
||||||
|
// check rails keep clear of the blades and the rails of the other path of a switch running inside the rail, here and in a switch joined at an end, and of the blade tips
|
||||||
|
knots::line check_blocks( TTrack const &Track, int const Path, int const Side, std::vector<planned_check> const &Checks, double const Clearance ) {
|
||||||
|
|
||||||
|
auto const halfwidth { 0.5 * std::abs( Track.fTrackWidth ) };
|
||||||
|
auto const &segment { path_segment( Track, Path ) };
|
||||||
|
auto const length { segment.GetLength() };
|
||||||
|
knots::line blocks;
|
||||||
auto const start { plan( segment.FastGetPoint_0() ) };
|
auto const start { plan( segment.FastGetPoint_0() ) };
|
||||||
auto const end { plan( segment.FastGetPoint_1() ) };
|
auto const end { plan( segment.FastGetPoint_1() ) };
|
||||||
std::vector<gauge_line> others;
|
std::vector<gauge_line> others;
|
||||||
auto const add_path = [&]( TSegment const &Other ) {
|
auto const add_path = [&]( TSegment const &Other ) {
|
||||||
others.push_back( make_gauge_line( Other, -halfwidth, 0.0 ) );
|
others.push_back( make_gauge_line( Other, -halfwidth, 0.0 ) );
|
||||||
others.push_back( make_gauge_line( Other, halfwidth, 0.0 ) ); };
|
others.push_back( make_gauge_line( Other, halfwidth, 0.0 ) ); };
|
||||||
if( eType == tt_Switch ) {
|
if( Track.eType == tt_Switch ) {
|
||||||
blocks.emplace_back( -1e9, 0.3 );
|
blocks.emplace_back( -1e9, 0.3 );
|
||||||
add_path( path_segment( *this, 1 - path ) );
|
add_path( path_segment( Track, 1 - Path ) );
|
||||||
}
|
}
|
||||||
for( auto const *neighbour : { trPrev, trNext } ) {
|
for( auto const *neighbour : { Track.trPrev, Track.trNext } ) {
|
||||||
if( neighbour == nullptr || neighbour == this || neighbour->eType != tt_Switch || neighbour->SwitchExtension == nullptr ) {
|
if( neighbour == nullptr || neighbour == &Track || neighbour->eType != tt_Switch || neighbour->SwitchExtension == nullptr ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto const tip { plan( neighbour->SwitchExtension->Segments[ 0 ]->FastGetPoint_0() ) };
|
auto const tip { plan( neighbour->SwitchExtension->Segments[ 0 ]->FastGetPoint_0() ) };
|
||||||
@@ -469,53 +529,87 @@ track_rails::check_rail_set TTrack::check_rails( std::vector<rail_crossing> cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( false == others.empty() ) {
|
if( false == others.empty() ) {
|
||||||
auto const ours { make_gauge_line( segment, side * halfwidth, 0.0 ) };
|
auto const ours { make_gauge_line( segment, Side * halfwidth, 0.0 ) };
|
||||||
for( auto const &check : checks ) {
|
for( auto const &check : Checks ) {
|
||||||
for( auto s { check.from }; s <= check.to; s += 0.1 ) {
|
for( auto s { check.from }; s <= check.to; s += 0.1 ) {
|
||||||
glm::dvec3 point, tangent;
|
glm::dvec3 point, tangent;
|
||||||
ours.at( s, point, tangent );
|
ours.at( s, point, tangent );
|
||||||
auto const gauge { plan( point ) };
|
if( blocked_by( others, plan( point ), plan( ours.normal( s, Side ) ), Clearance ) ) {
|
||||||
auto const inward { plan( ours.normal( s, side ) ) };
|
|
||||||
auto blocked { false };
|
|
||||||
for( auto const &other : others ) {
|
|
||||||
for( std::size_t i = 1; i < other.points.size() && false == blocked; ++i ) {
|
|
||||||
auto const a { plan( other.points[ i - 1 ] ) };
|
|
||||||
auto const edge { plan( other.points[ i ] ) - a };
|
|
||||||
double t, u;
|
|
||||||
if( false == meet( gauge, inward, a, edge, 1e-9, t, u ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
blocked = ( u > -1e-6 && u < 1.0 + 1e-6 && t > -0.05 && t < clearance );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( blocked ) {
|
|
||||||
blocks.emplace_back( s - 0.3, s + 0.3 );
|
blocks.emplace_back( s - 0.3, s + 0.3 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort( blocks.begin(), blocks.end(), []( glm::dvec2 const &A, glm::dvec2 const &B ) { return A.x < B.x; } );
|
knots::sort( blocks );
|
||||||
for( auto const &check : checks ) {
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cut_check( planned_check const &Check, knots::line const &Blocks, std::vector<check_rail> &Result ) {
|
||||||
|
|
||||||
auto const add = [&]( double const From, double const To ) {
|
auto const add = [&]( double const From, double const To ) {
|
||||||
result[ path ][ right ].push_back( {
|
Result.push_back( {
|
||||||
From, To,
|
From, To,
|
||||||
( From > check.from || check.flarefrom ) ? check.flare : 0.0,
|
( From > Check.from || Check.flarefrom ) ? Check.flare : 0.0,
|
||||||
( To < check.to || check.flareto ) ? check.flare : 0.0,
|
( To < Check.to || Check.flareto ) ? Check.flare : 0.0,
|
||||||
From > check.from ? 0.0 : check.frombend,
|
From > Check.from ? 0.0 : Check.frombend,
|
||||||
To < check.to ? 0.0 : check.tobend } ); };
|
To < Check.to ? 0.0 : Check.tobend } ); };
|
||||||
auto from { check.from };
|
auto from { Check.from };
|
||||||
for( auto const &block : blocks ) {
|
for( auto const &block : Blocks ) {
|
||||||
if( block.y <= from || block.x >= check.to ) {
|
if( block.y <= from || block.x >= Check.to ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if( block.x - from >= check.shortest ) {
|
if( block.x - from >= Check.shortest ) {
|
||||||
add( from, block.x );
|
add( from, block.x );
|
||||||
}
|
}
|
||||||
from = std::max( from, block.y );
|
from = std::max( from, block.y );
|
||||||
}
|
}
|
||||||
if( check.to - from >= check.shortest ) {
|
if( Check.to - from >= Check.shortest ) {
|
||||||
add( from, check.to );
|
add( from, Check.to );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::vector<track_rails::rail_crossing> TTrack::rail_crossings( bool const Joined ) {
|
||||||
|
|
||||||
|
if( false == cut_rails( *this ) || simulation::Region == nullptr ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto &memo { memo_of( *this ) };
|
||||||
|
if( Joined && memo.joined.has_value() ) {
|
||||||
|
return *memo.joined;
|
||||||
|
}
|
||||||
|
if( false == memo.own.has_value() ) {
|
||||||
|
memo.own = own_crossings( *this );
|
||||||
|
}
|
||||||
|
auto result { *memo.own };
|
||||||
|
if( false == Joined ) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
add_neighbour_crossings( *this, result );
|
||||||
|
memo.joined = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
track_rails::check_rail_set TTrack::check_rails( std::vector<rail_crossing> const &Crossings ) {
|
||||||
|
|
||||||
|
check_rail_set result;
|
||||||
|
auto const size { rail_dimensions() };
|
||||||
|
if( size.grooved ) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto plans { planned_checks( *this, Crossings ) };
|
||||||
|
auto const clearance { 0.046 + 0.04 * size.head / 0.0735 + size.head };
|
||||||
|
for( int path = 0; path < path_count( *this ); ++path ) {
|
||||||
|
for( int right = 0; right < 2; ++right ) {
|
||||||
|
auto &checks { plans[ path ][ right ] };
|
||||||
|
if( checks.empty() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
merge_checks( checks );
|
||||||
|
auto const blocks { check_blocks( *this, path, right ? 1 : -1, checks, clearance ) };
|
||||||
|
for( auto const &check : checks ) {
|
||||||
|
cut_check( check, blocks, result[ path ][ right ] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1381,20 +1381,20 @@ void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
|||||||
|
|
||||||
void TTrack::share_joints() {
|
void TTrack::share_joints() {
|
||||||
|
|
||||||
for( int path = 0; path < ( eType == tt_Switch ? 2 : 1 ); ++path ) {
|
for( int path = 0; path < track_rails::path_count( *this ); ++path ) {
|
||||||
auto *segment { eType == tt_Switch ? SwitchExtension->Segments[ path ].get() : Segment.get() };
|
auto *segment { eType == tt_Switch ? SwitchExtension->Segments[ path ].get() : Segment.get() };
|
||||||
if( segment == nullptr ) {
|
if( segment == nullptr ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for( int end = 0; end < 2; ++end ) {
|
for( int end = 0; end < 2; ++end ) {
|
||||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> joint;
|
std::optional<std::pair<glm::dvec3, glm::dvec3>> joint;
|
||||||
auto *neighbour { eType == tt_Switch ? ( end ? SwitchExtension->pNexts[ path ] : SwitchExtension->pPrevs[ path ] ) : ( end ? trNext : trPrev ) };
|
auto *neighbour { track_rails::path_neighbour( *this, path, end ) };
|
||||||
if( neighbour != nullptr && neighbour != this && ( neighbour->iCategoryFlag & 15 ) == ( iCategoryFlag & 15 ) ) {
|
if( neighbour != nullptr && neighbour != this && ( neighbour->iCategoryFlag & 15 ) == ( iCategoryFlag & 15 ) ) {
|
||||||
glm::dvec3 point;
|
glm::dvec3 point;
|
||||||
glm::dvec3 across;
|
glm::dvec3 across;
|
||||||
segment->plan_frame( end ? segment->GetLength() : 0.0, point, across );
|
segment->plan_frame( end ? segment->GetLength() : 0.0, point, across );
|
||||||
auto closest { 0.2 };
|
auto closest { 0.2 };
|
||||||
for( int theirpath = 0; theirpath < ( neighbour->eType == tt_Switch ? 2 : 1 ); ++theirpath ) {
|
for( int theirpath = 0; theirpath < track_rails::path_count( *neighbour ); ++theirpath ) {
|
||||||
auto const *theirs { neighbour->eType == tt_Switch ? neighbour->SwitchExtension->Segments[ theirpath ].get() : neighbour->Segment.get() };
|
auto const *theirs { neighbour->eType == tt_Switch ? neighbour->SwitchExtension->Segments[ theirpath ].get() : neighbour->Segment.get() };
|
||||||
if( theirs == nullptr ) {
|
if( theirs == nullptr ) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ gfx::userdata_array worn_userdata( std::size_t const Count );
|
|||||||
void cut_faces( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::geometrybank_handle const &Bank, TTrack::geometryhandle_sequence &Geometry );
|
void cut_faces( gfx::vertex_array const &Strip, std::size_t const Ring, bool const Start, bool const End, gfx::geometrybank_handle const &Bank, TTrack::geometryhandle_sequence &Geometry );
|
||||||
|
|
||||||
TSegment const &path_segment( TTrack const &Track, int const Path );
|
TSegment const &path_segment( TTrack const &Track, int const Path );
|
||||||
|
int path_count( TTrack const &Track );
|
||||||
|
TTrack *path_neighbour( TTrack const &Track, int const Path, int const End );
|
||||||
double knuckle_bend( double const Into );
|
double knuckle_bend( double const Into );
|
||||||
bool replaced_check( std::vector<check_rail> const &Checks, double const Wingend, double const Direction, double &Far );
|
bool replaced_check( std::vector<check_rail> const &Checks, double const Wingend, double const Direction, double &Far );
|
||||||
gauge_line const &rail_line( TTrack const &Track, int const Path, int const Side, bool const Blades );
|
gauge_line const &rail_line( TTrack const &Track, int const Path, int const Side, bool const Blades );
|
||||||
|
|||||||
Reference in New Issue
Block a user