build 170903. scan table fixes, some const correctness improvements

This commit is contained in:
tmj-fstate
2017-09-04 19:08:59 +02:00
parent 5d7206b369
commit 2446468038
15 changed files with 254 additions and 220 deletions

View File

@@ -32,6 +32,20 @@ http://mozilla.org/MPL/2.0/.
#define LOGSTOPS 1
#define LOGBACKSCAN 0
#define LOGPRESS 0
// finds point of specified track nearest to specified event. returns: distance to that point from the specified end of the track
// TODO: move this to file with all generic routines, too easy to forget it's here and it may come useful
double
ProjectEventOnTrack( TEvent const *Event, TTrack const *Track, double const Direction ) {
auto const segment = Track->CurrentSegment();
auto const nearestpoint = segment->find_nearest_point( Event->PositionGet() );
return (
Direction > 0 ?
nearestpoint * segment->GetLength() : // measure from point1
( 1.0 - nearestpoint ) * segment->GetLength() ); // measure from point2
};
/*
Moduł obsługujący sterowanie pojazdami (składami pociągów, samochodami).
@@ -106,43 +120,6 @@ std::string StopReasonTable[] = {
"Error", // stopError //z powodu błędu w obliczeniu drogi hamowania
};
double GetDistanceToEvent(TTrack* track, TEvent* event, double scan_dir, double start_dist, int iter = 0, bool back = false)
{
std::shared_ptr<TSegment> segment = track->CurrentSegment();
vector3 pos_event = event->PositionGet();
double len1, len2;
double sd = scan_dir;
double seg_len = scan_dir > 0 ? 0.0 : 1.0;
double dzielnik = 1.0 / segment->GetLength();// rozdzielczosc mniej wiecej 1m
int krok = 0; // krok obliczeniowy do sprawdzania czy odwracamy
len2 = (pos_event - segment->FastGetPoint(seg_len)).Length();
do
{
len1 = len2;
seg_len += scan_dir > 0 ? dzielnik : -dzielnik;
len2 = (pos_event - segment->FastGetPoint(seg_len)).Length();
krok++;
} while ((len1 > len2) && (seg_len >= dzielnik && (seg_len <= (1 - dzielnik))));
//trzeba sprawdzić czy seg_len nie osiągnął skrajnych wartości, bo wtedy
// trzeba sprawdzić tor obok
if (1 == krok)
sd = -sd; // jeśli tylko jeden krok tzn, że event przy poprzednim sprawdzaym torze
if (((seg_len <= dzielnik) || (seg_len > (1 - dzielnik))) && (iter < 3))
{ // przejście na inny tor
track = track->Neightbour(int(sd), sd);
start_dist += (1 == krok) ? 0 : back ? -segment->GetLength() : segment->GetLength();
return GetDistanceToEvent(track, event, sd, start_dist, ++iter, 1 == krok ? true : false);
}
else
{ // obliczenie mojego toru
seg_len -= scan_dir > 0 ? dzielnik : -dzielnik; //trzeba wrócić do pozycji len1
seg_len = scan_dir < 0 ? 1 - seg_len : seg_len;
seg_len = back ? 1 - seg_len : seg_len; // odwracamy jeśli idzie do tyłu
start_dist -= back ? segment->GetLength() : 0;
return start_dist + (segment->GetLength() * seg_len);
}
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
@@ -384,7 +361,7 @@ void TController::TableClear()
eSignSkip = nullptr; // nic nie pomijamy
};
TEvent * TController::CheckTrackEvent(double fDirection, TTrack *Track)
TEvent * TController::CheckTrackEvent( TTrack *Track, double const fDirection ) const
{ // sprawdzanie eventów na podanym torze do podstawowego skanowania
TEvent *e = (fDirection > 0) ? Track->evEvent2 : Track->evEvent1;
if (!e)
@@ -444,7 +421,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
}
fTrackLength -= odl_czola_od_wozka;
fCurrentDistance = -fLength - fTrackLength; // aktualna odległość ma być ujemna gdyż jesteśmy na końcu składu
fLastVel = pTrack->VelocityGet(); // aktualna prędkość
fLastVel = -1.0; // pTrack->VelocityGet(); // aktualna prędkość // changed to -1 to recognize speed limit, if any
sSpeedTable.clear();
iLast = -1;
tLast = nullptr; //żaden nie sprawdzony
@@ -504,7 +481,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->NameGet() );
}
if( ( pEvent = CheckTrackEvent( fLastDir, pTrack ) ) != nullptr ) // jeśli jest semafor na tym torze
if( ( pEvent = CheckTrackEvent( pTrack, fLastDir ) ) != nullptr ) // jeśli jest semafor na tym torze
{ // trzeba sprawdzić tabelkę, bo dodawanie drugi raz tego samego przystanku nie jest korzystne
if (TableNotFound(pEvent)) // jeśli nie ma
{
@@ -514,7 +491,10 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
WriteLog("Speed table for " + OwnerName() + " found new event, " + pEvent->asName);
}
auto &newspeedpoint = sSpeedTable[iLast];
if (newspeedpoint.Set(pEvent, GetDistanceToEvent(pTrack, pEvent, fLastDir, fCurrentDistance), OrderCurrentGet())) {
if( newspeedpoint.Set(
pEvent,
fCurrentDistance + ProjectEventOnTrack( pEvent, pTrack, fLastDir ),
OrderCurrentGet() ) ) {
fDistance = newspeedpoint.fDist; // jeśli sygnał stop, to nie ma potrzeby dalej skanować
SemNextStopIndex = iLast;
@@ -604,29 +584,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
if( ( tLast->VelocityGet() > 0 )
&& ( ( tLast->VelocityGet() < pTrack->VelocityGet() )
|| ( pTrack->VelocityGet() < 0 ) ) ) {
/*
if( ( pTrack->VelocityGet() < 0 ?
tLast->VelocityGet() > 0 :
pTrack->VelocityGet() > tLast->VelocityGet() ) ) {
// jeśli kolejny ma większą prędkość niż poprzedni, to zapamiętać poprzedni (do czasu wyjechania)
if( ( ( ( iLast != -1 )
&& ( TestFlag( sSpeedTable[ iLast ].iFlags, spEnabled | spTrack ) ) ) ?
( sSpeedTable[ iLast ].trTrack != tLast ) :
true ) ) {
// jeśli nie był dodany do tabelki
if( TableAddNew() ) {
// zapisanie toru z ograniczeniem prędkości
sSpeedTable[ iLast ].Set(
tLast, fCurrentDistance,
( fLastDir > 0 ?
pTrack->iPrevDirection :
pTrack->iNextDirection ) ?
spEnabled :
spEnabled | spReverse );
}
}
*/
if( ( iLast != -1 )
&& ( sSpeedTable[ iLast ].trTrack == tLast ) ) {
// if the track is already in the table we only need to mark it as relevant
@@ -658,7 +616,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
if( TableAddNew() ) {
// zapisanie ostatniego sprawdzonego toru
sSpeedTable[iLast].Set(
tLast, fCurrentDistance,
tLast, fCurrentDistance - fTrackLength, // by now the current distance points to beginning of next track,
( fLastDir < 0 ?
spEnabled | spEnd | spReverse :
spEnabled | spEnd ));
@@ -692,9 +650,10 @@ void TController::TableCheck(double fDistance)
}
else if (iTableDirection)
{ // trzeba sprawdzić, czy coś się zmieniło
for (auto &sp : sSpeedTable)
{
sp.UpdateDistance(MoveDistanceGet()); // aktualizacja odległości dla wszystkich pozycji tabeli
auto const distance = MoveDistanceGet();
for (auto &sp : sSpeedTable) {
// aktualizacja odległości dla wszystkich pozycji tabeli
sp.UpdateDistance(distance);
}
MoveDistanceReset(); // kasowanie odległości po aktualizacji tabelki
for( int i = 0; i < iLast; ++i )
@@ -4245,7 +4204,7 @@ TController::UpdateSituation(double dt) {
0 :
1 ); // sprzęg z przodu składu
if( ( coupler->Connected )
&& ( coupler->CouplingFlag == 0 ) ) {
&& ( coupler->CouplingFlag == 0 ) ) {
// mamy coś z przodu podłączone sprzęgiem wirtualnym
// wyliczanie optymalnego przyspieszenia do jazdy na widoczność
ActualProximityDist = std::min(

View File

@@ -369,7 +369,7 @@ private: // parametry aktualnego składu
// double Distance(vector3 &p1, vector3 &n, vector3 &p2);
private: // Ra: metody obsługujące skanowanie toru
TEvent *CheckTrackEvent(double fDirection, TTrack *Track);
TEvent *CheckTrackEvent(TTrack *Track, double const fDirection ) const;
// bool TableCheckEvent(TEvent *e);
bool TableAddNew();
bool TableNotFound(TEvent const *Event) const;

View File

@@ -78,7 +78,7 @@ class TAnimValveGear
class TAnimPant
{ // współczynniki do animacji pantografu
public:
vector3 vPos; // Ra: współrzędne punktu zerowego pantografu (X dodatnie dla przedniego)
Math3D::vector3 vPos; // Ra: współrzędne punktu zerowego pantografu (X dodatnie dla przedniego)
double fLenL1; // długość dolnego ramienia 1, odczytana z modelu
double fLenU1; // długość górnego ramienia 1, odczytana z modelu
double fLenL2; // długość dolnego ramienia 2, odczytana z modelu
@@ -152,9 +152,9 @@ class TDynamicObject { // klasa pojazdu
friend class opengl_renderer;
private: // położenie pojazdu w świecie oraz parametry ruchu
vector3 vPosition; // Ra: pozycja pojazdu liczona zaraz po przesunięciu
vector3 vCoulpler[ 2 ]; // współrzędne sprzęgów do liczenia zderzeń czołowych
vector3 vUp, vFront, vLeft; // wektory jednostkowe ustawienia pojazdu
Math3D::vector3 vPosition; // Ra: pozycja pojazdu liczona zaraz po przesunięciu
Math3D::vector3 vCoulpler[ 2 ]; // współrzędne sprzęgów do liczenia zderzeń czołowych
Math3D::vector3 vUp, vFront, vLeft; // wektory jednostkowe ustawienia pojazdu
int iDirection; // kierunek pojazdu względem czoła składu (1=zgodny,0=przeciwny)
TTrackShape ts; // parametry toru przekazywane do fizyki
TTrackParam tp; // parametry toru przekazywane do fizyki
@@ -163,14 +163,14 @@ private: // położenie pojazdu w świecie oraz parametry ruchu
int iAxleFirst; // numer pierwszej osi w kierunku ruchu (oś wiążąca pojazd z torem i wyzwalająca
// eventy)
float fAxleDist; // rozstaw wózków albo osi do liczenia proporcji zacienienia
vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
Math3D::vector3 modelRot; // obrot pudła względem świata - do przeanalizowania, czy potrzebne!!!
// bool bCameraNear; //blisko kamer są potrzebne dodatkowe obliczenia szczegółów
TDynamicObject * ABuFindNearestObject( TTrack *Track, TDynamicObject *MyPointer, int &CouplNr );
public: // parametry położenia pojazdu dostępne publicznie
std::string asTrack; // nazwa toru początkowego; wywalić?
std::string asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)"
matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli
Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli
TMoverParameters *MoverParameters; // parametry fizyki ruchu oraz przeliczanie
// TMoverParameters *pControlled; //wskaźnik do sterowanego członu silnikowego
TDynamicObject *NextConnected; // pojazd podłączony od strony sprzęgu 1 (kabina -1)
@@ -237,7 +237,7 @@ public: // modele składowe pojazdu
void toggle_lights(); // switch light levels for registered interior sections
private: // Ra: ciąg dalszy animacji, dopiero do ogarnięcia
// ABuWozki 060504
vector3 bogieRot[2]; // Obroty wozkow w/m korpusu
Math3D::vector3 bogieRot[2]; // Obroty wozkow w/m korpusu
TSubModel *smBogie[2]; // Wyszukiwanie max 2 wozkow
TSubModel *smWahacze[4]; // wahacze (np. nogi, dźwignia w drezynie)
TSubModel *smBrakeMode; // Ra 15-01: nastawa hamulca też
@@ -249,7 +249,7 @@ public: // modele składowe pojazdu
TSubModel *smBuforLewy[2];
TSubModel *smBuforPrawy[2];
TAnimValveGear *pValveGear;
vector3 vFloor; // podłoga dla ładunku
Math3D::vector3 vFloor; // podłoga dla ładunku
public:
TAnim *pants; // indeks obiektu animującego dla pantografu 0
double NoVoltTime; // czas od utraty zasilania
@@ -264,7 +264,7 @@ public: // modele składowe pojazdu
void ABuLittleUpdate(double ObjSqrDist);
bool btnOn; // ABu: czy byly uzywane buttony, jesli tak, to po renderingu wylacz
// bo ten sam model moze byc jeszcze wykorzystany przez inny obiekt!
double ComputeRadius(vector3 p1, vector3 p2, vector3 p3, vector3 p4);
double ComputeRadius( Math3D::vector3 p1, Math3D::vector3 p2, Math3D::vector3 p3, Math3D::vector3 p4);
TButton btCoupler1; // sprzegi
TButton btCoupler2;
@@ -337,7 +337,7 @@ public: // modele składowe pojazdu
double eng_turbo;
void ABuBogies();
void ABuModelRoll();
vector3 modelShake;
Math3D::vector3 modelShake;
bool renderme; // yB - czy renderowac
// TRealSound sBrakeAcc; //dźwięk przyspieszacza
@@ -406,7 +406,7 @@ public: // modele składowe pojazdu
int &CouplNr);
TDynamicObject * GetFirstDynamic(int cpl_type, int cf = 1);
// TDynamicObject* GetFirstCabDynamic(int cpl_type);
void ABuSetModelShake(vector3 mShake);
void ABuSetModelShake( Math3D::vector3 mShake);
// McZapkie-010302
TController *Mechanik;
@@ -437,31 +437,31 @@ public: // modele składowe pojazdu
void Move(double fDistance);
void FastMove(double fDistance);
void RenderSounds();
inline vector3 GetPosition() const
inline Math3D::vector3 GetPosition() const
{
return vPosition;
};
inline vector3 HeadPosition()
inline Math3D::vector3 HeadPosition()
{
return vCoulpler[iDirection ^ 1];
}; // pobranie współrzędnych czoła
inline vector3 RearPosition()
inline Math3D::vector3 RearPosition()
{
return vCoulpler[iDirection];
}; // pobranie współrzędnych tyłu
inline vector3 AxlePositionGet()
inline Math3D::vector3 AxlePositionGet()
{
return iAxleFirst ? Axle1.pPosition : Axle0.pPosition;
};
inline vector3 VectorFront() const
inline Math3D::vector3 VectorFront() const
{
return vFront;
};
inline vector3 VectorUp()
inline Math3D::vector3 VectorUp()
{
return vUp;
};
inline vector3 VectorLeft() const
inline Math3D::vector3 VectorLeft() const
{
return vLeft;
};

View File

@@ -673,7 +673,7 @@ double TEvent::ValueGet(int n)
return 0.0; // inne eventy się nie liczą
};
vector3 TEvent::PositionGet()
vector3 TEvent::PositionGet() const
{ // pobranie współrzędnych eventu
switch (Type)
{ //

View File

@@ -108,7 +108,7 @@ class TEvent // zmienne: ev*
std::string CommandGet();
TCommandType Command();
double ValueGet(int n);
vector3 PositionGet();
vector3 PositionGet() const;
bool StopCommand();
void StopCommandSent();
void Append(TEvent *e);

View File

@@ -1489,6 +1489,8 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
*/
// we rely on the SUB chunk coming before the vertex data, and on the overall vertex count matching the size of data in the chunk.
// geometry associated with chunks isn't stored in the same order as the chunks themselves, so we need to sort that out first
if( Root == nullptr )
throw std::runtime_error( "e3d: VNT chunk encountered before SUB chunk" );
std::vector< std::pair<int, int> > submodeloffsets; // vertex data offset, submodel index
submodeloffsets.reserve( iSubModelsCount );
for( int submodelindex = 0; submodelindex < iSubModelsCount; ++submodelindex ) {

View File

@@ -64,10 +64,10 @@ bool TPythonInterpreter::loadClassFile( std::string const &lookupPath, std::stri
if (sourceFile != nullptr)
{
fseek(sourceFile, 0, SEEK_END);
long fsize = ftell(sourceFile);
auto const fsize = ftell(sourceFile);
char *buffer = (char *)calloc(fsize + 1, sizeof(char));
fseek(sourceFile, 0, SEEK_SET);
size_t freaded = fread(buffer, sizeof(char), fsize, sourceFile);
auto const freaded = fread(buffer, sizeof(char), fsize, sourceFile);
buffer[freaded] = 0; // z jakiegos powodu czytamy troche mniej i trzczeba dodac konczace
// zero do bufora (mimo ze calloc teoretycznie powiniene zwrocic
// wyzerowana pamiec)

View File

@@ -21,20 +21,17 @@ http://mozilla.org/MPL/2.0/.
// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0
TSegment::TSegment(TTrack *owner) :
pOwner( owner )
{
fAngle[ 0 ] = 0.0;
fAngle[ 1 ] = 0.0;
};
pOwner( owner )
{}
TSegment::~TSegment()
{
SafeDeleteArray(fTsBuffer);
};
}
bool TSegment::Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1, double fNewRoll2)
bool TSegment::Init(Math3D::vector3 NewPoint1, Math3D::vector3 NewPoint2, double fNewStep, double fNewRoll1, double fNewRoll2)
{ // wersja dla prostego - wyliczanie punktów kontrolnych
vector3 dir;
Math3D::vector3 dir;
// NOTE: we're enforcing division also for straight track, to ensure dense enough mesh for per-vertex lighting
/*
@@ -55,9 +52,7 @@ bool TSegment::Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, doubl
}
};
bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn,
vector3 &NewPoint2, double fNewStep, double fNewRoll1, double fNewRoll2,
bool bIsCurve)
bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, Math3D::vector3 NewCPointIn, Math3D::vector3 &NewPoint2, double fNewStep, double fNewRoll1, double fNewRoll2, bool bIsCurve)
{ // wersja uniwersalna (dla krzywej i prostego)
Point1 = NewPoint1;
CPointOut = NewCPointOut;
@@ -77,7 +72,7 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI
// mieć moment wypoziomowania, ale musi on być również podniesiony.
if (fRoll1 != 0.0)
{ // tylko jeśli jest przechyłka
double w1 = fabs(sin(fRoll1) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435
double w1 = std::abs(std::sin(fRoll1) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435
Point1.y += w1; // modyfikacja musi być przed policzeniem dalszych parametrów
if (bCurve)
CPointOut.y += w1; // prosty ma wektory jednostkowe
@@ -85,7 +80,7 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI
}
if (fRoll2 != 0.0)
{
double w2 = fabs(sin(fRoll2) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435
double w2 = std::abs(std::sin(fRoll2) * 0.75); // 0.5*w2+0.0325; //0.75m dla 1.435
Point2.y += w2; // modyfikacja musi być przed policzeniem dalszych parametrów
if (bCurve)
CPointIn.y += w2; // prosty ma wektory jednostkowe
@@ -137,12 +132,12 @@ bool TSegment::Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointI
return true;
}
vector3 TSegment::GetFirstDerivative(double fTime)
Math3D::vector3 TSegment::GetFirstDerivative(double const fTime) const
{
double fOmTime = 1.0 - fTime;
double fPowTime = fTime;
vector3 kResult = fOmTime * (CPointOut - Point1);
Math3D::vector3 kResult = fOmTime * (CPointOut - Point1);
// int iDegreeM1 = 3 - 1;
@@ -156,7 +151,7 @@ vector3 TSegment::GetFirstDerivative(double fTime)
return kResult;
}
double TSegment::RombergIntegral(double fA, double fB)
double TSegment::RombergIntegral(double const fA, double const fB) const
{
double fH = fB - fA;
@@ -188,7 +183,7 @@ double TSegment::RombergIntegral(double fA, double fB)
return ms_apfRom[0][ms_iOrder - 1];
}
double TSegment::GetTFromS(double s)
double TSegment::GetTFromS(double const s) const
{
// initial guess for Newton's method
double fTolerance = 0.001;
@@ -216,41 +211,83 @@ double TSegment::GetTFromS(double s)
return fTime;
};
vector3 TSegment::RaInterpolate(double t)
Math3D::vector3 TSegment::RaInterpolate(double const t) const
{ // wyliczenie XYZ na krzywej Beziera z użyciem współczynników
return t * (t * (t * vA + vB) + vC) + Point1; // 9 mnożeń, 9 dodawań
};
vector3 TSegment::RaInterpolate0(double t)
Math3D::vector3 TSegment::RaInterpolate0(double const t) const
{ // wyliczenie XYZ na krzywej Beziera, na użytek liczenia długości nie jest dodawane Point1
return t * (t * (t * vA + vB) + vC); // 9 mnożeń, 6 dodawań
};
double TSegment::ComputeLength() // McZapkie-150503: dlugosc miedzy punktami krzywej
double TSegment::ComputeLength() const // McZapkie-150503: dlugosc miedzy punktami krzywej
{ // obliczenie długości krzywej Beziera za pomocą interpolacji odcinkami
// Ra: zamienić na liczenie rekurencyjne średniej z cięciwy i łamanej po kontrolnych
// Ra: koniec rekurencji jeśli po podziale suma długości nie różni się więcej niż 0.5mm od
// poprzedniej
// Ra: ewentualnie rozpoznać łuk okręgu płaskiego i liczyć ze wzoru na długość łuku
double t, l = 0;
vector3 last = vector3(0, 0, 0); // długość liczona po przesunięciu odcinka do początku układu
vector3 tmp = Point2 - Point1;
Math3D::vector3 last = Math3D::vector3(0, 0, 0); // długość liczona po przesunięciu odcinka do początku układu
Math3D::vector3 tmp = Point2 - Point1;
int m = 20.0 * tmp.Length(); // było zawsze do 10000, teraz jest liczone odcinkami po około 5cm
for (int i = 1; i <= m; i++)
{
t = double(i) / double(m); // wyznaczenie parametru na krzywej z przedziału (0,1>
// tmp=Interpolate(t,p1,cp1,cp2,p2);
tmp = RaInterpolate0(t); // obliczenie punktu dla tego parametru
t = vector3(tmp - last).Length(); // obliczenie długości wektora
t = Math3D::vector3(tmp - last).Length(); // obliczenie długości wektora
l += t; // zwiększenie wyliczanej długości
last = tmp;
}
return (l);
}
// finds point on segment closest to specified point in 3d space. returns: point on segment as value in range 0-1
double
TSegment::find_nearest_point( glm::dvec3 const &Point ) const {
if( ( false == bCurve ) || ( iSegCount == 1 ) ) {
// for straight track just treat it as a single segment
return
nearest_segment_point(
glm::dvec3{ FastGetPoint_0() },
glm::dvec3{ FastGetPoint_1() },
Point );
}
else {
// for curves iterate through segment chunks, and find the one which gives us the least distance to the specified point
double distance = std::numeric_limits<double>::max();
double nearest;
// NOTE: we're reusing already created segment chunks, which are created based on splinefidelity setting
// this means depending on splinefidelity the results can be potentially slightly different
for( int segmentidx = 0; segmentidx < iSegCount; ++segmentidx ) {
auto const segmentpoint =
clamp(
nearest_segment_point(
glm::dvec3{ FastGetPoint( fTsBuffer[ segmentidx ] ) },
glm::dvec3{ FastGetPoint( fTsBuffer[ segmentidx + 1 ] ) },
Point ) // point in range 0-1 on current segment
* ( fTsBuffer[ segmentidx + 1 ] - fTsBuffer[ segmentidx ] ) // segment length
+ fTsBuffer[ segmentidx ], // segment offset
0.0, 1.0 ); // we clamp the range in case there's some floating point math inaccuracies
auto const segmentdistance = glm::length2( Point - glm::dvec3{ FastGetPoint( segmentpoint ) } );
if( segmentdistance < distance ) {
nearest = segmentpoint;
distance = segmentdistance;
}
}
//
return nearest;
}
}
const double fDirectionOffset = 0.1; // długość wektora do wyliczenia kierunku
vector3 TSegment::GetDirection(double fDistance)
Math3D::vector3 TSegment::GetDirection(double const fDistance) const
{ // takie toporne liczenie pochodnej dla podanego dystansu od Point1
double t1 = GetTFromS(fDistance - fDirectionOffset);
if (t1 <= 0.0)
@@ -261,7 +298,7 @@ vector3 TSegment::GetDirection(double fDistance)
return (FastGetPoint(t2) - FastGetPoint(t1));
}
vector3 TSegment::FastGetDirection(double fDistance, double fOffset)
Math3D::vector3 TSegment::FastGetDirection(double fDistance, double fOffset)
{ // takie toporne liczenie pochodnej dla parametru 0.0÷1.0
double t1 = fDistance - fOffset;
if (t1 <= 0.0)
@@ -272,7 +309,7 @@ vector3 TSegment::FastGetDirection(double fDistance, double fOffset)
return (FastGetPoint(t2) - FastGetPoint(t1));
}
vector3 TSegment::GetPoint(double fDistance)
Math3D::vector3 TSegment::GetPoint(double const fDistance) const
{ // wyliczenie współrzędnych XYZ na torze w odległości (fDistance) od Point1
if (bCurve)
{ // można by wprowadzić uproszczony wzór dla okręgów płaskich
@@ -287,7 +324,7 @@ vector3 TSegment::GetPoint(double fDistance)
}
};
void TSegment::RaPositionGet(double fDistance, vector3 &p, vector3 &a)
void TSegment::RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const
{ // ustalenie pozycji osi na torze, przechyłki, pochylenia i kierunku jazdy
if (bCurve)
{ // można by wprowadzić uproszczony wzór dla okręgów płaskich
@@ -309,13 +346,16 @@ void TSegment::RaPositionGet(double fDistance, vector3 &p, vector3 &a)
}
};
vector3 TSegment::FastGetPoint(double t)
Math3D::vector3 TSegment::FastGetPoint(double const t) const
{
// return (bCurve?Interpolate(t,Point1,CPointOut,CPointIn,Point2):((1.0-t)*Point1+(t)*Point2));
return (bCurve ? RaInterpolate(t) : ((1.0 - t) * Point1 + (t)*Point2));
return (
( ( true == bCurve ) || ( iSegCount == 1 ) ) ?
RaInterpolate( t ) :
interpolate( Point1, Point2, t ) );
}
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, vector3 **p, bool bRender)
bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, const vector6 *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale, int iSkip, int iEnd, double fOffsetX, Math3D::vector3 **p, bool bRender)
{ // generowanie trójkątów dla odcinka trajektorii ruchu
// standardowo tworzy triangle_strip dla prostego albo ich zestaw dla łuku
// po modyfikacji - dla ujemnego (iNumShapePoints) w dodatkowych polach tabeli
@@ -325,7 +365,7 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
if( !fTsBuffer )
return false; // prowizoryczne zabezpieczenie przed wysypem - ustalić faktyczną przyczynę
vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
Math3D::vector3 pos1, pos2, dir, parallel1, parallel2, pt, norm;
double s, step, fOffset, tv1, tv2, t, fEnd;
bool const trapez = iNumShapePoints < 0; // sygnalizacja trapezowatości
iNumShapePoints = std::abs( iNumShapePoints );
@@ -341,7 +381,7 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
fOffset = 0.1 / fLength; // pierwsze 10cm
pos1 = FastGetPoint( t ); // wektor początku segmentu
dir = FastGetDirection( t, fOffset ); // wektor kierunku
parallel1 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
parallel1 = Normalize( Math3D::vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
if( iEnd == 0 )
iEnd = iSegCount;
fEnd = fLength * double( iEnd ) / double( iSegCount );
@@ -371,7 +411,7 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
t = fTsBuffer[ i ]; // szybsze od GetTFromS(s);
pos2 = FastGetPoint( t );
dir = FastGetDirection( t, fOffset ); // nowy wektor kierunku
parallel2 = Normalize( vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
parallel2 = Normalize( Math3D::vector3( -dir.z, 0.0, dir.x ) ); // wektor poprzeczny
if( trapez ) {
for( int j = 0; j < iNumShapePoints; ++j ) {
@@ -453,7 +493,7 @@ bool TSegment::RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin,
void TSegment::Render()
{
vector3 pt;
Math3D::vector3 pt;
GfxRenderer.Bind_Material( null_handle );
if (bCurve)

148
Segment.h
View File

@@ -7,24 +7,19 @@ obtain one at
http://mozilla.org/MPL/2.0/.
*/
#ifndef SegmentH
#define SegmentH
/*
#include "VBO.h"
*/
#pragma once
#include "openglgeometrybank.h"
#include "dumb3d.h"
#include "Classes.h"
#include "usefull.h"
using namespace Math3D;
// 110405 Ra: klasa punktów przekroju z normalnymi
class vector6 : public vector3
class vector6 : public Math3D::vector3
{ // punkt przekroju wraz z wektorem normalnym
public:
vector3 n;
Math3D::vector3 n;
vector6()
{
x = y = z = n.x = n.z = 0.0;
@@ -54,7 +49,7 @@ class vector6 : public vector3
class TSegment
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
private:
vector3 Point1, CPointOut, CPointIn, Point2;
Math3D::vector3 Point1, CPointOut, CPointIn, Point2;
double fRoll1 = 0.0,
fRoll2 = 0.0; // przechyłka na końcach
double fLength = 0.0; // długość policzona
@@ -63,63 +58,92 @@ class TSegment
int iSegCount = 0; // ilość odcinków do rysowania krzywej
double fDirection = 0.0; // Ra: kąt prostego w planie; dla łuku kąt od Point1
double fStoop = 0.0; // Ra: kąt wzniesienia; dla łuku od Point1
vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1
Math3D::vector3 vA, vB, vC; // współczynniki wielomianów trzeciego stopnia vD==Point1
TTrack *pOwner = nullptr; // wskaźnik na właściciela
double fAngle[2]; // kąty zakończenia drogi na przejazdach
double fAngle[ 2 ] = { 0.0, 0.0 }; // kąty zakończenia drogi na przejazdach
vector3 GetFirstDerivative(double fTime);
double RombergIntegral(double fA, double fB);
double GetTFromS(double s);
vector3 RaInterpolate(double t);
vector3 RaInterpolate0(double t);
public:
Math3D::vector3
GetFirstDerivative(double const fTime) const;
double
RombergIntegral(double const fA, double const fB) const;
double
GetTFromS(double const s) const;
Math3D::vector3
RaInterpolate(double const t) const;
Math3D::vector3
RaInterpolate0(double const t) const;
public:
bool bCurve = false;
TSegment(TTrack *owner);
~TSegment();
bool Init(vector3 NewPoint1, vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0);
bool Init(vector3 &NewPoint1, vector3 NewCPointOut, vector3 NewCPointIn, vector3 &NewPoint2,
double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0, bool bIsCurve = true);
inline double ComputeLength(); // McZapkie-150503
inline vector3 GetDirection1() {
return bCurve ? CPointOut - Point1 : CPointOut; };
inline vector3 GetDirection2() {
return bCurve ? CPointIn - Point2 : CPointIn; };
vector3 GetDirection(double fDistance);
vector3 GetDirection() {
return CPointOut; };
vector3 FastGetDirection(double fDistance, double fOffset);
vector3 GetPoint(double fDistance);
void RaPositionGet(double fDistance, vector3 &p, vector3 &a);
vector3 FastGetPoint(double t);
inline vector3 FastGetPoint_0() {
return Point1; };
inline vector3 FastGetPoint_1() {
return Point2; };
inline double GetRoll(double const Distance) {
return interpolate( fRoll1, fRoll2, Distance / fLength ); }
void GetRolls(double &r1, double &r2) {
// pobranie przechyłek (do generowania trójkątów)
r1 = fRoll1;
r2 = fRoll2; }
bool RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, vector3 **p = nullptr, bool bRender = true);
void Render();
inline double GetLength() {
return fLength; };
void MoveMe(vector3 pPosition)
{
Point1 += pPosition;
Point2 += pPosition;
if (bCurve)
{
CPointIn += pPosition;
CPointOut += pPosition;
}
}
int RaSegCount() {
return fTsBuffer ? iSegCount : 1; };
void AngleSet(int i, double a) {
fAngle[i] = a; };
bool
Init( Math3D::vector3 NewPoint1, Math3D::vector3 NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0);
bool
Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, Math3D::vector3 NewCPointIn, Math3D::vector3 &NewPoint2, double fNewStep, double fNewRoll1 = 0, double fNewRoll2 = 0, bool bIsCurve = true);
double
ComputeLength() const; // McZapkie-150503
// finds point on segment closest to specified point in 3d space. returns: point on segment as value in range 0-1
double
find_nearest_point( glm::dvec3 const &Point ) const;
inline
Math3D::vector3
GetDirection1() const {
return bCurve ? CPointOut - Point1 : CPointOut; };
inline
Math3D::vector3
GetDirection2() const {
return bCurve ? CPointIn - Point2 : CPointIn; };
Math3D::vector3
GetDirection(double const fDistance) const;
inline
Math3D::vector3
GetDirection() const {
return CPointOut; };
Math3D::vector3
FastGetDirection(double const fDistance, double const fOffset);
Math3D::vector3
GetPoint(double const fDistance) const;
void
RaPositionGet(double const fDistance, Math3D::vector3 &p, Math3D::vector3 &a) const;
Math3D::vector3
FastGetPoint(double const t) const;
inline
Math3D::vector3
FastGetPoint_0() const {
return Point1; };
inline
Math3D::vector3
FastGetPoint_1() const {
return Point2; };
inline
double
GetRoll(double const Distance) const {
return interpolate( fRoll1, fRoll2, Distance / fLength ); }
inline
void
GetRolls(double &r1, double &r2) const {
// pobranie przechyłek (do generowania trójkątów)
r1 = fRoll1;
r2 = fRoll2; }
bool
RenderLoft( vertex_array &Output, Math3D::vector3 const &Origin, vector6 const *ShapePoints, int iNumShapePoints, double fTextureLength, double Texturescale = 1.0, int iSkip = 0, int iEnd = 0, double fOffsetX = 0.0, Math3D::vector3 **p = nullptr, bool bRender = true);
void
Render();
inline
double
GetLength() const {
return fLength; };
inline
int
RaSegCount() const {
return fTsBuffer ? iSegCount : 1; };
inline
void
AngleSet(int const i, double const a) {
fAngle[i] = a; };
};
//---------------------------------------------------------------------------
#endif

View File

@@ -268,32 +268,30 @@ TTrack * TTrack::NullCreate(int dir)
trk2->fRadius = 20.0; // promień, aby się dodawało do tabelki prędkości i liczyło
// narastająco
trk2->Init(); // utworzenie segmentu
trk->pMyNode->asName = pMyNode->asName + ":loopstart";
trk2->pMyNode->asName = pMyNode->asName + ":loopfinish";
switch (dir)
{ //łączenie z nowym torem
case 0:
p1 = Segment->FastGetPoint_0();
cv1 = -20.0 * Normalize(Segment->GetDirection1()); // pierwszy wektor kontrolny
p2 = p1 + cv1 + cv1; // 40m
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2,
-RadToDeg(r1),
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, -RadToDeg(r1), 0.0);
ConnectPrevPrev(trk, 0);
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2,
-RadToDeg(r1),
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, -RadToDeg(r1), 0.0);
trk2->iPrevDirection = 0; // zwrotnie do tego samego odcinka
break;
case 1:
p1 = Segment->FastGetPoint_1();
cv1 = -20.0 * Normalize(Segment->GetDirection2()); // pierwszy wektor kontrolny
p2 = p1 + cv1 + cv1;
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2,
RadToDeg(r2),
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
trk->Segment->Init(p1, p1 + cv1, p2 + vector3(-cv1.z, cv1.y, cv1.x), p2, 2, RadToDeg(r2), 0.0);
ConnectNextPrev(trk, 0);
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2,
RadToDeg(r2),
0.0); // bo prosty, kontrolne wyliczane przy zmiennej przechyłce
// bo prosty, kontrolne wyliczane przy zmiennej przechyłce
trk2->Segment->Init(p1, p1 + cv1, p2 + vector3(cv1.z, cv1.y, -cv1.x), p2, 2, RadToDeg(r2), 0.0);
trk2->iPrevDirection = 1; // zwrotnie do tego samego odcinka
break;
}
@@ -870,7 +868,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
}
else {
if( evEventall1 == nullptr ) {
evEventall1 = NewEvent0;
evEventall1 = NewEvent1;
asEventall1Name = "";
iEvents |= 16; // sumaryczna informacja o eventach
}
@@ -888,7 +886,7 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
}
else {
if( evEventall2 == nullptr ) {
evEventall2 = NewEvent0;
evEventall2 = NewEvent2;
asEventall2Name = "";
iEvents |= 32; // sumaryczna informacja o eventach
}

10
Track.h
View File

@@ -77,7 +77,7 @@ class TSwitchExtension
struct
{ // zmienne dla skrzyżowania
int iRoads; // ile dróg się spotyka?
vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
Math3D::vector3 *vPoints; // tablica wierzchołków nawierzchni, generowana przez pobocze
// int iPoints; // liczba faktycznie użytych wierzchołków nawierzchni
bool bPoints; // czy utworzone?
};
@@ -90,7 +90,7 @@ class TSwitchExtension
TEvent *evPlus = nullptr,
*evMinus = nullptr; // zdarzenia sygnalizacji rozprucia
float fVelocity = -1.0; // maksymalne ograniczenie prędkości (ustawianej eventem)
vector3 vTrans; // docelowa translacja przesuwnicy
Math3D::vector3 vTrans; // docelowa translacja przesuwnicy
private:
};
@@ -199,7 +199,7 @@ public:
void ConnectNextNext(TTrack *pNewNext, int typ);
inline double Length() {
return Segment->GetLength(); };
inline std::shared_ptr<TSegment> CurrentSegment() {
inline std::shared_ptr<TSegment> CurrentSegment() const {
return Segment; };
inline TTrack * CurrentNext() {
return (trNext); };
@@ -215,7 +215,7 @@ public:
SwitchExtension ?
SwitchExtension->CurrentIndex :
-1); };
void Load(cParser *parser, vector3 pOrigin, std::string name);
void Load(cParser *parser, Math3D::vector3 pOrigin, std::string name);
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
@@ -247,7 +247,7 @@ public:
m_material1 :
m_material2 ); };
bool IsGroupable();
int TestPoint(vector3 *Point);
int TestPoint( Math3D::vector3 *Point);
void MovedUp1(float const dh);
std::string NameGet();
void VelocitySet(float v);

