mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-11 00:35:16 +01:00
Merge branch 'master' into feat/renderers-cleanup
This commit is contained in:
@@ -81,10 +81,8 @@ 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();
|
||||
m_setting.designrolls = { fRoll1, fRoll2 };
|
||||
m_setting.joints = {};
|
||||
bCurve = bIsCurve;
|
||||
if (Global.bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
@@ -139,7 +137,7 @@ 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 > 0.0 && std::isfinite( fNewStep ) ) ? fNewStep : fLength;
|
||||
if( m_uneven && pOwner->eType != tt_Switch ) {
|
||||
if( m_setting.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 );
|
||||
}
|
||||
@@ -179,8 +177,8 @@ bool TSegment::InitChain(std::vector<std::shared_ptr<TSegment>> Pieces)
|
||||
Point2 = last.Point2;
|
||||
fRoll1 = first.fRoll1;
|
||||
fRoll2 = last.fRoll2;
|
||||
m_designrolls[ 0 ] = first.m_designrolls[ 0 ];
|
||||
m_designrolls[ 1 ] = last.m_designrolls[ 1 ];
|
||||
m_setting.designrolls[ 0 ] = first.m_setting.designrolls[ 0 ];
|
||||
m_setting.designrolls[ 1 ] = last.m_setting.designrolls[ 1 ];
|
||||
bCurve = true;
|
||||
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
|
||||
fStoop = std::atan2(Point2.y - Point1.y, fLength);
|
||||
@@ -435,21 +433,6 @@ 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, m_path ) };
|
||||
rotation.x += static_cast<float>( track_uneven::stray_per_mm * (
|
||||
amount.up * track_uneven::roll( position, across, gauge )
|
||||
+ amount.cross * track_uneven::level( position, across ) / gauge ) );
|
||||
position += track_uneven::across_only( stray( position, amount, fDistance ), across );
|
||||
}
|
||||
|
||||
glm::dvec3 TSegment::stray( glm::dvec3 const &Point, track_uneven::amounts const &Amount, double const Distance ) const {
|
||||
auto const field { track_uneven::field( Point ) };
|
||||
glm::dvec3 result { field.x * Amount.side, field.y * Amount.up, field.z * Amount.side };
|
||||
@@ -459,30 +442,25 @@ glm::dvec3 TSegment::stray( glm::dvec3 const &Point, track_uneven::amounts const
|
||||
}
|
||||
|
||||
glm::dvec3 TSegment::uneven_bend( double const Distance ) const {
|
||||
if( false == m_uneven ) {
|
||||
if( false == m_setting.uneven ) {
|
||||
return glm::dvec3 { 0.0 };
|
||||
}
|
||||
// over about a bogie
|
||||
auto const reach { 1.5 };
|
||||
auto const strayed = [&]( double const At ) {
|
||||
return stray( point_extended( At ), pOwner->uneven_at( At, m_path ), At ); };
|
||||
auto const strayed = [ this ]( double const At ) {
|
||||
// past the ends of the path straight on: the polynomial would run off on a short curved one
|
||||
auto const on { std::clamp( At, 0.0, fLength ) };
|
||||
auto const t { FastGetTFromS( on ) };
|
||||
auto point { FastGetPoint( t ) };
|
||||
if( auto const direction { FastGetDirection( t, 0.1 / fLength ) }; on != At && glm::length( direction ) > 0.0 ) {
|
||||
point += direction * ( ( At - on ) / glm::length( direction ) );
|
||||
}
|
||||
return stray( point, pOwner->uneven_at( At, m_setting.path ), At ); };
|
||||
return ( strayed( Distance + reach ) - 2.0 * strayed( Distance ) + strayed( Distance - reach ) ) / ( reach * reach );
|
||||
}
|
||||
|
||||
glm::dvec3 TSegment::point_extended( double const Distance ) const {
|
||||
auto const on { std::clamp( Distance, 0.0, fLength ) };
|
||||
auto const t { FastGetTFromS( on ) };
|
||||
auto const point { FastGetPoint( t ) };
|
||||
if( on == Distance ) {
|
||||
return point;
|
||||
}
|
||||
auto const direction { FastGetDirection( t, 0.1 / fLength ) };
|
||||
auto const size { glm::length( direction ) };
|
||||
return size > 0.0 ? point + direction * ( ( Distance - on ) / size ) : point;
|
||||
}
|
||||
|
||||
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 ) {
|
||||
if( false == m_setting.uneven ) {
|
||||
return;
|
||||
}
|
||||
// the rails settling apart turn about the middle of the track, what's outside them follows the rail; the foot of the ballast stays
|
||||
@@ -492,12 +470,12 @@ void TSegment::settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origi
|
||||
if( share <= 0.0 ) {
|
||||
return;
|
||||
}
|
||||
auto const amount { pOwner->uneven_at( Distance, m_path ) };
|
||||
auto const amount { pOwner->uneven_at( Distance, m_setting.path ) };
|
||||
Vertex.position.y -= static_cast<float>( share * track_uneven::stray_per_mm * amount.cross * track_uneven::level( Origin + glm::dvec3 { Position }, glm::dvec3 { Parallel } ) * across / gauge );
|
||||
Vertex.position += glm::vec3 { share * stray( Origin + glm::dvec3 { Vertex.position }, amount, Distance ) };
|
||||
}
|
||||
|
||||
void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
|
||||
void TSegment::RaPositionGet(double const fDistance, glm::dvec3 &position, glm::vec3 &rotation) const {
|
||||
if( false == m_pieces.empty() ) {
|
||||
// the pieces keep to their design, the unevenness is the one of the whole path
|
||||
auto const piece { piece_at( fDistance ) };
|
||||
@@ -525,6 +503,17 @@ void TSegment::design_position(double const fDistance, glm::dvec3 &position, glm
|
||||
rotation.y = static_cast<float>(fStoop); // pochylenie toru prostego
|
||||
rotation.z = static_cast<float>(fDirection); // kierunek toru w planie
|
||||
}
|
||||
if( false == m_setting.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, m_setting.path ) };
|
||||
rotation.x += static_cast<float>( track_uneven::stray_per_mm * (
|
||||
amount.up * track_uneven::roll( position, across, gauge )
|
||||
+ amount.cross * track_uneven::level( position, across ) / gauge ) );
|
||||
position += track_uneven::across_only( stray( position, amount, fDistance ), across );
|
||||
};
|
||||
|
||||
glm::dvec3 TSegment::FastGetPoint(double const t) const
|
||||
@@ -584,9 +573,9 @@ 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( iSkip == 0 && m_setting.joints[ 0 ] ) {
|
||||
pos1 = glm::vec3{ m_setting.joints[ 0 ]->first - Origin };
|
||||
parallel1 = glm::vec3{ m_setting.joints[ 0 ]->second };
|
||||
}
|
||||
if( iEnd == 0 )
|
||||
iEnd = iSegCount;
|
||||
@@ -633,9 +622,9 @@ 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 };
|
||||
if( i == iSegCount && m_setting.joints[ 1 ] ) {
|
||||
pos2 = glm::vec3{ m_setting.joints[ 1 ]->first - Origin };
|
||||
parallel2 = glm::vec3{ m_setting.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
|
||||
@@ -749,13 +738,13 @@ bool TSegment::RenderLoftSteps( gfx::vertex_array &Output, glm::dvec3 const &Ori
|
||||
auto const offset { 0.1 / fLength };
|
||||
// point and the unit vector across the path at the k-th of the Steps stations
|
||||
auto const station = [&]( int const k, glm::vec3 &Position, glm::vec3 &Parallel ) {
|
||||
if( k == 0 && m_joints[ 0 ] ) {
|
||||
Position = glm::vec3{ m_joints[ 0 ]->first - Origin };
|
||||
Parallel = glm::vec3{ m_joints[ 0 ]->second };
|
||||
if( k == 0 && m_setting.joints[ 0 ] ) {
|
||||
Position = glm::vec3{ m_setting.joints[ 0 ]->first - Origin };
|
||||
Parallel = glm::vec3{ m_setting.joints[ 0 ]->second };
|
||||
return; }
|
||||
if( k == Steps && m_joints[ 1 ] ) {
|
||||
Position = glm::vec3{ m_joints[ 1 ]->first - Origin };
|
||||
Parallel = glm::vec3{ m_joints[ 1 ]->second };
|
||||
if( k == Steps && m_setting.joints[ 1 ] ) {
|
||||
Position = glm::vec3{ m_setting.joints[ 1 ]->first - Origin };
|
||||
Parallel = glm::vec3{ m_setting.joints[ 1 ]->second };
|
||||
return; }
|
||||
auto const t { k == 0 ? 0.0 : k == Steps ? 1.0 : FastGetTFromS( fLength * k / Steps ) };
|
||||
Position = glm::vec3{ FastGetPoint( t ) - Origin };
|
||||
@@ -957,7 +946,7 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
glm::dvec3 point;
|
||||
glm::dvec3 across;
|
||||
plan_frame( Distance, point, across );
|
||||
if( auto const &joint { m_joints[ Distance < 0.001 ? 0 : 1 ] }; joint && ( Distance < 0.001 || Distance > fLength - 0.001 ) ) {
|
||||
if( auto const &joint { m_setting.joints[ Distance < 0.001 ? 0 : 1 ] }; joint && ( Distance < 0.001 || Distance > fLength - 0.001 ) ) {
|
||||
point = joint->first;
|
||||
across = joint->second;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "utilities/Classes.h"
|
||||
#include "rendering/geometrybank.h"
|
||||
@@ -103,11 +105,15 @@ 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
|
||||
bool m_uneven { false }; // see TrackUneven.h
|
||||
int m_path { 0 }; // which path of a switch
|
||||
// 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 ];
|
||||
// how the path sits among the others
|
||||
struct setting {
|
||||
std::array<float, 2> designrolls { 0.f, 0.f }; // as entered; fRoll1 and fRoll2 can differ at a joint
|
||||
bool uneven { false }; // see TrackUneven.h
|
||||
int path { 0 }; // which path of a switch
|
||||
// where the path meets the next one: the middle of their ends and their common vector across
|
||||
std::array<std::optional<std::pair<glm::dvec3, glm::dvec3>>, 2> joints;
|
||||
};
|
||||
setting m_setting;
|
||||
double fLength { -1.0 }; // długość policzona
|
||||
std::vector<double> fTsBuffer; // wartości parametru krzywej t dla równych odcinków s
|
||||
std::vector<double> fTsSlope; // nachylenie dt/du (= dt/ds * fStep) w tych samych punktach
|
||||
@@ -141,9 +147,6 @@ class TSegment
|
||||
void settle_vertex( gfx::basic_vertex &Vertex, glm::dvec3 const &Origin, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const;
|
||||
// displacement of a point by the unevenness, at a distance along the path
|
||||
glm::dvec3 stray( glm::dvec3 const &Point, track_uneven::amounts const &Amount, double const Distance ) const;
|
||||
// a point of the path at a distance, past its ends straight on: the polynomial would run off on a short curved path
|
||||
glm::dvec3 point_extended( double const Distance ) const;
|
||||
void design_position( double const fDistance, glm::dvec3 &position, glm::vec3 &rotation ) const;
|
||||
|
||||
public:
|
||||
bool bCurve = false;
|
||||
@@ -196,17 +199,14 @@ public:
|
||||
// call before Init, it sets the density of the geometry
|
||||
void
|
||||
set_uneven( bool const Uneven, int const Path = 0 ) {
|
||||
m_uneven = Uneven;
|
||||
m_path = Path; }
|
||||
glm::dvec3
|
||||
end_point( int const End ) const {
|
||||
return End == 0 ? Point1 : Point2; }
|
||||
m_setting.uneven = Uneven;
|
||||
m_setting.path = Path; }
|
||||
float
|
||||
design_roll( int const End ) const {
|
||||
return m_designrolls[ End ]; }
|
||||
return m_setting.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;
|
||||
m_setting.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
|
||||
|
||||
@@ -31,6 +31,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/Logs.h"
|
||||
#include "rendering/renderer.h"
|
||||
|
||||
#include <format>
|
||||
|
||||
// 101206 Ra: trapezoidalne drogi i tory
|
||||
// 110720 Ra: rozprucie zwrotnicy i odcinki izolowane
|
||||
|
||||
@@ -433,7 +435,6 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
std::string str;
|
||||
size_t i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie
|
||||
std::string token;
|
||||
bool tributary{false};
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> str; // typ toru
|
||||
@@ -475,17 +476,15 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
}
|
||||
else if (str == "tributary")
|
||||
{
|
||||
ErrorLog("Bad track: type \"tributary\" of track \"" + m_name + "\" in file \"" + parser->Name() + "\" (line " + std::to_string(parser->Line()) + ") isn't supported, loaded as a river with its first path");
|
||||
// dopływ: no path of it was ever made, the simulator falling over it as it loaded. a river of its first path now, the
|
||||
// second one kept and written back
|
||||
ErrorLog(std::format("Bad track: tributary \"{}\" in file \"{}\" (line {}) is drawn and run on as a river of its first path", m_name, parser->Name(), parser->Line()));
|
||||
eType = tt_Normal;
|
||||
iCategoryFlag = 4;
|
||||
tributary = true;
|
||||
m_tributary = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorLog("Bad track: unknown type \"" + str + "\" of track \"" + m_name + "\" in file \"" + parser->Name() + "\" (line " + std::to_string(parser->Line()) + "), loaded as a normal track");
|
||||
eType = tt_Normal;
|
||||
iCategoryFlag = 1;
|
||||
}
|
||||
eType = tt_Unknown; // left out by the loader
|
||||
if (Global.iWriteLogEnabled & 4)
|
||||
WriteLog(str);
|
||||
parser->getTokens(4);
|
||||
@@ -558,10 +557,6 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
// all subtypes contain at least one path
|
||||
m_paths.emplace_back();
|
||||
m_paths.back().deserialize( *parser, pOrigin );
|
||||
if( tributary ) {
|
||||
segment_data ignored;
|
||||
ignored.deserialize( *parser, pOrigin );
|
||||
}
|
||||
switch( eType ) {
|
||||
case tt_Switch:
|
||||
case tt_Cross:
|
||||
@@ -575,6 +570,11 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( m_tributary ) {
|
||||
// the second path of a tributary, kept to be written back
|
||||
m_paths.emplace_back();
|
||||
m_paths.back().deserialize( *parser, pOrigin );
|
||||
}
|
||||
|
||||
// optional attributes
|
||||
parser->getTokens();
|
||||
@@ -813,6 +813,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
m_name = m_name.substr(0, i - 1); // usunięcie z nazwy
|
||||
}
|
||||
|
||||
if( CurrentSegment() == nullptr ) {
|
||||
// of an unknown type, no path of it is made
|
||||
return;
|
||||
}
|
||||
update_location();
|
||||
// sleeper transforms are baked later in create_geometry(), once the owning cell has
|
||||
// assigned this track its m_origin (otherwise the local-space matrices would be relative
|
||||
@@ -1530,7 +1534,7 @@ glm::vec3 TTrack::get_nearest_point(const glm::dvec3 &point) const
|
||||
// wypełnianie tablic VBO
|
||||
void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
++s_layoutstamp;
|
||||
m_drawnrun = {};
|
||||
|
||||
track_rails::forget();
|
||||
auto const erase = [ this ]( gfx::geometry_handle const &Chunk ) {
|
||||
@@ -1576,6 +1580,9 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
}
|
||||
share_joints();
|
||||
m_sleepers3d.active = track_sleepers::lays( *this );
|
||||
if( rail_phase( 0.0 ) >= 0.0 ) {
|
||||
m_drawnrun = m_railrun;
|
||||
}
|
||||
// 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).
|
||||
// a track laying the 3D sleepers draws its sleeper model with them, the transforms of the model alone wouldn't be drawn
|
||||
@@ -2648,24 +2655,37 @@ TTrack::deserialize_( std::istream &Input ) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
// the keyword the track is written with, by its type and for a plain one by what runs on it
|
||||
char const *
|
||||
TTrack::type_keyword() const {
|
||||
|
||||
if( eType == tt_Normal && m_tributary ) {
|
||||
return "tributary";
|
||||
}
|
||||
if( eType == tt_Normal ) {
|
||||
switch( iCategoryFlag & 15 ) {
|
||||
case 1: { return "normal"; }
|
||||
case 2: { return "road"; }
|
||||
case 4: { return "river"; }
|
||||
default: { return "none"; }
|
||||
}
|
||||
}
|
||||
switch( eType ) {
|
||||
case tt_Switch: { return "switch"; }
|
||||
case tt_Cross: { return "cross"; }
|
||||
case tt_Table: { return "turn"; }
|
||||
case tt_Tributary: { return "tributary"; }
|
||||
default: { return "none"; }
|
||||
}
|
||||
}
|
||||
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
// header
|
||||
Output << "track ";
|
||||
// type
|
||||
Output << (
|
||||
eType == tt_Normal ? (
|
||||
( iCategoryFlag & 15 ) == 1 ? "normal" :
|
||||
( iCategoryFlag & 15 ) == 2 ? "road" :
|
||||
( iCategoryFlag & 15 ) == 4 ? "river" :
|
||||
"none" ) :
|
||||
eType == tt_Switch ? "switch" :
|
||||
eType == tt_Cross ? "cross" :
|
||||
eType == tt_Table ? "turn" :
|
||||
eType == tt_Tributary ? "tributary" :
|
||||
"none" )
|
||||
<< ' ';
|
||||
Output << type_keyword() << ' ';
|
||||
// basic attributes
|
||||
Output
|
||||
<< Length() << ' '
|
||||
|
||||
@@ -220,6 +220,7 @@ public:
|
||||
std::vector<TTrack *> m_crossings; // tracks whose rails cross the rails of this one, found when its geometry was made
|
||||
track_rails::rail_plan m_railplans[ 2 ][ 2 ]; // the cuts of its rails, by path and right side, as its geometry was made
|
||||
std::vector<glm::dvec2> m_railguards[ 2 ][ 2 ]; // the guard rails inside its rails at the crossings at wide angles, from and to along the path, as its geometry was made
|
||||
bool m_tributary { false }; // loaded as a tributary: a river of its first path, the second one kept to be written back
|
||||
scene::basic_node *m_road { nullptr }; // road or road junction which generated this path. such path is one-way, and isn't saved nor edited on its own
|
||||
std::array<float, 3> m_routeweights { 0.f, 0.f, 0.f }; // odds of each route through a crossroads being picked by a driver, by the number of the route. all zero: even odds
|
||||
int iterate_stamp = 0;
|
||||
@@ -415,16 +416,22 @@ public:
|
||||
// the unevenness the track declares, on a path of a switch
|
||||
track_uneven::amounts uneven_declared( int const Path = 0 ) const;
|
||||
bool is_uneven() const;
|
||||
// the unevenness along what the vehicles take now: the path set on a switch, with what the switches joined and the tracks by them allow
|
||||
track_uneven::amounts uneven_underway();
|
||||
// the unevenness at a distance along a path, meeting the tracks joined at its ends
|
||||
track_uneven::amounts uneven_at( double const Distance, int const Path = 0 ) const;
|
||||
track_uneven::amounts uneven_at( double const Distance, int const Path = 0 );
|
||||
// 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
|
||||
double joint_dip( double const Distance ); // m
|
||||
// distance from the rail joint behind; negative: the track has no joints that dip
|
||||
double rail_phase( double const Distance ) const;
|
||||
double rail_phase( double const Distance );
|
||||
// whether the rail joints are elsewhere than the geometry of the track has them
|
||||
bool rail_joints_moved();
|
||||
// the uneven tracks whose values go by the switches among the given: all the switches joined to those, and the tracks they meet
|
||||
static std::vector<TTrack *> switch_followers( std::vector<TTrack *> const &Tracks );
|
||||
void ConnectionsLog();
|
||||
bool DoubleSlip() const;
|
||||
static void fetch_default_profiles();
|
||||
@@ -443,6 +450,8 @@ private:
|
||||
void deserialize_( std::istream &Input );
|
||||
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
|
||||
void export_as_text_( std::ostream &Output ) const;
|
||||
// the keyword the track is written with, by its type and for a plain one by what runs on it
|
||||
char const *type_keyword() const;
|
||||
// locates specified profile in the profile database, potentially loading it from a file
|
||||
static std::pair<std::string, int> fetch_track_rail_profile( std::string const &Profile );
|
||||
// loads content of specified file and converts it into a vertex array
|
||||
@@ -463,8 +472,9 @@ private:
|
||||
double way { 1.0 }; // direction of the path along the run
|
||||
int stamp { -1 };
|
||||
};
|
||||
void settle_rail_run() const;
|
||||
mutable rail_run m_railrun;
|
||||
void settle_rail_run();
|
||||
rail_run m_railrun;
|
||||
rail_run m_drawnrun; // as the geometry has it; stamp -1: it has no joints that dip
|
||||
// the value along each path of a switch: the lowest of that path in the switches joined, 0 next to a track with none.
|
||||
// And at the ends of the paths, by what meets there: the other path at the common end, the path of a switch joined
|
||||
struct switch_stray {
|
||||
@@ -472,16 +482,17 @@ private:
|
||||
std::array<std::array<track_uneven::amounts, 2>, 2> ends;
|
||||
int stamp { -1 };
|
||||
};
|
||||
mutable switch_stray m_switchstray;
|
||||
switch_stray const &switch_uneven() const;
|
||||
void settle_switch_stray() const;
|
||||
switch_stray m_switchstray;
|
||||
switch_stray const &switch_uneven();
|
||||
void settle_switch_stray();
|
||||
void settle_switch_ends();
|
||||
// the lowest value of the paths ending at the point
|
||||
track_uneven::amounts switch_paths_at( glm::dvec3 const &Point ) const;
|
||||
// what a plain track comes to at its end, where it meets the other one
|
||||
track_uneven::amounts uneven_met( TTrack const *Other, glm::dvec3 const &Point ) const;
|
||||
track_uneven::amounts uneven_met( TTrack *Other, glm::dvec3 const &Point ) const;
|
||||
// the value of a switch where a track joined to it meets it
|
||||
track_uneven::amounts switch_uneven_at( glm::dvec3 const &Point ) const;
|
||||
static int s_layoutstamp; // bumped when tracks are joined or changed, invalidates the two above
|
||||
track_uneven::amounts switch_uneven_at( glm::dvec3 const &Point );
|
||||
static int s_layoutstamp; // bumped when tracks are joined or changed, invalidates the two above. Once per change: a run is walked again after each
|
||||
void create_road_profile( gfx::vertex_array &Output, bool const Forcetransition = false );
|
||||
void create_road_side_profile( gfx::vertex_array &Right, gfx::vertex_array &Left, gfx::vertex_array const &Road, bool const Forcetransition = false );
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "world/Track.h"
|
||||
|
||||
#include <span>
|
||||
|
||||
// The part of TTrack that goes with the unevenness of a track and with what it meets at its ends: joined tracks and switches.
|
||||
// The rules themselves are in TrackUneven.h, here they get applied to the tracks.
|
||||
|
||||
@@ -24,42 +26,55 @@ bool is_switch( TTrack const *Track ) {
|
||||
return Track != nullptr && Track->eType == tt_Switch && Track->SwitchExtension;
|
||||
}
|
||||
|
||||
std::array<TTrack const *, 4> joined_to_switch( TTrack const &Switch ) {
|
||||
glm::dvec3 end_point( TSegment const &Segment, int const End ) {
|
||||
|
||||
return End == 0 ? Segment.FastGetPoint_0() : Segment.FastGetPoint_1();
|
||||
}
|
||||
|
||||
std::array<TTrack *, 4> joined_to_switch( TTrack const &Switch ) {
|
||||
|
||||
auto const &extension { *Switch.SwitchExtension };
|
||||
return { extension.pPrevs[ 0 ], extension.pPrevs[ 1 ], extension.pNexts[ 0 ], extension.pNexts[ 1 ] };
|
||||
}
|
||||
|
||||
// the switch and the switches joined directly to it, and to those
|
||||
std::vector<TTrack const *> switch_group( TTrack const &Switch ) {
|
||||
std::vector<TTrack *> switch_group( TTrack &Switch ) {
|
||||
|
||||
std::vector<TTrack const *> group { &Switch };
|
||||
for( std::size_t index = 0; index < group.size(); ++index ) {
|
||||
for( auto const *other : joined_to_switch( *group[ index ] ) ) {
|
||||
if( is_switch( other ) && std::find( group.begin(), group.end(), other ) == group.end() ) {
|
||||
std::vector group { &Switch };
|
||||
std::vector pending { &Switch };
|
||||
while( false == pending.empty() ) {
|
||||
auto const *track { pending.back() };
|
||||
pending.pop_back();
|
||||
for( auto *other : joined_to_switch( *track ) ) {
|
||||
if( is_switch( other ) && std::ranges::find( group, other ) == group.end() ) {
|
||||
group.push_back( other );
|
||||
pending.push_back( other );
|
||||
}
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
// a plain track with none of a component keeps the switch to its design in it, any other comes to the value of the switch
|
||||
void keep_to_plain_track( std::array<track_uneven::amounts, 2> &Values, TTrack const &Plain ) {
|
||||
|
||||
auto const theirs { Plain.uneven_declared() };
|
||||
for( auto &path : Values ) {
|
||||
if( theirs.up <= 0.0 ) { path.up = 0.0; }
|
||||
if( theirs.side <= 0.0 ) { path.side = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
// the value along each path: the lowest of that path in the group, 0 in a component that a plain track joined has none of
|
||||
std::array<track_uneven::amounts, 2> group_path_values( std::vector<TTrack const *> const &Group ) {
|
||||
std::array<track_uneven::amounts, 2> group_path_values( std::span<TTrack * const> const Group ) {
|
||||
|
||||
std::array<track_uneven::amounts, 2> values { Group.front()->uneven_declared( 0 ), Group.front()->uneven_declared( 1 ) };
|
||||
for( auto const *track : Group ) {
|
||||
values[ 0 ] = track_uneven::least( values[ 0 ], track->uneven_declared( 0 ) );
|
||||
values[ 1 ] = track_uneven::least( values[ 1 ], track->uneven_declared( 1 ) );
|
||||
for( auto const *other : joined_to_switch( *track ) ) {
|
||||
if( other == nullptr || is_switch( other ) ) {
|
||||
continue;
|
||||
}
|
||||
// any other comes to the value of the switch
|
||||
auto const theirs { other->uneven_declared() };
|
||||
for( auto &path : values ) {
|
||||
if( theirs.up <= 0.0 ) { path.up = 0.0; }
|
||||
if( theirs.side <= 0.0 ) { path.side = 0.0; }
|
||||
if( other != nullptr && false == is_switch( other ) ) {
|
||||
keep_to_plain_track( values, *other );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +89,7 @@ track_uneven::amounts least_at_ends( TTrack const &Switch, glm::dvec3 const &Poi
|
||||
track_uneven::amounts result { track_uneven::most, track_uneven::most, track_uneven::most };
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
if( glm::length( Switch.path_segment( path )->end_point( end ) - Point ) < switch_end_reach ) {
|
||||
if( glm::length( end_point( *Switch.path_segment( path ), end ) - Point ) < switch_end_reach ) {
|
||||
result = track_uneven::least( result, Value( path, end ) );
|
||||
found = true;
|
||||
}
|
||||
@@ -160,21 +175,26 @@ bool TTrack::is_uneven() const {
|
||||
return any( uneven_declared( 0 ) ) || any( uneven_declared( 1 ) ) || joint_depth() > 0.0;
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_underway() {
|
||||
|
||||
return is_switch( this ) ? switch_uneven().paths[ SwitchExtension->CurrentIndex ] : uneven_declared();
|
||||
}
|
||||
|
||||
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, int const Path ) const {
|
||||
track_uneven::amounts TTrack::uneven_at( double const Distance, int const Path ) {
|
||||
|
||||
if( eType == tt_Switch ) {
|
||||
auto const &stray { switch_uneven() };
|
||||
return track_uneven::along( stray.paths[ Path ], stray.ends[ Path ][ 0 ], stray.ends[ Path ][ 1 ], Distance, path_segment( Path )->GetLength() );
|
||||
}
|
||||
return track_uneven::along( uneven_declared(), uneven_met( trPrev, Segment->end_point( 0 ) ), uneven_met( trNext, Segment->end_point( 1 ) ), Distance, Length() );
|
||||
return track_uneven::along( uneven_declared(), uneven_met( trPrev, end_point( *Segment, 0 ) ), uneven_met( trNext, end_point( *Segment, 1 ) ), Distance, Length() );
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::uneven_met( TTrack const *Other, glm::dvec3 const &Point ) const {
|
||||
track_uneven::amounts TTrack::uneven_met( TTrack *Other, glm::dvec3 const &Point ) const {
|
||||
|
||||
if( Other == nullptr ) {
|
||||
return {};
|
||||
@@ -182,7 +202,7 @@ track_uneven::amounts TTrack::uneven_met( TTrack const *Other, glm::dvec3 const
|
||||
return Other->eType == tt_Switch ? Other->switch_uneven_at( Point ) : track_uneven::least( uneven_declared(), Other->uneven_declared() );
|
||||
}
|
||||
|
||||
TTrack::switch_stray const &TTrack::switch_uneven() const {
|
||||
TTrack::switch_stray const &TTrack::switch_uneven() {
|
||||
|
||||
if( m_switchstray.stamp != s_layoutstamp ) {
|
||||
settle_switch_stray();
|
||||
@@ -190,26 +210,30 @@ TTrack::switch_stray const &TTrack::switch_uneven() const {
|
||||
return m_switchstray;
|
||||
}
|
||||
|
||||
void TTrack::settle_switch_stray() const {
|
||||
void TTrack::settle_switch_stray() {
|
||||
|
||||
auto const group { switch_group( *this ) };
|
||||
auto const values { group_path_values( group ) };
|
||||
for( auto const *track : group ) {
|
||||
for( auto *track : group ) {
|
||||
track->m_switchstray.paths = values;
|
||||
track->m_switchstray.stamp = s_layoutstamp;
|
||||
}
|
||||
// at the ends of the paths, with the paths known in all of the group
|
||||
for( auto const *track : group ) {
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
auto const point { track->path_segment( path )->end_point( end ) };
|
||||
auto value { track->switch_paths_at( point ) };
|
||||
auto const *other { track->path_neighbour( path, end ) };
|
||||
if( is_switch( other ) ) {
|
||||
value = track_uneven::least( value, other->switch_paths_at( point ) );
|
||||
}
|
||||
track->m_switchstray.ends[ path ][ end ] = value;
|
||||
// with the paths known in all of the group
|
||||
for( auto *track : group ) {
|
||||
track->settle_switch_ends();
|
||||
}
|
||||
}
|
||||
|
||||
void TTrack::settle_switch_ends() {
|
||||
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
auto const point { end_point( *path_segment( path ), end ) };
|
||||
auto value { switch_paths_at( point ) };
|
||||
if( auto const *other { path_neighbour( path, end ) }; is_switch( other ) ) {
|
||||
value = track_uneven::least( value, other->switch_paths_at( point ) );
|
||||
}
|
||||
m_switchstray.ends[ path ][ end ] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,13 +241,13 @@ void TTrack::settle_switch_stray() const {
|
||||
track_uneven::amounts TTrack::switch_paths_at( glm::dvec3 const &Point ) const {
|
||||
|
||||
auto const &paths { m_switchstray.paths };
|
||||
return least_at_ends( *this, Point, track_uneven::least( paths[ 0 ], paths[ 1 ] ), [ & ]( int const Path, int ) { return paths[ Path ]; } );
|
||||
return least_at_ends( *this, Point, track_uneven::least( paths[ 0 ], paths[ 1 ] ), [ &paths ]( int const Path, int ) { return paths[ Path ]; } );
|
||||
}
|
||||
|
||||
track_uneven::amounts TTrack::switch_uneven_at( glm::dvec3 const &Point ) const {
|
||||
track_uneven::amounts TTrack::switch_uneven_at( glm::dvec3 const &Point ) {
|
||||
|
||||
auto const &stray { switch_uneven() };
|
||||
return least_at_ends( *this, Point, track_uneven::least( stray.paths[ 0 ], stray.paths[ 1 ] ), [ & ]( int const Path, int const End ) { return stray.ends[ Path ][ End ]; } );
|
||||
return least_at_ends( *this, Point, track_uneven::least( stray.paths[ 0 ], stray.paths[ 1 ] ), [ &stray ]( int const Path, int const End ) { return stray.ends[ Path ][ End ]; } );
|
||||
}
|
||||
|
||||
double TTrack::joint_depth() const {
|
||||
@@ -234,7 +258,7 @@ double TTrack::joint_depth() const {
|
||||
return ( m_uneven.dip >= 0.f ? m_uneven.dip : track_uneven::dip_share * uneven_declared().up );
|
||||
}
|
||||
|
||||
double TTrack::joint_dip( double const Distance ) const {
|
||||
double TTrack::joint_dip( double const Distance ) {
|
||||
|
||||
auto const phase { rail_phase( Distance ) };
|
||||
if( phase < 0.0 ) {
|
||||
@@ -245,12 +269,12 @@ double TTrack::joint_dip( double const Distance ) const {
|
||||
return 0.0;
|
||||
}
|
||||
auto const depth { joint_depth() };
|
||||
auto const atend = [&]( TTrack const *Other ) {
|
||||
auto const atend = [ this, depth ]( TTrack const *Other ) {
|
||||
return ( Other == nullptr || Other->fSoundDistance != fSoundDistance ? 0.0 : std::min( depth, Other->joint_depth() ) ); };
|
||||
return 0.001 * track_uneven::dip( fromjoint ) * track_uneven::along( depth, atend( trPrev ), atend( trNext ), Distance, Length() );
|
||||
}
|
||||
|
||||
double TTrack::rail_phase( double const Distance ) const {
|
||||
double TTrack::rail_phase( double const Distance ) {
|
||||
|
||||
if( joint_depth() <= 0.0 || fSoundDistance <= 2.0 * track_uneven::dip_reach ) {
|
||||
return -1.0;
|
||||
@@ -261,22 +285,48 @@ double TTrack::rail_phase( double const Distance ) const {
|
||||
return track_uneven::rail_phase( m_railrun.origin + m_railrun.way * Distance, fSoundDistance );
|
||||
}
|
||||
|
||||
void TTrack::settle_rail_run() const {
|
||||
bool TTrack::rail_joints_moved() {
|
||||
|
||||
return m_drawnrun.stamp != -1
|
||||
&& rail_phase( 0.0 ) >= 0.0
|
||||
&& ( m_railrun.origin != m_drawnrun.origin || m_railrun.way != m_drawnrun.way );
|
||||
}
|
||||
|
||||
std::vector<TTrack *> TTrack::switch_followers( std::vector<TTrack *> const &Tracks ) {
|
||||
|
||||
std::vector<TTrack *> followers;
|
||||
auto const follow = [ &followers ]( TTrack *Track ) {
|
||||
if( Track != nullptr && Track->is_uneven() && std::ranges::find( followers, Track ) == followers.end() ) {
|
||||
followers.push_back( Track );
|
||||
} };
|
||||
for( auto *track : Tracks ) {
|
||||
if( false == is_switch( track ) ) {
|
||||
continue;
|
||||
}
|
||||
for( auto *member : switch_group( *track ) ) {
|
||||
follow( member );
|
||||
std::ranges::for_each( joined_to_switch( *member ), follow );
|
||||
}
|
||||
}
|
||||
return followers;
|
||||
}
|
||||
|
||||
void TTrack::settle_rail_run() {
|
||||
|
||||
// the next track of the run past an end of a track, and which of its ends is joined there
|
||||
auto const onward = []( TTrack const &Track, int const End, int &Joined ) -> TTrack const * {
|
||||
auto const *other { End == 0 ? Track.trPrev : Track.trNext };
|
||||
auto const onward = []( TTrack const &Track, int const End, int &Joined ) -> TTrack * {
|
||||
auto *other { End == 0 ? Track.trPrev : Track.trNext };
|
||||
if( other == nullptr || other == &Track || other->joint_depth() <= 0.0 || other->fSoundDistance != Track.fSoundDistance ) {
|
||||
return nullptr;
|
||||
}
|
||||
Joined = ( End == 0 ? Track.iPrevDirection : Track.iNextDirection ) & 1;
|
||||
return other; };
|
||||
// walks from this track to an end of the run
|
||||
auto const walk = [&]( int &End ) {
|
||||
auto const *track { this };
|
||||
auto const walk = [ this, &onward ]( int &End ) {
|
||||
auto *track { this };
|
||||
int joined { 0 };
|
||||
for( int step = 0; step < 1000000; ++step ) {
|
||||
auto const *next { onward( *track, End, joined ) };
|
||||
auto *next { onward( *track, End, joined ) };
|
||||
if( next == nullptr || next == this ) {
|
||||
break;
|
||||
}
|
||||
@@ -285,15 +335,14 @@ void TTrack::settle_rail_run() const {
|
||||
}
|
||||
return track; };
|
||||
auto const place = []( TTrack const &Track, int const End ) {
|
||||
auto const point { Track.Segment->end_point( End ) };
|
||||
auto const point { end_point( *Track.Segment, End ) };
|
||||
return std::make_pair( point.x, point.z ); };
|
||||
|
||||
// start at the end with the lesser coordinates, to get the same joints from any track of the run
|
||||
int end { 0 };
|
||||
int otherend { 1 };
|
||||
auto const *track { walk( end ) };
|
||||
auto const *other { walk( otherend ) };
|
||||
if( place( *other, otherend ) < place( *track, end ) ) {
|
||||
auto *track { walk( end ) };
|
||||
if( auto *other { walk( otherend ) }; place( *other, otherend ) < place( *track, end ) ) {
|
||||
track = other;
|
||||
end = otherend;
|
||||
}
|
||||
@@ -327,7 +376,8 @@ void TTrack::share_joints() {
|
||||
}
|
||||
}
|
||||
if( eType != tt_Switch && Segment && ( iCategoryFlag & 1 ) ) {
|
||||
float roll1, roll2;
|
||||
float roll1 { 0.f };
|
||||
float roll2 { 0.f };
|
||||
Segment->GetRolls( roll1, roll2 );
|
||||
if( roll1 != 0.f || roll2 != 0.f ) {
|
||||
iTrapezoid |= 1;
|
||||
|
||||
@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/constants.hpp>
|
||||
|
||||
@@ -42,6 +43,18 @@ inline amounts least( amounts const &Left, amounts const &Right ) {
|
||||
return { std::min( Left.up, Right.up ), std::min( Left.side, Right.side ), std::min( Left.cross, Right.cross ) };
|
||||
}
|
||||
|
||||
// which of the other sources of the cab shake the ride on a track stands in for
|
||||
struct shake_sources {
|
||||
bool sway { false }; // from the lateral acceleration
|
||||
bool jolts { false }; // drawn at random
|
||||
};
|
||||
|
||||
// sideways only with something going sideways. Cross level turns the body, and the dips at the joints come and go: neither makes up for any of them
|
||||
inline shake_sources replaced_shake( amounts const &Amount ) {
|
||||
|
||||
return { Amount.side > 0.0, Amount.up > 0.0 || Amount.side > 0.0 };
|
||||
}
|
||||
|
||||
struct wave {
|
||||
double x;
|
||||
double z;
|
||||
@@ -51,18 +64,20 @@ struct wave {
|
||||
|
||||
// the numbers of an entry like "uneven 14;35", negative where left out
|
||||
template <std::size_t Count>
|
||||
std::array<float, Count> read_fields( std::string const &Text ) {
|
||||
std::array<float, Count> read_fields( std::string_view const Text ) {
|
||||
|
||||
std::array<float, Count> result;
|
||||
result.fill( -1.f );
|
||||
std::size_t start { 0 };
|
||||
for( std::size_t index = 0; index < Count && start < Text.size(); ++index ) {
|
||||
auto const end { std::min( Text.find( ';', start ), Text.size() ) };
|
||||
auto value { 0.f };
|
||||
if( end > start && std::from_chars( Text.data() + start, Text.data() + end, value ).ec == std::errc {} ) {
|
||||
result[ index ] = std::clamp( value, 0.f, most );
|
||||
auto rest { Text };
|
||||
for( auto &field : result ) {
|
||||
auto const end { std::min( rest.find( ';' ), rest.size() ) };
|
||||
if( auto value { 0.f }; end > 0 && std::from_chars( rest.data(), rest.data() + end, value ).ec == std::errc {} ) {
|
||||
field = std::clamp( value, 0.f, most );
|
||||
}
|
||||
start = end + 1;
|
||||
if( end == rest.size() ) {
|
||||
break;
|
||||
}
|
||||
rest.remove_prefix( end + 1 );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -100,7 +115,7 @@ struct attribute {
|
||||
};
|
||||
|
||||
// a plain track: value;up;side;cross;dip. A switch: p1-p2;p3-p4;up of p1-p2;side of p1-p2;up of p3-p4;side of p3-p4
|
||||
inline attribute read_attribute( std::string const &Text, bool const Switch ) {
|
||||
inline attribute read_attribute( std::string_view const Text, bool const Switch ) {
|
||||
|
||||
auto const fields { read_fields<6>( Text ) };
|
||||
attribute result;
|
||||
@@ -136,15 +151,15 @@ inline std::string write_attribute( attribute const &Values, bool const Switch )
|
||||
// what a path comes to from the values: what's not given takes the first value, p3-p4 those of p1-p2. Cross level on plain tracks only
|
||||
inline amounts declared( attribute const &Values, bool const Plain, int const Path ) {
|
||||
|
||||
auto const given = []( float const Part, double const Otherwise ) {
|
||||
return Part >= 0.f ? static_cast<double>( Part ) : Otherwise; };
|
||||
amounts result {
|
||||
Values.up >= 0.f ? Values.up : Values.value,
|
||||
Values.side >= 0.f ? Values.side : Values.value,
|
||||
false == Plain ? 0.f : Values.cross >= 0.f ? Values.cross : Values.value };
|
||||
given( Values.up, Values.value ),
|
||||
given( Values.side, Values.value ),
|
||||
Plain ? given( Values.cross, Values.value ) : 0.0 };
|
||||
if( Path == 1 ) {
|
||||
auto const branch = [ &Values ]( float const Part, double const Straight ) -> double {
|
||||
return Part >= 0.f ? Part : Values.branch >= 0.f ? Values.branch : Straight; };
|
||||
result.up = branch( Values.branchup, result.up );
|
||||
result.side = branch( Values.branchside, result.side );
|
||||
result.up = given( Values.branchup, given( Values.branch, result.up ) );
|
||||
result.side = given( Values.branchside, given( Values.branch, result.side ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -160,8 +175,9 @@ wave_set<Count> make_waves( double const Turn, std::array<double, Count> const &
|
||||
wave_set<Count> result {};
|
||||
for( std::size_t i = 0; i < Count; ++i ) {
|
||||
auto const number { glm::two_pi<double>() / Lengths[ i ] };
|
||||
auto const heading { Turn + golden * i };
|
||||
result[ i ] = { number * std::cos( heading ), number * std::sin( heading ), golden * ( i + 1 ) * ( 1.0 + 3.0 * Turn ), Shares[ i ] };
|
||||
auto const place { static_cast<double>( i ) };
|
||||
auto const heading { Turn + golden * place };
|
||||
result[ i ] = { number * std::cos( heading ), number * std::sin( heading ), golden * ( place + 1.0 ) * ( 1.0 + 3.0 * Turn ), Shares[ i ] };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -246,7 +262,10 @@ inline glm::dvec3 across_of( glm::dvec3 const &Direction, glm::dvec3 const &Chor
|
||||
// the cant where two paths meet, theirs turned to the way of this one: a switch takes that of a plain track, alike ones meet halfway
|
||||
inline float joint_roll( float const Own, float const Their, bool const Switch, bool const Theirswitch ) {
|
||||
|
||||
return Switch == Theirswitch ? 0.5f * ( Own + Their ) : Switch ? Their : Own;
|
||||
if( Switch == Theirswitch ) {
|
||||
return 0.5f * ( Own + Their );
|
||||
}
|
||||
return Switch ? Their : Own;
|
||||
}
|
||||
|
||||
// each component the same way
|
||||
|
||||
Reference in New Issue
Block a user