mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-01 01:09:04 +01:00
fix(track): the ends of joined paths meet, in place and in cant
Ends less than 20 cm apart meet in the middle with a common vector across, which closes the cracks from coordinates that don't match in the data, on tracks with no unevenness as well. At such a joint a switch takes the cant of the plain track, and alike ones meet halfway: the slips on Baltyk had steps of 0.2 degrees. The physics goes by the same cant.
This commit is contained in:
@@ -60,6 +60,8 @@ 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.
|
||||
|
||||
Końce złączonych dróg spotykają się w środku między sobą, z jednym kierunkiem poprzecznym, jeśli są bliżej niż 20 cm, co zamyka pęknięcia z niezgodnych współrzędnych w danych, także na torach bez nierówności. Przechyłkę na takim styku rozjazd bierze od zwykłego toru, a dwa tory albo dwa rozjazdy spotykają się w połowie. To dotyczy też fizyki.
|
||||
|
||||
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.
|
||||
|
||||
@@ -69,6 +69,10 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
|
||||
// poprawienie przechyłki
|
||||
fRoll1 = static_cast<float>(glm::radians(fNewRoll1)); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = static_cast<float>(glm::radians(fNewRoll2));
|
||||
m_designrolls[ 0 ] = fRoll1;
|
||||
m_designrolls[ 1 ] = fRoll2;
|
||||
m_joints[ 0 ].reset();
|
||||
m_joints[ 1 ].reset();
|
||||
bCurve = bIsCurve;
|
||||
if (Global.bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
@@ -441,6 +445,18 @@ void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm
|
||||
}
|
||||
};
|
||||
|
||||
void TSegment::plan_frame( double const Distance, glm::dvec3 &Point, glm::dvec3 &Across ) const {
|
||||
auto const t { FastGetTFromS( std::clamp( Distance, 0.0, fLength ) ) };
|
||||
Point = FastGetPoint( t );
|
||||
auto const dir { FastGetDirection( t, 0.1 / fLength ) };
|
||||
Across = glm::dvec3{ -dir.z, 0.0, dir.x };
|
||||
if( glm::length2( Across ) == 0.0 ) {
|
||||
auto const chord { FastGetPoint_1() - FastGetPoint_0() };
|
||||
Across = glm::dvec3{ -chord.z, 0.0, chord.x };
|
||||
}
|
||||
Across = glm::normalize( Across );
|
||||
}
|
||||
|
||||
glm::dvec3 TSegment::FastGetPoint(double const t) const
|
||||
{
|
||||
// return (bCurve?std::lerp(t,Point1,CPointOut,CPointIn,Point2):((1.0-t)*Point1+(t)*Point2));
|
||||
@@ -492,6 +508,10 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
parallel1 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
|
||||
}
|
||||
parallel1 = glm::normalize( parallel1 );
|
||||
if( iSkip == 0 && m_joints[ 0 ] ) {
|
||||
pos1 = glm::vec3{ m_joints[ 0 ]->first - Origin };
|
||||
parallel1 = glm::vec3{ m_joints[ 0 ]->second };
|
||||
}
|
||||
if( iEnd == 0 )
|
||||
iEnd = iSegCount;
|
||||
fEnd = static_cast<float>(fLength * double( iEnd ) / double( iSegCount ));
|
||||
@@ -537,6 +557,10 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
parallel2 = glm::vec3{ glm::dvec3{ FastGetPoint_1() - FastGetPoint_0() } };
|
||||
}
|
||||
parallel2 = glm::normalize( parallel2 );
|
||||
if( i == iSegCount && m_joints[ 1 ] ) {
|
||||
pos2 = glm::vec3{ m_joints[ 1 ]->first - Origin };
|
||||
parallel2 = glm::vec3{ m_joints[ 1 ]->second };
|
||||
}
|
||||
|
||||
// TODO: refactor the loop, there's no need to calculate starting points for each segment when we can copy the end points of the previous one
|
||||
if( Transition ) {
|
||||
|
||||
@@ -9,6 +9,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "utilities/Classes.h"
|
||||
#include "rendering/geometrybank.h"
|
||||
#include <glm/glm.hpp>
|
||||
@@ -47,6 +49,9 @@ class TSegment
|
||||
glm::dvec3 Point2;
|
||||
float fRoll1 { 0.f };
|
||||
float fRoll2 { 0.f }; // przechyłka na końcach
|
||||
float m_designrolls[ 2 ] { 0.f, 0.f }; // as entered; the two above can differ at a joint
|
||||
// where the path meets the next one: the middle of their ends and their common vector across
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> m_joints[ 2 ];
|
||||
bool m_uneven { false }; // see TrackUneven.h
|
||||
double fLength { -1.0 }; // długość policzona
|
||||
std::vector<double> fTsBuffer; // wartości parametru krzywej t dla równych odcinków s
|
||||
@@ -117,6 +122,16 @@ public:
|
||||
void
|
||||
set_uneven( bool const Uneven ) {
|
||||
m_uneven = Uneven; }
|
||||
// a point of the path and the unit vector across it in the plan
|
||||
void
|
||||
plan_frame( double const Distance, glm::dvec3 &Point, glm::dvec3 &Across ) const;
|
||||
float
|
||||
design_roll( int const End ) const {
|
||||
return m_designrolls[ End ]; }
|
||||
void
|
||||
set_joint( int const End, std::optional<std::pair<glm::dvec3, glm::dvec3>> const &Joint, float const Roll ) {
|
||||
m_joints[ End ] = Joint;
|
||||
( End == 0 ? fRoll1 : fRoll2 ) = Roll; }
|
||||
// second derivative of the displacement along the path; times speed squared: acceleration of an axle
|
||||
glm::dvec3
|
||||
uneven_bend( double const Distance ) const;
|
||||
|
||||
@@ -1561,8 +1561,72 @@ void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
create_geometry( Bank );
|
||||
}
|
||||
|
||||
void TTrack::share_joints() {
|
||||
|
||||
int const paths { eType == tt_Switch ? 2 : 1 };
|
||||
auto const segment_of = []( TTrack const &Track, int const Path ) -> TSegment * {
|
||||
return ( Track.eType == tt_Switch ? Track.SwitchExtension->Segments[ Path ].get() : Track.Segment.get() ); };
|
||||
for( int path = 0; path < paths; ++path ) {
|
||||
auto *segment { segment_of( *this, path ) };
|
||||
if( segment == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> joint;
|
||||
auto roll { segment->design_roll( end ) };
|
||||
auto const *neighbour { eType == tt_Switch ?
|
||||
( end ? SwitchExtension->pNexts[ path ] : SwitchExtension->pPrevs[ path ] ) :
|
||||
( end ? trNext : trPrev ) };
|
||||
if( neighbour != nullptr && neighbour != this && ( neighbour->iCategoryFlag & 15 ) == ( iCategoryFlag & 15 ) ) {
|
||||
glm::dvec3 point;
|
||||
glm::dvec3 across;
|
||||
segment->plan_frame( end ? segment->GetLength() : 0.0, point, across );
|
||||
auto closest { 0.2 };
|
||||
for( int theirpath = 0; theirpath < ( neighbour->eType == tt_Switch ? 2 : 1 ); ++theirpath ) {
|
||||
auto const *theirs { segment_of( *neighbour, theirpath ) };
|
||||
if( theirs == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
for( int theirend = 0; theirend < 2; ++theirend ) {
|
||||
glm::dvec3 theirpoint;
|
||||
glm::dvec3 theiracross;
|
||||
theirs->plan_frame( theirend ? theirs->GetLength() : 0.0, theirpoint, theiracross );
|
||||
if( theirend == end ) {
|
||||
theiracross = -theiracross;
|
||||
}
|
||||
auto const gap { glm::length( theirpoint - point ) };
|
||||
if( gap >= closest || glm::dot( across, theiracross ) < 0.9 ) {
|
||||
continue;
|
||||
}
|
||||
closest = gap;
|
||||
joint.emplace( 0.5 * ( point + theirpoint ), glm::normalize( across + theiracross ) );
|
||||
if( iCategoryFlag & 1 ) {
|
||||
// the cant of a plain track is what was designed, a switch takes it; alike ones meet halfway
|
||||
auto const own { segment->design_roll( end ) };
|
||||
auto const their { theirend == end ? -theirs->design_roll( theirend ) : theirs->design_roll( theirend ) };
|
||||
roll = (
|
||||
( eType == tt_Switch ) == ( neighbour->eType == tt_Switch ) ? 0.5f * ( own + their ) :
|
||||
eType == tt_Switch ? their :
|
||||
own );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
segment->set_joint( end, joint, roll );
|
||||
}
|
||||
}
|
||||
if( eType != tt_Switch && Segment && ( iCategoryFlag & 1 ) ) {
|
||||
float roll1, roll2;
|
||||
Segment->GetRolls( roll1, roll2 );
|
||||
if( roll1 != 0.f || roll2 != 0.f ) {
|
||||
iTrapezoid |= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
gfx::userdata_array empty_userdata;
|
||||
share_joints();
|
||||
// bake per-instance sleeper transforms now that the owning cell has assigned m_origin.
|
||||
// safe to call here even if the track has no sleepermodel (early-outs internally).
|
||||
if( m_sleeper_enabled && m_sleeper_local_transforms.empty() ) {
|
||||
@@ -3845,6 +3909,11 @@ path_table::InitTracks() {
|
||||
isolated = isolated->Next();
|
||||
}
|
||||
|
||||
// the physics goes by the cant at the joints too, and comes before any geometry is made
|
||||
for( auto *track : m_items ) {
|
||||
track->share_joints();
|
||||
}
|
||||
|
||||
TTrack::fetch_default_profiles();
|
||||
}
|
||||
|
||||
|
||||
@@ -353,6 +353,8 @@ public:
|
||||
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;
|
||||
// closes the gaps and steps of cant between the ends of joined paths
|
||||
void share_joints();
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user