mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-06 05:48:35 +01:00
fix(track): the legs of an acute nose are cut along the line halfway between the gauge lines of the two rails, followed every 10 cm from the tip to where the full profiles part, instead of a straight bisector, so the nose of a switch frog with a curved diverging path has no seam opening along its middle
This commit is contained in:
@@ -954,15 +954,11 @@ std::vector<glm::dvec2> wing_extension( TTrack &Track, TTrack::check_rail_set co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// acute frog: the rail coming from the throat bends out as a wing rail, the rail going on behind the gap is a leg of the nose
|
// acute frog: the rail coming from the throat bends out as a wing rail, the rail going on behind the gap is a leg of the nose
|
||||||
void acute( TTrack::rail_plan &Plan, double const At, double const Toward, double const Slope, std::vector<glm::dvec2> const &Extension, TTrack::rail_size const &Size ) {
|
void acute( TTrack::rail_plan &Plan, double const At, double const Toward, double const Slope, std::vector<glm::dvec2> const &Extension, std::vector<glm::dvec2> const &Legs ) {
|
||||||
|
|
||||||
auto const half { Slope / ( 1.0 + std::sqrt( 1.0 + Slope * Slope ) ) };
|
|
||||||
auto const tip { 0.5 * nose_tip };
|
|
||||||
auto const apart { Size.high + 0.01 };
|
|
||||||
auto const throat { At + Toward * flangeway / Slope };
|
auto const throat { At + Toward * flangeway / Slope };
|
||||||
auto const flare { At - Toward * wing_reach( Slope ) };
|
auto const flare { At - Toward * wing_reach( Slope ) };
|
||||||
auto const nose { At - Toward * tip / half };
|
auto const nose { Toward < 0.0 ? Legs.front().x : Legs.back().x };
|
||||||
auto const blunt { At - Toward * apart / half };
|
|
||||||
std::vector<glm::dvec2> wing { { throat, 0.0 }, { flare, std::abs( flare - throat ) * Slope } };
|
std::vector<glm::dvec2> wing { { throat, 0.0 }, { flare, std::abs( flare - throat ) * Slope } };
|
||||||
wing.insert( wing.end(), Extension.begin(), Extension.end() );
|
wing.insert( wing.end(), Extension.begin(), Extension.end() );
|
||||||
auto const wingend { Extension.empty() ? flare : Extension.back().x };
|
auto const wingend { Extension.empty() ? flare : Extension.back().x };
|
||||||
@@ -978,11 +974,11 @@ void acute( TTrack::rail_plan &Plan, double const At, double const Toward, doubl
|
|||||||
cut.endoffsets = wing;
|
cut.endoffsets = wing;
|
||||||
cut.endrolled = rolled;
|
cut.endrolled = rolled;
|
||||||
cut.start = nose;
|
cut.start = nose;
|
||||||
cut.startextents = { { nose, tip }, { blunt, apart } };
|
cut.startextents = Legs;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cut.end = nose;
|
cut.end = nose;
|
||||||
cut.endextents = { { blunt, apart }, { nose, tip } };
|
cut.endextents = Legs;
|
||||||
cut.start = wingend;
|
cut.start = wingend;
|
||||||
cut.startoffsets = wing;
|
cut.startoffsets = wing;
|
||||||
cut.startrolled = rolled;
|
cut.startrolled = rolled;
|
||||||
@@ -1090,44 +1086,53 @@ struct frame_corner {
|
|||||||
double facing { 0.0 };
|
double facing { 0.0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
double lateral( gauge_line const &Line, int const Side, glm::dvec3 const &Point, double &Distance ) {
|
||||||
|
|
||||||
|
glm::dvec3 point, tangent;
|
||||||
|
for( int step = 0; step < 8; ++step ) {
|
||||||
|
Line.at( Distance, point, tangent );
|
||||||
|
Distance += glm::dot( plan( Point - point ), glm::normalize( plan( tangent ) ) );
|
||||||
|
}
|
||||||
|
Line.at( Distance, point, tangent );
|
||||||
|
return -glm::dot( plan( Point - point ), plan( Line.normal( Distance, Side ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
double nearest_distance( gauge_line const &Line, glm::dvec3 const &Point ) {
|
||||||
|
|
||||||
|
auto result { Line.distances.front() };
|
||||||
|
auto nearest { std::numeric_limits<double>::max() };
|
||||||
|
for( std::size_t i = 0; i < Line.points.size(); ++i ) {
|
||||||
|
auto const gap { glm::length( plan( Line.points[ i ] - Point ) ) };
|
||||||
|
if( gap < nearest ) {
|
||||||
|
nearest = gap;
|
||||||
|
result = Line.distances[ i ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<glm::dvec2> tread_edge( TTrack const &Track, int const Path, int const Side, TTrack const &Other, int const Otherpath, int const Otherside, double const From, double const To, bool &Below, std::vector<glm::dvec2> &Gauge ) {
|
std::vector<glm::dvec2> tread_edge( TTrack const &Track, int const Path, int const Side, TTrack const &Other, int const Otherpath, int const Otherside, double const From, double const To, bool &Below, std::vector<glm::dvec2> &Gauge ) {
|
||||||
|
|
||||||
auto const &ours { rail_line( Track, Path, Side > 0, false ) };
|
auto const &ours { rail_line( Track, Path, Side > 0, false ) };
|
||||||
auto const &theirs { rail_line( Other, Otherpath, Otherside > 0, false ) };
|
auto const &theirs { rail_line( Other, Otherpath, Otherside > 0, false ) };
|
||||||
auto const project = [&]( gauge_line const &Line, int const Lineside, glm::dvec3 const &Point, double &Distance ) {
|
|
||||||
glm::dvec3 point, tangent;
|
|
||||||
for( int step = 0; step < 8; ++step ) {
|
|
||||||
Line.at( Distance, point, tangent );
|
|
||||||
Distance += glm::dot( plan( Point - point ), glm::normalize( plan( tangent ) ) );
|
|
||||||
}
|
|
||||||
Line.at( Distance, point, tangent );
|
|
||||||
return -glm::dot( plan( Point - point ), plan( Line.normal( Distance, Lineside ) ) ); };
|
|
||||||
glm::dvec3 point, tangent;
|
glm::dvec3 point, tangent;
|
||||||
ours.at( From, point, tangent );
|
ours.at( From, point, tangent );
|
||||||
auto otherat { theirs.distances.front() };
|
auto otherat { nearest_distance( theirs, point ) };
|
||||||
auto nearest { std::numeric_limits<double>::max() };
|
|
||||||
for( std::size_t i = 0; i < theirs.points.size(); ++i ) {
|
|
||||||
auto const gap { glm::length( plan( theirs.points[ i ] - point ) ) };
|
|
||||||
if( gap < nearest ) {
|
|
||||||
nearest = gap;
|
|
||||||
otherat = theirs.distances[ i ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<glm::dvec2> knots;
|
std::vector<glm::dvec2> knots;
|
||||||
auto below { 0 };
|
auto below { 0 };
|
||||||
auto const count { std::max( 2, static_cast<int>( std::ceil( ( To - From ) / 0.1 ) ) + 1 ) };
|
auto const count { std::max( 2, static_cast<int>( std::ceil( ( To - From ) / 0.1 ) ) + 1 ) };
|
||||||
for( int i = 0; i < count; ++i ) {
|
for( int i = 0; i < count; ++i ) {
|
||||||
auto distance { glm::mix( From, To, static_cast<double>( i ) / ( count - 1 ) ) };
|
auto distance { glm::mix( From, To, static_cast<double>( i ) / ( count - 1 ) ) };
|
||||||
ours.at( distance, point, tangent );
|
ours.at( distance, point, tangent );
|
||||||
project( theirs, Otherside, point, otherat );
|
lateral( theirs, Otherside, point, otherat );
|
||||||
glm::dvec3 line;
|
glm::dvec3 line;
|
||||||
theirs.at( otherat, line, tangent );
|
theirs.at( otherat, line, tangent );
|
||||||
auto const normal { theirs.normal( otherat, Otherside ) };
|
auto const normal { theirs.normal( otherat, Otherside ) };
|
||||||
auto at { distance };
|
auto at { distance };
|
||||||
auto const gauge { project( ours, Side, line, at ) };
|
auto const gauge { lateral( ours, Side, line, at ) };
|
||||||
Gauge.emplace_back( at, gauge );
|
Gauge.emplace_back( at, gauge );
|
||||||
at = distance;
|
at = distance;
|
||||||
auto const edge { project( ours, Side, line - normal * rolled_band, at ) };
|
auto const edge { lateral( ours, Side, line - normal * rolled_band, at ) };
|
||||||
below += ( gauge < edge ? 1 : -1 );
|
below += ( gauge < edge ? 1 : -1 );
|
||||||
knots.emplace_back( at, edge );
|
knots.emplace_back( at, edge );
|
||||||
}
|
}
|
||||||
@@ -1138,6 +1143,44 @@ std::vector<glm::dvec2> tread_edge( TTrack const &Track, int const Path, int con
|
|||||||
return knots;
|
return knots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<glm::dvec2> nose_extents( TTrack const &Track, int const Path, int const Side, TTrack const &Other, int const Otherpath, int const Otherside, double const At, double const Toward, double const Slope, TTrack::rail_size const &Size ) {
|
||||||
|
|
||||||
|
auto const half { Slope / ( 1.0 + std::sqrt( 1.0 + Slope * Slope ) ) };
|
||||||
|
auto const tip { 0.5 * nose_tip };
|
||||||
|
auto const apart { Size.high + 0.01 };
|
||||||
|
auto const nose { At - Toward * tip / half };
|
||||||
|
auto const blunt { At - Toward * apart / half };
|
||||||
|
std::vector<glm::dvec2> straight { { std::min( nose, blunt ), Toward < 0.0 ? tip : apart }, { std::max( nose, blunt ), Toward < 0.0 ? apart : tip } };
|
||||||
|
auto const &ours { rail_line( Track, Path, Side > 0, false ) };
|
||||||
|
auto const &theirs { rail_line( Other, Otherpath, Otherside > 0, false ) };
|
||||||
|
glm::dvec3 point, tangent;
|
||||||
|
ours.at( nose, point, tangent );
|
||||||
|
auto otherat { nearest_distance( theirs, point ) };
|
||||||
|
auto extent { tip };
|
||||||
|
auto const step { 0.1 };
|
||||||
|
auto const limit { static_cast<int>( std::ceil( 3.0 * std::abs( blunt - nose ) / step ) ) };
|
||||||
|
std::vector<glm::dvec2> knots;
|
||||||
|
for( int i = 0; i <= limit; ++i ) {
|
||||||
|
auto const distance { nose - Toward * step * i };
|
||||||
|
ours.at( distance, point, tangent );
|
||||||
|
auto const normal { ours.normal( distance, Side ) };
|
||||||
|
for( int iteration = 0; iteration < 6; ++iteration ) {
|
||||||
|
extent += 0.5 * ( lateral( theirs, Otherside, point - normal * extent, otherat ) - extent );
|
||||||
|
}
|
||||||
|
if( extent >= apart && false == knots.empty() ) {
|
||||||
|
auto const &last { knots.back() };
|
||||||
|
knots.emplace_back( glm::mix( last.x, distance, ( apart - last.y ) / ( extent - last.y ) ), apart );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
knots.emplace_back( distance, std::max( extent, 0.0 ) );
|
||||||
|
}
|
||||||
|
if( knots.size() < 2 || knots.back().y < apart ) {
|
||||||
|
return straight;
|
||||||
|
}
|
||||||
|
std::sort( knots.begin(), knots.end(), []( glm::dvec2 const &A, glm::dvec2 const &B ) { return A.x < B.x; } );
|
||||||
|
return knots;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
material_handle TTrack::rail_material( int const Path ) const {
|
material_handle TTrack::rail_material( int const Path ) const {
|
||||||
@@ -1293,7 +1336,8 @@ TTrack::rail_layout TTrack::plan_rails( bool const Crossings ) {
|
|||||||
auto const slope { std::tan( crossing.angle ) };
|
auto const slope { std::tan( crossing.angle ) };
|
||||||
wingends[ crossing.path ][ crossing.side > 0 ].emplace_back( crossing.at - toward * wing_reach( slope ), -toward );
|
wingends[ crossing.path ][ crossing.side > 0 ].emplace_back( crossing.at - toward * wing_reach( slope ), -toward );
|
||||||
acute( plan, crossing.at, toward, slope,
|
acute( plan, crossing.at, toward, slope,
|
||||||
wing_extension( *this, checks, crossing.path, crossing.side, crossing.at, toward, slope, *crossing.track, crossing.otherpath, crossing.otherside, crossing.otherat, crossing.aligned ? -toward : toward ), size );
|
wing_extension( *this, checks, crossing.path, crossing.side, crossing.at, toward, slope, *crossing.track, crossing.otherpath, crossing.otherside, crossing.otherat, crossing.aligned ? -toward : toward ),
|
||||||
|
nose_extents( *this, crossing.path, crossing.side, *crossing.track, crossing.otherpath, crossing.otherside, crossing.at, toward, slope, size ) );
|
||||||
auto const nose { toward < 0.0 ? plan.cuts.back().start : plan.cuts.back().end };
|
auto const nose { toward < 0.0 ? plan.cuts.back().start : plan.cuts.back().end };
|
||||||
auto const shared { crossing.at - toward * ( rolled_band + size.head + tread_fade ) / slope };
|
auto const shared { crossing.at - toward * ( rolled_band + size.head + tread_fade ) / slope };
|
||||||
tread( crossing.path, crossing.side, { std::min( nose, shared ), std::max( nose, shared ) }, *crossing.track, crossing.otherpath, toward > 0.0 ? 1 : -1, crossing.otherside );
|
tread( crossing.path, crossing.side, { std::min( nose, shared ), std::max( nose, shared ) }, *crossing.track, crossing.otherpath, toward > 0.0 ? 1 : -1, crossing.otherside );
|
||||||
@@ -1419,7 +1463,8 @@ TTrack::rail_layout TTrack::plan_rails( bool const Crossings ) {
|
|||||||
}
|
}
|
||||||
wingends[ path ][ frog.side[ path ] > 0 ].emplace_back( frog.at[ path ] + wing_reach( slope ), 1.0 );
|
wingends[ path ][ frog.side[ path ] > 0 ].emplace_back( frog.at[ path ] + wing_reach( slope ), 1.0 );
|
||||||
acute( plans[ path ][ frog.side[ path ] > 0 ], frog.at[ path ], -1.0, slope,
|
acute( plans[ path ][ frog.side[ path ] > 0 ], frog.at[ path ], -1.0, slope,
|
||||||
wing_extension( *this, checks, path, frog.side[ path ], frog.at[ path ], -1.0, slope, *this, 1 - path, frog.side[ 1 - path ], frog.at[ 1 - path ], 1.0 ), size );
|
wing_extension( *this, checks, path, frog.side[ path ], frog.at[ path ], -1.0, slope, *this, 1 - path, frog.side[ 1 - path ], frog.at[ 1 - path ], 1.0 ),
|
||||||
|
nose_extents( *this, path, frog.side[ path ], *this, 1 - path, frog.side[ 1 - path ], frog.at[ path ], -1.0, slope, size ) );
|
||||||
auto const nose { plans[ path ][ frog.side[ path ] > 0 ].cuts.back().start };
|
auto const nose { plans[ path ][ frog.side[ path ] > 0 ].cuts.back().start };
|
||||||
auto const shared { frog.at[ path ] + ( rolled_band + size.head + tread_fade ) / slope };
|
auto const shared { frog.at[ path ] + ( rolled_band + size.head + tread_fade ) / slope };
|
||||||
tread( path, frog.side[ path ], { std::min( nose, shared ), std::max( nose, shared ) }, *this, 1 - path, -1, frog.side[ 1 - path ] );
|
tread( path, frog.side[ path ], { std::min( nose, shared ), std::max( nose, shared ) }, *this, 1 - path, -1, frog.side[ 1 - path ] );
|
||||||
|
|||||||
Reference in New Issue
Block a user