17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-30 20:10:29 +01:00

fix(sleepers): the wing rails on the timbers as they're bent out: the rails of a track taken in their parts between the cuts at the crossings, as they're laid, a part going on over the gap at an obtuse crossing where its check rail lies; three rails or more close beside held by the fastening of two rails covering the most of them first, then those before and after it, one holding more rails than its seats not narrowed; a rail lying on the brace of a chair beside takes the brace away; a plate cut short at the fastening beside from where its narrowing left it

This commit is contained in:
maj00r
2026-10-23 19:24:47 +02:00
parent fa62a61389
commit f7821eea99
5 changed files with 120 additions and 72 deletions

View File

@@ -18,6 +18,7 @@ http://mozilla.org/MPL/2.0/.
#include "simulation/simulation.h"
#include <algorithm>
#include <functional>
#include <numeric>
#include <optional>
@@ -57,50 +58,67 @@ fastened_rails::fastened_rails( TTrack &Track ) {
auto const bladestretch = [&]( int const Path ) {
auto const &shape { track->blade( Path ) };
return glm::dvec2 { shape.valid ? shape.tip : 0.0, track_rails::blade_length( *track, Path ) }; };
// what the rail is along the path: a blade, the stock rail of a blade, checked
auto const add = [&]( rail &&Line, int const Path, int const Side ) {
if( switched ) {
if( Side == bladeside( Path ) ) {
Line.blade = { 0.0, bladestretch( Path ).y };
}
if( Side == bladeside( 1 - Path ) ) {
auto const stretch { bladestretch( 1 - Path ) };
Line.stock = { std::max( 0.0, stretch.x - chair_lead ), stretch.y };
}
}
if( cut ) {
for( auto const &check : track_rails::rail_checks( *track )[ Path ][ Side > 0 ? 1 : 0 ] ) {
Line.checks.emplace_back( check.from, check.to );
}
}
m_rails.emplace_back( std::move( Line ) ); };
for( int path = 0; path < path_count( *track ); ++path ) {
auto const *segment { path_segment( *track, path ) };
if( segment == nullptr ) {
continue;
}
auto const length { segment->GetLength() };
auto const count { std::max( 1, static_cast<int>( std::ceil( length / fastening_step ) ) ) };
for( auto const side : { -1, 1 } ) {
rail line;
line.track = track;
line.path = path;
line.side = side;
line.foot = size.web - size.low;
line.low = glm::dvec2 { std::numeric_limits<double>::max() };
line.high = glm::dvec2 { std::numeric_limits<double>::lowest() };
for( int step = 0; step <= count; ++step ) {
auto const distance { length * step / count };
glm::dvec3 point, across;
segment->plan_frame( distance, point, across );
auto const flat { plan( across ) };
auto const inward { glm::length( flat ) > 1e-9 ? glm::normalize( flat ) * static_cast<double>( -side ) : glm::dvec2 { 1.0, 0.0 } };
auto const position { plan( point ) - inward * middle };
line.points.push_back( position );
line.heights.push_back( point.y );
line.inward.push_back( inward );
line.distances.push_back( distance );
line.low = glm::min( line.low, position );
line.high = glm::max( line.high, position );
}
if( switched ) {
if( side == bladeside( path ) ) {
line.blade = { 0.0, bladestretch( path ).y };
// the rail in its parts between the cuts at the crossings, as they're laid: a wing rail bent out from the path; on over the
// gap at an obtuse crossing, where its check rail lies
auto cuts { cut ? track->m_railplans[ path ][ side > 0 ].cuts : std::vector<track_rails::rail_cut> {} };
std::stable_sort( cuts.begin(), cuts.end(), []( track_rails::rail_cut const &A, track_rails::rail_cut const &B ) { return A.at < B.at; } );
for( std::size_t part = 0; part <= cuts.size(); ++part ) {
auto const *before { part > 0 ? &cuts[ part - 1 ] : nullptr };
auto const *after { part < cuts.size() ? &cuts[ part ] : nullptr };
auto const from { std::max( 0.0, before != nullptr ? before->start : 0.0 ) };
auto const to { std::min( length, after != nullptr ? std::max( after->end, after->start ) : length ) };
if( to - from < fastening_merge ) {
continue;
}
if( side == bladeside( 1 - path ) ) {
auto const stretch { bladestretch( 1 - path ) };
line.stock = { std::max( 0.0, stretch.x - chair_lead ), stretch.y };
auto const offsets { knots::sum( before != nullptr ? before->startoffsets : knots::line {}, after != nullptr ? after->endoffsets : knots::line {} ) };
auto const count { std::max( 1, static_cast<int>( std::ceil( ( to - from ) / fastening_step ) ) ) };
rail line;
line.track = track;
line.path = path;
line.side = side;
line.foot = size.web - size.low;
line.low = glm::dvec2 { std::numeric_limits<double>::max() };
line.high = glm::dvec2 { std::numeric_limits<double>::lowest() };
for( int step = 0; step <= count; ++step ) {
auto const distance { from + ( to - from ) * step / count };
glm::dvec3 point, across;
segment->plan_frame( distance, point, across );
auto const flat { plan( across ) };
auto const inward { glm::length( flat ) > 1e-9 ? glm::normalize( flat ) * static_cast<double>( -side ) : glm::dvec2 { 1.0, 0.0 } };
auto const position { plan( point ) - inward * ( middle + knots::sample( offsets, distance, 0.0 ) ) };
line.points.push_back( position );
line.heights.push_back( point.y );
line.inward.push_back( inward );
line.distances.push_back( distance );
line.low = glm::min( line.low, position );
line.high = glm::max( line.high, position );
}
add( std::move( line ), path, side );
}
if( cut ) {
for( auto const &check : track_rails::rail_checks( *track )[ path ][ side > 0 ? 1 : 0 ] ) {
line.checks.emplace_back( check.from, check.to );
}
}
m_rails.emplace_back( std::move( line ) );
}
}
}
@@ -189,47 +207,54 @@ std::vector<fastening> fastened_rails::on( beam const &Beam, beam_model const &M
return Beam.from + span * ( At / length ); };
auto const has = [&]( int const Part ) {
return Model.parts[ Part ] != nullptr; };
// the rails from the first to the last under fastenings of two rails in turn, each with its seats under two rails side by side
// and over as many of the rails after them as it reaches
auto const crowd = [&]( std::size_t First, std::size_t const Last ) {
// the rails from the first to the last under fastenings of two rails, each with its seats under two rails side by side and over as
// many of the rails around as it reaches: the one holding the most first, the rails before and after it in turn
std::function<void( std::size_t, std::size_t )> crowd = [&]( std::size_t const First, std::size_t const Last ) {
auto const &reach { Model.spans[ part_check ] };
while( First <= Last ) {
std::size_t covered { 0 };
auto origin { 0.0 };
auto turn { 1.0 };
for( auto seat { First }; seat < Last; ++seat ) {
for( auto const direction : { 1.0, -1.0 } ) {
auto const at { 0.5 * ( rails[ seat ].at + rails[ seat + 1 ].at - direction * check_seats ) };
auto const from { at + std::min( direction * reach.x, direction * reach.y ) };
auto const to { at + std::max( direction * reach.x, direction * reach.y ) };
if( rails[ First ].at < from ) {
continue;
}
std::size_t count { 0 };
while( First + count <= Last && rails[ First + count ].at <= to ) {
++count;
}
if( count > covered ) {
covered = count;
origin = at;
turn = direction;
}
std::size_t covered { 0 };
std::size_t from { First };
auto origin { 0.0 };
auto turn { 1.0 };
for( auto seat { First }; seat < Last; ++seat ) {
for( auto const direction : { 1.0, -1.0 } ) {
auto const at { 0.5 * ( rails[ seat ].at + rails[ seat + 1 ].at - direction * check_seats ) };
auto const low { at + std::min( direction * reach.x, direction * reach.y ) };
auto const high { at + std::max( direction * reach.x, direction * reach.y ) };
auto start { seat };
while( start > First && rails[ start - 1 ].at >= low ) {
--start;
}
auto end { seat + 1 };
while( end < Last && rails[ end + 1 ].at <= high ) {
++end;
}
if( end - start + 1 > covered ) {
covered = end - start + 1;
from = start;
origin = at;
turn = direction;
}
}
if( covered < 2 ) {
result.push_back( { part_plate, point( rails[ First ].at ), rails[ First ].inward } );
++First;
continue;
}
if( covered < 2 ) {
for( auto rail { First }; rail <= Last; ++rail ) {
result.push_back( { part_plate, point( rails[ rail ].at ), rails[ rail ].inward } );
}
result.push_back( { part_check, point( origin ), axis * turn, 1.f, static_cast<float>( 0.5 * check_seats ), 0.f, true } );
First += covered;
return;
}
result.push_back( { part_check, point( origin ), axis * turn, 1.f, static_cast<float>( 0.5 * check_seats ), 0.f, true, covered > 2 } );
if( from > First ) {
crowd( First, from - 1 );
}
if( from + covered <= Last ) {
crowd( from + covered, Last );
}
};
for( std::size_t index = 0; index < rails.size(); ++index ) {
auto const &rail { rails[ index ] };
// three rails or more close beside one another, as at the crossings of the slips, none a stock rail or with a check rail
auto last { index };
while( last + 1 < rails.size() && rails[ last + 1 ].at - rails[ last ].at < fastening_pair && rails[ last ].kind == role::plain && rails[ last + 1 ].kind == role::plain ) {
while( last + 1 < rails.size() && rails[ last + 1 ].at - rails[ last ].at < fastening_crowd && rails[ last ].kind == role::plain && rails[ last + 1 ].kind == role::plain ) {
++last;
}
if( last >= index + 2 && has( part_check ) ) {
@@ -338,7 +363,7 @@ void fastened_rails::fit( std::vector<fastening> &Fastenings, beam const &Beam,
switch( Fastening.part ) {
case part_plate: { return plate_least; }
case part_slide: { return slide_least; }
case part_check: { return check_least; }
case part_check: { return Fastening.whole ? 1.0 : check_least; }
default: { return 1.0; }
} };
// those of one rail together, the rails in the order along the timber
@@ -451,8 +476,8 @@ void fastened_rails::fit( std::vector<fastening> &Fastenings, beam const &Beam,
kept = index;
continue;
}
auto const firstreach { extent( first ) };
auto const secondreach { extent( second ) };
auto firstreach { extent( first ) };
auto secondreach { extent( second ) };
auto const drop = [&]( std::pair<std::size_t, std::size_t> const &Rail ) {
for( auto member { Rail.first }; member < Rail.second; ++member ) {
dropped[ order[ member ] ] = true;
@@ -468,8 +493,13 @@ void fastened_rails::fit( std::vector<fastening> &Fastenings, beam const &Beam,
auto const turn { glm::dot( fastening.across, axis ) };
auto const toward { turn * Toward > 0.0 ? span.y : span.x };
auto const away { turn * Toward > 0.0 ? span.x : span.y };
auto const stays { fastening.placed( away, 1.0 ) };
auto const scale { ( Toward * turn * Room - stays ) / ( toward - away ) };
// the other end where the narrowing left it, or as the plate was if that leaves too little of it
auto stays { fastening.placed( away, fastening.scale ) };
auto scale { ( Toward * turn * Room - stays ) / ( toward - away ) };
if( scale < clip_least ) {
stays = fastening.placed( away, 1.0 );
scale = ( Toward * turn * Room - stays ) / ( toward - away );
}
if( scale < clip_least ) {
return false;
}
@@ -489,15 +519,24 @@ void fastened_rails::fit( std::vector<fastening> &Fastenings, beam const &Beam,
}
return Rail; };
// the brace of a chair where the rail beside comes too close for it, its slide plate kept
auto const brace = [&]( std::pair<std::size_t, std::size_t> const &Rail, int const Side ) {
auto const brace = [&]( std::pair<std::size_t, std::size_t> const &Rail, int const Side, double const Reaching = fastening_gap ) {
for( auto member { Rail.first }; member < Rail.second; ++member ) {
auto const &fastening { Fastenings[ order[ member ] ] };
if( fastening.part == part_chair && reach( fastening, fastening.scale )[ Side ] > fastening_gap ) {
if( fastening.part == part_chair && false == dropped[ order[ member ] ] && reach( fastening, fastening.scale )[ Side ] > Reaching ) {
dropped[ order[ member ] ] = true;
return true;
}
}
return false; };
// a rail lying on the brace of a chair beside takes the brace away
if( brace( first, 1, apart ) || brace( second, 0, apart ) ) {
if( false == overlaps() ) {
kept = index;
continue;
}
firstreach = extent( first );
secondreach = extent( second );
}
// of two rails with check rails, the one with its check rail toward the other one, lying on the fastening of the other
// one then, goes in a plate cut short at that fastening, or without its own, the other one keeping its check rail seated
if( checks( first ) && checks( second ) && faces( first, 1.0 ) != faces( second, -1.0 ) ) {