17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-17 05:09:20 +02:00

feat(track): at a crossing at a wide angle every head of one track meets every head of the other in a mitre from the corner of their flangeways to the far corner of the heads, the way the corners of a cast diamond look, so the running rails and guard rails of both tracks form closed corners and only the flangeways stay open, instead of the rails of one track going through and the other ones glued to their sides; corner_cut gives the mitres, as bends of the running rails and as miters of the guard rails; the fit of a loft end to the profile of another rail and the field and gauge outlines of the rail profile are gone with the gluing

This commit is contained in:
maj00r
2026-10-14 11:08:02 +02:00
parent f27ed682c0
commit 572ee569dc
6 changed files with 31 additions and 92 deletions

View File

@@ -568,11 +568,9 @@ void TTrack::rail_layer::lay_guards() {
sort_cuts( cuts ); sort_cuts( cuts );
auto start { guard.from }; auto start { guard.from };
auto startmiter { guard.frommiter }; auto startmiter { guard.frommiter };
rail_cut startcut;
for( std::size_t i = 0; i <= cuts.size(); ++i ) { for( std::size_t i = 0; i <= cuts.size(); ++i ) {
auto const end { i < cuts.size() ? cuts[ i ].end : guard.to }; auto const end { i < cuts.size() ? cuts[ i ].end : guard.to };
auto const endmiter { i < cuts.size() ? cuts[ i ].endmiter : guard.tomiter }; auto const endmiter { i < cuts.size() ? cuts[ i ].endmiter : guard.tomiter };
auto const endcut { i < cuts.size() ? cuts[ i ] : rail_cut {} };
auto const a { std::max( { mitered( startmiter, start, false ), m_from, 0.0 } ) }; auto const a { std::max( { mitered( startmiter, start, false ), m_from, 0.0 } ) };
auto const b { std::min( { mitered( endmiter, end, true ), m_length, mitered( guard.tomiter, guard.to, true ) } ) }; auto const b { std::min( { mitered( endmiter, end, true ), m_length, mitered( guard.tomiter, guard.to, true ) } ) };
if( b - a > 0.01 ) { if( b - a > 0.01 ) {
@@ -583,17 +581,14 @@ void TTrack::rail_layer::lay_guards() {
( ending == ( miter.y < 0.0 ) ? uppers : lowers ).emplace_back( 1.0 / miter.y, -miter.x / miter.y - m_guardoffset ); ( ending == ( miter.y < 0.0 ) ? uppers : lowers ).emplace_back( 1.0 / miter.y, -miter.x / miter.y - m_guardoffset );
} }
} }
auto const glued { a == start && false == startcut.startfit.empty() };
auto const gluedend { b == end && false == endcut.endfit.empty() };
piece( piece(
m_profile, m_profile,
{ .from = a, .to = b, .offsets = offsets, .extents = envelope( uppers, true, a, b ), .inner = envelope( lowers, false, a, b ), .capfrom = false == glued, .capto = false == gluedend, .rolled = false }, { .from = a, .to = b, .offsets = offsets, .extents = envelope( uppers, true, a, b ), .inner = envelope( lowers, false, a, b ), .capfrom = true, .capto = true, .rolled = false },
{ a, b, { glued ? startcut.startbend : 0.0, glued ? startcut.startfit : knots::line {} }, { gluedend ? endcut.endbend : 0.0, gluedend ? endcut.endfit : knots::line {} } } ); { a, b, {}, {} } );
} }
if( i < cuts.size() && cuts[ i ].start > start ) { if( i < cuts.size() && cuts[ i ].start > start ) {
start = cuts[ i ].start; start = cuts[ i ].start;
startmiter = cuts[ i ].startmiter; startmiter = cuts[ i ].startmiter;
startcut = cuts[ i ];
} }
} }
} }
@@ -639,7 +634,6 @@ void TTrack::rail_layer::lay_cuts( gfx::vertex_array const &Shape, std::vector<r
auto start { -1e9 }; auto start { -1e9 };
auto startcap { true }; auto startcap { true };
auto startbend { 0.0 }; auto startbend { 0.0 };
knots::line startfit;
knots::line rolledfrom; knots::line rolledfrom;
knots::line offsets, extents, inner; knots::line offsets, extents, inner;
for( std::size_t i = 0; i <= Cuts.size(); ++i ) { for( std::size_t i = 0; i <= Cuts.size(); ++i ) {
@@ -662,8 +656,8 @@ void TTrack::rail_layer::lay_cuts( gfx::vertex_array const &Shape, std::vector<r
auto const capend { end < m_length ? Cuts[ i ].endcap : m_openend }; auto const capend { end < m_length ? Cuts[ i ].endcap : m_openend };
piece_ends const ends { piece_ends const ends {
a, b, a, b,
{ start > m_from ? startbend : 0.0, start > m_from ? startfit : knots::line {} }, { start > m_from ? startbend : 0.0 },
{ end < m_length ? Cuts[ i ].endbend : 0.0, end < m_length ? Cuts[ i ].endfit : knots::line {} } }; { end < m_length ? Cuts[ i ].endbend : 0.0 } };
if( b - a > 0.01 ) { if( b - a > 0.01 ) {
std::vector<rail_tread> active; std::vector<rail_tread> active;
for( auto const &tread : Treads ) { for( auto const &tread : Treads ) {
@@ -714,7 +708,6 @@ void TTrack::rail_layer::lay_cuts( gfx::vertex_array const &Shape, std::vector<r
start = Cuts[ i ].start; start = Cuts[ i ].start;
startcap = Cuts[ i ].startcap; startcap = Cuts[ i ].startcap;
startbend = Cuts[ i ].startbend; startbend = Cuts[ i ].startbend;
startfit = Cuts[ i ].startfit;
offsets = Cuts[ i ].startoffsets; offsets = Cuts[ i ].startoffsets;
extents = Cuts[ i ].startextents; extents = Cuts[ i ].startextents;
inner = Cuts[ i ].startinner; inner = Cuts[ i ].startinner;

View File

@@ -72,7 +72,6 @@ struct rail_size {
double ledge { 0.0 }; double ledge { 0.0 };
double web { 0.0365 }; double web { 0.0365 };
double neck { -0.0467 }; double neck { -0.0467 };
knots::line field, gauge;
}; };
// a check rail beside a rail, how far its ends turn away from the running rail // a check rail beside a rail, how far its ends turn away from the running rail
struct check_rail { struct check_rail {
@@ -95,7 +94,6 @@ struct rail_cut {
glm::dvec2 startmiter { 0.0 }; glm::dvec2 startmiter { 0.0 };
double endbend { 0.0 }; double endbend { 0.0 };
double startbend { 0.0 }; double startbend { 0.0 };
knots::line endfit, startfit;
knots::line endinner, startinner; knots::line endinner, startinner;
bool endcap { true }; bool endcap { true };
bool startcap { true }; bool startcap { true };

View File

@@ -99,14 +99,12 @@ void obtuse( track_rails::rail_plan &Plan, double const At, double const Into, t
Plan.cuts.push_back( cut ); Plan.cuts.push_back( cut );
} }
// crossing at a wide angle: running rails are broken for the flanges of the other track, the ones of the track not going through also where the head of the other rail lies; guard rails give way to the running rails and flangeways of the other track, the ones of the track not going through also to its guard rails // a guard rail of a crossing at a middle angle gives way to the running rail and the flangeway of the other track
struct wide_cut { struct wide_cut {
double from { 0.0 }; double from { 0.0 };
double to { 0.0 }; double to { 0.0 };
double inner { 0.0 }; double inner { 0.0 };
double outer { 0.0 }; double outer { 0.0 };
knots::line fromline;
knots::line toline;
}; };
void wide( track_rails::rail_plan &Plan, track_rails::rail_crossing const &Crossing, wide_cut const &Cut ) { void wide( track_rails::rail_plan &Plan, track_rails::rail_crossing const &Crossing, wide_cut const &Cut ) {
@@ -122,29 +120,26 @@ void wide( track_rails::rail_plan &Plan, track_rails::rail_crossing const &Cross
cut.start = at + std::max( low, high ); cut.start = at + std::max( low, high );
cut.endmiter = { at + ( into > 0.0 ? Cut.from - 0.005 : Cut.to + 0.005 ) / into, facing / into }; cut.endmiter = { at + ( into > 0.0 ? Cut.from - 0.005 : Cut.to + 0.005 ) / into, facing / into };
cut.startmiter = { at + ( into > 0.0 ? Cut.to + 0.005 : Cut.from - 0.005 ) / into, facing / into }; cut.startmiter = { at + ( into > 0.0 ? Cut.to + 0.005 : Cut.from - 0.005 ) / into, facing / into };
auto const glue = [&]( knots::line const &Line, double const Edge, double &Position, glm::dvec2 &Miter, double &Bend, knots::line &Fit, bool &Cap ) {
if( Line.empty() ) {
return;
}
Position = at + Edge / into;
Miter = {};
Bend = facing / into;
for( auto const &knot : Line ) {
Fit.emplace_back( knot.x, ( knot.y - Edge ) / into );
}
Cap = false; };
glue( into > 0.0 ? Cut.fromline : Cut.toline, into > 0.0 ? Cut.from : Cut.to, cut.end, cut.endmiter, cut.endbend, cut.endfit, cut.endcap );
glue( into > 0.0 ? Cut.toline : Cut.fromline, into > 0.0 ? Cut.to : Cut.from, cut.start, cut.startmiter, cut.startbend, cut.startfit, cut.startcap );
Plan.cuts.push_back( cut ); Plan.cuts.push_back( cut );
} }
std::vector<glm::dvec2> glue_line( std::vector<glm::dvec2> const &Outline, double const Base ) { track_rails::rail_cut corner_cut( track_rails::rail_crossing const &Crossing, double const Face, double const Toward, double const Head, double const Other ) {
std::vector<glm::dvec2> line; auto const mitre = [&]( double const Edge, double const Flange ) {
for( auto const &knot : Outline ) { auto const slope { Flange * Other / ( Toward * Head ) };
line.emplace_back( knot.x, Base - knot.y ); return glm::dvec2 { Crossing.at + ( Edge - Face * slope ) / Crossing.into, ( slope + Crossing.facing ) / Crossing.into }; };
} auto const rail { mitre( 0.0, 1.0 ) };
return line; auto const guard { mitre( flangeway, -1.0 ) };
auto const rising { Crossing.into > 0.0 };
track_rails::rail_cut cut;
cut.at = Crossing.at;
cut.endmiter = ( rising ? rail : guard );
cut.startmiter = ( rising ? guard : rail );
cut.end = cut.endmiter.x + cut.endmiter.y * Face;
cut.start = cut.startmiter.x + cut.startmiter.y * Face;
cut.endbend = cut.endmiter.y;
cut.startbend = cut.startmiter.y;
return cut;
} }
track_rails::rail_fill guard_fill( track_rails::guard_rail const &Guard, track_rails::rail_size const &Size ) { track_rails::rail_fill guard_fill( track_rails::guard_rail const &Guard, track_rails::rail_size const &Size ) {
@@ -443,15 +438,12 @@ void TTrack::rail_planner::cross_grooved( rail_crossing const &Crossing, rail_si
void TTrack::rail_planner::cross_wide( rail_crossing const &Crossing, rail_size const &Other ) { void TTrack::rail_planner::cross_wide( rail_crossing const &Crossing, rail_size const &Other ) {
auto const through { goes_through( m_track, *Crossing.track ) }; plan_of( Crossing ).cuts.push_back( corner_cut( Crossing, 0.0, -1.0, m_size.head, Other.head ) );
wide( plan_of( Crossing ), Crossing, { through ? 0.0 : -Other.head, flangeway, 0.0, m_size.head, through ? knots::line {} : glue_line( Other.field, 0.0 ) } ); add_tread( Crossing.path, Crossing.side, shared_span( Crossing, Other ), *Crossing.track, Crossing.otherpath );
if( through ) {
add_tread( Crossing.path, Crossing.side, shared_span( Crossing, Other ), *Crossing.track, Crossing.otherpath );
}
auto const reach { ( flangeway + m_size.head + guard_reach ) / std::abs( Crossing.into ) }; auto const reach { ( flangeway + m_size.head + guard_reach ) / std::abs( Crossing.into ) };
track_rails::guard_rail guard { Crossing.at - reach, Crossing.at + reach }; track_rails::guard_rail guard { Crossing.at - reach, Crossing.at + reach };
guard.through = through; guard.through = goes_through( m_track, *Crossing.track );
wide( guard.plan, Crossing, { -Other.head, through ? flangeway : flangeway + Other.head, m_guardoffset, m_guardoffset + m_size.head, glue_line( Other.field, 0.0 ), through ? knots::line {} : glue_line( Other.gauge, flangeway + Other.head ) } ); guard.plan.cuts.push_back( corner_cut( Crossing, -flangeway, 1.0, m_size.head, Other.head ) );
merge_guard( m_layout.guards[ Crossing.path ][ Crossing.side > 0 ], guard ); merge_guard( m_layout.guards[ Crossing.path ][ Crossing.side > 0 ], guard );
} }

View File

@@ -33,36 +33,6 @@ rail_size measure_rail( gfx::vertex_array const &Profile ) {
} }
result.height = top - bottom; result.height = top - bottom;
result.crest = top; result.crest = top;
std::size_t firsttop { count };
std::size_t lasttop { 0 };
for( std::size_t i = 0; i < count; ++i ) {
if( Profile[ i ].position.y > top - 1e-4 ) {
firsttop = std::min( firsttop, i );
lasttop = std::max( lasttop, i );
}
}
knots::line sides[ 2 ];
for( std::size_t i = 0; i < count; ++i ) {
auto const &point { Profile[ i ].position };
if( i <= firsttop ) {
sides[ 0 ].emplace_back( point.y, point.x );
}
if( i >= lasttop ) {
sides[ 1 ].emplace_back( point.y, point.x );
}
}
for( auto &side : sides ) {
knots::sort( side );
}
auto const mean = []( knots::line const &Side ) {
auto sum { 0.0 };
for( auto const &knot : Side ) {
sum += knot.y;
}
return sum / std::max<std::size_t>( Side.size(), 1 ); };
auto const fieldfirst { mean( sides[ 0 ] ) > mean( sides[ 1 ] ) };
result.field = sides[ fieldfirst ? 0 : 1 ];
result.gauge = sides[ fieldfirst ? 1 : 0 ];
auto const middle { top - 0.5 * result.height }; auto const middle { top - 0.5 * result.height };
auto webfrom { 1e9 }; auto webfrom { 1e9 };
auto webto { -1e9 }; auto webto { -1e9 };

View File

@@ -616,23 +616,13 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
} }
std::sort( stations.begin(), stations.end() ); std::sort( stations.begin(), stations.end() );
stations.erase( std::unique( stations.begin(), stations.end(), []( double const A, double const B ) { return B - A < 0.001; } ), stations.end() ); stations.erase( std::unique( stations.begin(), stations.end(), []( double const A, double const B ) { return B - A < 0.001; } ), stations.end() );
if( Span.fromend.bend != 0.0 || Span.toend.bend != 0.0 || false == Span.fromend.fit.empty() || false == Span.toend.fit.empty() ) { if( Span.fromend.bend != 0.0 || Span.toend.bend != 0.0 ) {
auto widest { 0.0 }; auto widest { 0.0 };
for( auto const &point : ShapePoints ) { for( auto const &point : ShapePoints ) {
widest = std::max( widest, std::abs( static_cast<double>( Span.side * point.position.x - Span.halfwidth ) ) ); widest = std::max( widest, std::abs( static_cast<double>( Span.side * point.position.x - Span.halfwidth ) ) );
} }
auto offsetmost { 0.0 }; auto const frommargin { std::abs( Span.fromend.bend ) * widest + 0.001 };
for( auto const &knot : Span.offsets ) { auto const tomargin { std::abs( Span.toend.bend ) * widest + 0.001 };
offsetmost = std::max( offsetmost, std::abs( knot.y ) );
}
auto const margin = [&]( loft_end const &End ) {
auto fitmost { 0.0 };
for( auto const &knot : End.fit ) {
fitmost = std::max( fitmost, std::abs( knot.y ) );
}
return std::abs( End.bend ) * ( End.fit.empty() ? widest : widest + offsetmost ) + fitmost + 0.001; };
auto const frommargin { margin( Span.fromend ) };
auto const tomargin { margin( Span.toend ) };
stations.erase( std::remove_if( stations.begin(), stations.end(), [&]( double const Distance ) { stations.erase( std::remove_if( stations.begin(), stations.end(), [&]( double const Distance ) {
return ( Distance > Span.from && Distance < Span.to ) return ( Distance > Span.from && Distance < Span.to )
&& ( Distance < Span.from + frommargin || Distance > Span.to - tomargin ); } ), stations.end() ); && ( Distance < Span.from + frommargin || Distance > Span.to - tomargin ); } ), stations.end() );
@@ -671,17 +661,14 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
static loft_end const unshaped; static loft_end const unshaped;
auto const &shaped { Distance <= Span.from ? Span.fromend : Distance >= Span.to ? Span.toend : unshaped }; auto const &shaped { Distance <= Span.from ? Span.fromend : Distance >= Span.to ? Span.toend : unshaped };
auto const bend { shaped.bend }; auto const bend { shaped.bend };
auto const &fit { shaped.fit };
auto along { glm::vec3 { 0.f } }; auto along { glm::vec3 { 0.f } };
auto forward { glm::vec3 { 0.f } }; if( bend != 0.0 ) {
if( bend != 0.0 || false == fit.empty() ) {
glm::dvec3 ahead, behind, unused; glm::dvec3 ahead, behind, unused;
plan_frame( std::min( Distance + 0.001, static_cast<double>( fLength ) ), ahead, unused ); plan_frame( std::min( Distance + 0.001, static_cast<double>( fLength ) ), ahead, unused );
plan_frame( std::max( Distance - 0.001, 0.0 ), behind, unused ); plan_frame( std::max( Distance - 0.001, 0.0 ), behind, unused );
auto const tangent { glm::dvec3 { ahead.x - behind.x, 0.0, ahead.z - behind.z } }; auto const tangent { glm::dvec3 { ahead.x - behind.x, 0.0, ahead.z - behind.z } };
if( glm::length2( tangent ) > 0.0 ) { if( glm::length2( tangent ) > 0.0 ) {
forward = glm::vec3 { glm::normalize( tangent ) }; along = glm::vec3 { glm::normalize( tangent ) } * static_cast<float>( bend );
along = forward * static_cast<float>( bend );
} }
} }
Ring.clear(); Ring.clear();
@@ -763,7 +750,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
wall = ( side > 0 ? outerwall : innerwall ); wall = ( side > 0 ? outerwall : innerwall );
} }
} }
auto pt { parallel * static_cast<float>( Span.side * ( Span.halfwidth + outside + offset ) ) + position + along * static_cast<float>( outside + offset ) + forward * static_cast<float>( knots::sample( fit, shape.position.y, 0.0 ) ) }; auto pt { parallel * static_cast<float>( Span.side * ( Span.halfwidth + outside + offset ) ) + position + along * static_cast<float>( outside + offset ) };
pt.y += shape.position.y + Span.lift; pt.y += shape.position.y + Span.lift;
auto norm { shape.normal.x * parallel }; auto norm { shape.normal.x * parallel };
norm.y += shape.normal.y; norm.y += shape.normal.y;

View File

@@ -24,7 +24,6 @@ struct map_colored_paths {
struct loft_end { struct loft_end {
double bend { 0.0 }; double bend { 0.0 };
knots::line fit;
}; };
struct loft_span { struct loft_span {