View File

@@ -71,19 +71,11 @@ TTrack * TTrackFollower::SetCurrentTrack(TTrack *pTrack, int end)
}
break;
}
if (!pTrack)
{ // gdy nie ma toru w kierunku jazdy
pTrack = pCurrentTrack->NullCreate(
end); // tworzenie toru wykolejącego na przedłużeniu pCurrentTrack
if (!pTrack) {
// gdy nie ma toru w kierunku jazdy tworzenie toru wykolejącego na przedłużeniu pCurrentTrack
pTrack = pCurrentTrack->NullCreate(end);
if (!end) // jeśli dodana od strony zero, to zmiana kierunku
fDirection = -fDirection; // wtórna zmiana
// if (pTrack->iCategoryFlag&2)
//{//jeśli samochód, zepsuć na miejscu
// Owner->MoverParameters->V=0; //zatrzymać
// Owner->MoverParameters->Power=0; //ukraść silnik
// Owner->MoverParameters->AccS=0; //wchłonąć moc
// Global::iPause|=1; //zapauzowanie symulacji
//}
}
else
{ // najpierw +1, później -1, aby odcinek izolowany wspólny dla tych torów nie wykrył zera

View File

@@ -28,8 +28,8 @@ class TTrackFollower
// zwrotnicy pod taborem)
public:
double fOffsetH = 0.0; // Ra: odległość środka osi od osi toru (dla samochodów) - użyć do wężykowania
vector3 pPosition; // współrzędne XYZ w układzie scenerii
vector3 vAngles; // x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach)
Math3D::vector3 pPosition; // współrzędne XYZ w układzie scenerii
Math3D::vector3 vAngles; // x:przechyłka, y:pochylenie, z:kierunek w planie (w radianach)
TTrackFollower() = default;
~TTrackFollower();
TTrack * SetCurrentTrack(TTrack *pTrack, int end);

View File

@@ -95,4 +95,23 @@ bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterato
Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } );
}
// finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment
template <typename VecType_>
typename VecType_::value_type
nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) {
auto const v = Segmentend - Segmentstart;
auto const w = Point - Segmentstart;
auto const c1 = glm::dot( w, v );
if( c1 <= 0.0 ) {
return 0.0;
}
auto const c2 = glm::dot( v, v );
if( c2 <= c1 ) {
return 1.0;
}
return c1 / c2;
}
//---------------------------------------------------------------------------

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 902
#define VERSION_MINOR 903
#define VERSION_REVISION 0