17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-08 17:26:22 +01:00

feat(track): track unevenness declared in the track entry

Usage, optional attributes of a track entry, before endtrack:

  uneven <mm>       peak deviation of a rail on a 10 m chord, 0-100; normal and switch
  unevenup <mm>     up and down alone, instead of uneven; normal and switch
  unevenside <mm>   sideways alone, instead of uneven; normal and switch
  unevencross <mm>  cross level alone, instead of uneven; normal only
  jointdip <mm>     depth of the dip at rail joints, every sound distance; normal only,
                    default 0.4 of the up and down component

Values of uneven follow PLK Id-14 appendix 1: 6 mm is the limit at 160 km/h, 10 at 120,
18 at 80, 35 at 40; half of it for a track in a good state. Example:

  uneven 18
  unevencross 25
  jointdip 6
  endtrack

The same fields are in the editor, track panel, section Ride and sound. See
track_uneven_doc.md.

The unevenness is a displacement field over the plan of the scenery, with no random
numbers: one place strays the same every time, and joined tracks, the paths of a switch,
sleepermodel and axles at one place move together. Tracks meet at a joint at the lower of
their values. Joined switches take the lowest of theirs, the tracks joined to them come to
it, and a track with none of a component keeps the switch to its design in it. The clatter
comes from the dipping joints. Curve radius and grade for the physics stay as designed.

Tracks with it get geometry every 2 m on straights: 4x the vertices on Baltyk with all
tracks flagged, 0.2 ms more per frame on td.scn.
This commit is contained in:
maj00r
2026-10-31 15:47:10 +01:00
parent 66a940d4f5
commit e5266e1e6b
15 changed files with 774 additions and 4 deletions

View File

@@ -118,6 +118,10 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
fStoop = std::atan2(Point2.y - Point1.y, fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
fStep = fNewStep;
if( m_uneven && pOwner->eType != tt_Switch ) {
// dense enough for the waves; a switch keeps its division, the blades depend on it
fStep = std::min( fStep, 2.0 );
}
// NOTE: optionally replace this part with the commented version, after solving geometry issues with double switches
if( pOwner->eType == tt_Switch
&& fStep * (3.0 * Global.SplineFidelity) > fLength ) {
@@ -366,6 +370,52 @@ Math3D::vector3 TSegment::GetPoint(double const fDistance) const
*/
void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
design_position( fDistance, position, rotation );
if( false == m_uneven ) {
return;
}
// direction and slope stay as designed: the physics takes the curve radius and the grade from them
auto const gauge { std::max( std::abs( pOwner->fTrackWidth ), 0.1f ) };
glm::dvec3 const across { -std::cos( rotation.z ), 0.0, -std::sin( rotation.z ) };
auto const amount { pOwner->uneven_at( fDistance ) };
rotation.x += static_cast<float>( track_uneven::stray_per_mm * (
amount.up * track_uneven::roll( position, across, gauge )
+ amount.cross * track_uneven::level( position ) / gauge ) );
position += stray( position, fDistance );
}
glm::dvec3 TSegment::stray( glm::dvec3 const &Point, double const Distance ) const {
auto const amount { pOwner->uneven_at( Distance ) };
auto const field { track_uneven::field( Point ) };
glm::dvec3 result { field.x * amount.side, field.y * amount.up, field.z * amount.side };
result *= track_uneven::stray_per_mm;
result.y -= pOwner->joint_dip( Distance );
return result;
}
glm::dvec3 TSegment::uneven_bend( double const Distance ) const {
if( false == m_uneven ) {
return glm::dvec3 { 0.0 };
}
// over about a bogie; FastGetTFromS extrapolates past the ends of the path
auto const reach { 1.5 };
auto const strayed = [&]( double const At ) {
return stray( FastGetPoint( FastGetTFromS( At ) ), At ); };
return ( strayed( Distance + reach ) - 2.0 * strayed( Distance ) + strayed( Distance - reach ) ) / ( reach * reach );
}
void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origin, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const {
if( false == m_uneven ) {
return;
}
// the rails settling apart turn about the middle of the track, what's outside them follows the rail
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<float>( track_uneven::stray_per_mm * pOwner->uneven_at( Distance ).cross * track_uneven::level( Origin + glm::dvec3 { Position } ) * across / gauge );
Vertex.position += glm::vec3 { stray( Origin + glm::dvec3 { Vertex.position }, Distance ) };
}
void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
if (bCurve) {
// można by wprowadzić uproszczony wzór dla okręgów płaskich
auto const t = FastGetTFromS(fDistance); // aproksymacja dystansu na krzywej Beziera na parametr (t)
@@ -500,6 +550,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
pt,
glm::normalize( norm ),
glm::vec2 { ( jmm1 * ShapePoints[ j ].texture.x + m1 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv1 } );
settle_vertex( Output.back(), Origin, pos1, parallel1, s - step );
}
// jeśli jest wskaźnik do tablicy
if (p && *p && !j) // to dla pierwszego punktu
@@ -518,6 +569,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
pt,
glm::normalize( norm ),
glm::vec2 { ( jmm2 * ShapePoints[ j ].texture.x + m2 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv2 } );
settle_vertex( Output.back(), Origin, pos2, parallel2, s );
}
// jeśli jest wskaźnik do tablicy
// to dla pierwszego punktu
@@ -540,6 +592,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
pt,
glm::normalize( norm ),
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } );
settle_vertex( Output.back(), Origin, pos1, parallel1, s - step );
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m2 * ( ShapePoints[ j ].position.x - fOffsetX.second ) ) + pos2;
pt.y += ShapePoints[ j ].position.y;
@@ -550,6 +603,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
pt,
glm::normalize( norm ),
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv2 } );
settle_vertex( Output.back(), Origin, pos2, parallel2, s );
}
}
}