From 3b43c71dbbcd1b63b2ea7a12cde2bde7cab81a57 Mon Sep 17 00:00:00 2001 From: maj00r Date: Mon, 26 Oct 2026 20:40:28 +0100 Subject: [PATCH] feat(track): the blades of the switches laid in the editor shaped from their templates with the frogs still whole: the blades alone are on (track_features::blades), the rails cut at the frogs, the wing and the check rails stay off. A switch with the key frogs draws its blades from the tip where their planed nose ends to the heel, bent as they're thrown, the rail behind them from the heel on, where they were laid from the start of the switch before; on a switch of the catalogue they start at the cut tip of the tables, 1.248 m from the joint at R 190, 1.5 m at R 300. The plain track a blade of a double switch runs on into starts its rail behind the heel. The switches without the key, laid by other tools, and the ones of a double slip, whose blades end short of crossings found only with the rails cut, keep the blades they had. The paths the vehicles run on don't change --- world/RailCrossings.cpp | 17 +++++++++++++++-- world/Track.cpp | 8 +++++++- world/TrackFeatures.h | 3 +++ world/TrackRails.h | 3 +++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/world/RailCrossings.cpp b/world/RailCrossings.cpp index 1b94e94c..8d399eaf 100644 --- a/world/RailCrossings.cpp +++ b/world/RailCrossings.cpp @@ -96,6 +96,19 @@ bool cut_rails( TTrack const &Track ) { Track.eType == tt_Switch && Track.SwitchExtension && Track.SwitchExtension->m_frogs && Track.SwitchExtension->Segments[ 0 ] && Track.SwitchExtension->Segments[ 1 ] ); } +bool shaped_blades( TTrack const &Track ) { + + if( cut_rails( Track ) ) { + return true; + } + return track_features::blades + && ( Track.iCategoryFlag & 15 ) == 1 + && Track.m_material1 != null_handle + && false == Track.m_editorremoved + && Track.eType == tt_Switch && Track.SwitchExtension && Track.SwitchExtension->m_frogs && Track.SwitchExtension->Segments[ 0 ] && Track.SwitchExtension->Segments[ 1 ] + && false == Track.DoubleSlip(); +} + int blade_steps( TTrack const &Track, int const Path ) { return static_cast( std::ceil( Track.SwitchExtension->Segments[ Path ]->RaSegCount() * 0.65 ) ); @@ -131,7 +144,7 @@ TTrack const *runon_track( TTrack const &Switch, int const Path ) { double blade_runon( TTrack const &Track, int const Side ) { auto const *owner { Track.trPrev }; - if( Track.eType != tt_Normal || Track.Segment == nullptr || owner == nullptr || owner->eType != tt_Switch || false == cut_rails( *owner ) ) { + if( Track.eType != tt_Normal || Track.Segment == nullptr || owner == nullptr || owner->eType != tt_Switch || false == shaped_blades( *owner ) ) { return 0.0; } for( int path = 0; path < 2; ++path ) { @@ -831,7 +844,7 @@ track_rails::switch_blade const &TTrack::blade( int const Path ) const { } cached = switch_blade {}; auto &result { *cached }; - if( eType != tt_Switch || false == cut_rails( *this ) || m_profiles.empty() ) { + if( eType != tt_Switch || false == shaped_blades( *this ) || m_profiles.empty() ) { return result; } auto const side { blade_side( Path ) }; diff --git a/world/Track.cpp b/world/Track.cpp index 771ae2e8..f13e6f97 100644 --- a/world/Track.cpp +++ b/world/Track.cpp @@ -1637,7 +1637,13 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) { continue; } vertices.clear(); // reuse the scratchpad - Segment->RenderLoft( vertices, m_origin, profile, iTrapezoid > 0, texturelength ); + // the rail starts behind the heel of a blade running on into the track from the switch before it + if( auto const runon { eType == tt_Normal && iTrapezoid == 0 ? track_rails::blade_runon( *this, side ) : 0.0 }; runon > 0.0 ) { + Segment->RenderLoftSpan( vertices, m_origin, profile, { .side = side, .halfwidth = 0.5f * std::abs( fTrackWidth ), .texturelength = texturelength, .from = runon, .to = Segment->GetLength() } ); + } + else { + Segment->RenderLoft( vertices, m_origin, profile, iTrapezoid > 0, texturelength ); + } if( open ) { cut_faces( vertices, nnumPts, trPrev == nullptr, trNext == nullptr, GeometryCut1 ); } diff --git a/world/TrackFeatures.h b/world/TrackFeatures.h index e9b13768..366a91a2 100644 --- a/world/TrackFeatures.h +++ b/world/TrackFeatures.h @@ -17,5 +17,8 @@ namespace track_features { bool constexpr crossings { false }; // the 3D sleepers and switch timbers of sleepers3d; off, the tracks keep their ballast whatever eu07.ini sets bool constexpr sleepers { false }; +// the blades of the switches with the key frogs shaped as their templates have them, from the tip their planed nose ends at to the heel, +// with the rails left whole where the crossings are off; off with the crossings too, they're laid from the start of the switch as before +bool constexpr blades { true }; } // namespace track_features diff --git a/world/TrackRails.h b/world/TrackRails.h index 92c68c61..de1c69e2 100644 --- a/world/TrackRails.h +++ b/world/TrackRails.h @@ -33,6 +33,9 @@ double check_length( double const Slope ); double movable_nose_length( double const Slope ); // the rails of the track are cut where they cross other rails: plain tracks, and switches whose frog is made from the rails bool cut_rails( TTrack const &Track ); +// the blades of the switch are shaped from the tip to the heel: with the rails cut, or alone where only the blades are on, but for the +// switches of a double slip, whose blades end short of crossings found only with the rails cut +bool shaped_blades( TTrack const &Track ); int blade_steps( TTrack const &Track, int const Path ); double blade_length( TTrack const &Track, int const Path ); // the plain track a path of a switch goes on into at its end, laid the same way, which the blade of the path may run on into