diff --git a/tests/unit/test_track_uneven.cpp b/tests/unit/test_track_uneven.cpp index afea0b67..46bd1e5f 100644 --- a/tests/unit/test_track_uneven.cpp +++ b/tests/unit/test_track_uneven.cpp @@ -165,6 +165,18 @@ TEST_CASE("uneven track: the value along a track meets its neighbours exactly") } } +TEST_CASE("uneven track: the foot of the ballast stays where it was") +{ + double const rail{0.18}; + double const height{0.38}; + CHECK(track_uneven::bed_share(0.0, rail, height) == doctest::Approx(1.0)); // rail top + CHECK(track_uneven::bed_share(rail, rail, height) == doctest::Approx(1.0)); // top of the ballast + CHECK(track_uneven::bed_share(rail + 0.5 * height, rail, height) == doctest::Approx(0.5)); + CHECK(track_uneven::bed_share(rail + height, rail, height) == doctest::Approx(0.0)); // its foot + CHECK(track_uneven::bed_share(rail + 2.0 * height, rail, height) == doctest::Approx(0.0)); + CHECK(track_uneven::bed_share(rail + 1.0, rail, 0.0) == doctest::Approx(1.0)); // no ballast +} + TEST_CASE("uneven track: the rails dip around a joint") { CHECK(track_uneven::dip(0.0) == doctest::Approx(1.0)); diff --git a/track_uneven_doc.md b/track_uneven_doc.md index aca9ca32..8570fd94 100644 --- a/track_uneven_doc.md +++ b/track_uneven_doc.md @@ -60,7 +60,7 @@ Każda składowa łączy się osobno: - **Styki:** zapadnięcia są co `fSoundDistance`, na długości 6 m, i biegną dalej przez kolejne tory o tym samym odstępie. Stukot osi wypada w miejscu zapadnięcia. Przy odstępie 6 m lub mniejszym oraz na rozjazdach zapadnięć nie ma. - **Przechyłka:** dolicza się do projektowej. Jest pochyleniem w planie mapy, więc tory wpisane ku sobie spotykają się na tej samej przechyłce. Na rozjazdach tylko ta wynikająca z fal, bez osobnego siadania toków. -Za nierównością idą szyny, podsypka, `sleepermodel`, osie, przechył pudła i bujanie kabiny. +Za nierównością idą szyny, wierzch podsypki, `sleepermodel`, osie, przechył pudła i bujanie kabiny. Skarpa podsypki przejmuje różnicę, a jej spód zostaje w projekcie, na terenie. Nie idą za nią modele z includów (np. napędy i podkłady rozjazdów), teren ani sieć trakcyjna, więc przy dużych wartościach szyna rozjeżdża się z takim modelem o kilka centymetrów. diff --git a/world/Segment.cpp b/world/Segment.cpp index 84a0c22b..3668ed13 100644 --- a/world/Segment.cpp +++ b/world/Segment.cpp @@ -408,11 +408,12 @@ void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origi if( false == m_uneven ) { return; } - // the rails settling apart turn about the middle of the track, what's outside them follows the rail + // the rails settling apart turn about the middle of the track, what's outside them follows the rail; the foot of the ballast stays auto const gauge { std::max( std::abs( pOwner->fTrackWidth ), 0.1f ) }; auto const across { std::clamp( glm::dot( Vertex.position - Position, Parallel ), -0.5f * gauge, 0.5f * gauge ) }; - Vertex.position.y -= static_cast( track_uneven::stray_per_mm * pOwner->uneven_at( Distance ).cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge ); - Vertex.position += glm::vec3 { stray( Origin + glm::dvec3 { Vertex.position }, Distance ) }; + auto const share { pOwner->uneven_bed_share( Position.y - Vertex.position.y ) }; + Vertex.position.y -= static_cast( share * track_uneven::stray_per_mm * pOwner->uneven_at( Distance ).cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge ); + Vertex.position += glm::vec3 { share * stray( Origin + glm::dvec3 { Vertex.position }, Distance ) }; } void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const { diff --git a/world/Track.cpp b/world/Track.cpp index ff5a378a..b5589eed 100644 --- a/world/Track.cpp +++ b/world/Track.cpp @@ -731,6 +731,11 @@ bool TTrack::is_uneven() const { return declared.up > 0.0 || declared.side > 0.0 || declared.cross > 0.0 || joint_depth() > 0.0; } +double TTrack::uneven_bed_share( double const Depth ) const { + + return track_uneven::bed_share( Depth, std::abs( track_rail_profile( m_profile1.second ).front().position.y ), fTexHeight1 ); +} + track_uneven::amounts TTrack::uneven_at( double const Distance ) const { if( eType == tt_Switch ) { diff --git a/world/Track.h b/world/Track.h index ac6d1425..92516ee6 100644 --- a/world/Track.h +++ b/world/Track.h @@ -351,6 +351,8 @@ public: bool is_uneven() const; // the unevenness at a distance along the track, meeting the tracks joined at its ends track_uneven::amounts uneven_at( double const Distance ) const; + // how much of the displacement a point of the profile at the depth takes + double uneven_bed_share( double const Depth ) const; double joint_depth() const; // mm double joint_dip( double const Distance ) const; // m // distance from the rail joint behind; negative: the track has no joints that dip diff --git a/world/TrackUneven.h b/world/TrackUneven.h index 9031c6ca..182f3799 100644 --- a/world/TrackUneven.h +++ b/world/TrackUneven.h @@ -109,6 +109,13 @@ inline double along( double const Full, double const Atstart, double const Atend return ends + ( Full - ends ) * std::min( smooth( Distance / fade ), smooth( ( Length - Distance ) / fade ) ); } +// how much of the displacement a point of the profile takes, by its depth under the rail top: all of it down to the foot of the rail, +// none at the foot of the ballast, which stays on the ground as designed +inline double bed_share( double const Depth, double const Rail, double const Height ) { + + return Height > 0.0 ? std::clamp( 1.0 - ( Depth - Rail ) / Height, 0.0, 1.0 ) : 1.0; +} + // distance from the joint behind the point inline double rail_phase( double const Along, double const Rail ) {