Files
maszyna/TrkFoll.cpp
Firleju cd571c71ea Change clang format
Add AlignTrailingComments: false
Add AllowShortFunctionsOnASingleLine: Empty
2015-04-29 12:55:45 +02:00

341 lines
16 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
/*
MaSzyna EU07 locomotive simulator
Copyright (C) 2001-2004 Marcin Wozniak and others
*/
#include "system.hpp"
#include "classes.hpp"
#include "opengl/glew.h"
#include "opengl/glut.h"
#pragma hdrstop
#include "TrkFoll.h"
#include "Globals.h"
#include "DynObj.h"
#include "Ground.h"
#include "Event.h"
TTrackFollower::TTrackFollower()
{
pCurrentTrack = NULL;
pCurrentSegment = NULL;
fCurrentDistance = 0;
pPosition = vAngles = vector3(0, 0, 0);
fDirection = 1; // jest przodem do Point2
fOffsetH = 0.0; // na starcie stoi na środku
}
TTrackFollower::~TTrackFollower()
{
}
bool TTrackFollower::Init(TTrack *pTrack, TDynamicObject *NewOwner, double fDir)
{
fDirection = fDir;
Owner = NewOwner;
SetCurrentTrack(pTrack, 0);
iEventFlag = 3; // na torze startowym również wykonać eventy 1/2
iEventallFlag = 3;
if ((pCurrentSegment)) // && (pCurrentSegment->GetLength()<fFirstDistance))
return false;
return true;
}
TTrack *__fastcall TTrackFollower::SetCurrentTrack(TTrack *pTrack, int end)
{ // przejechanie na inny odcinkek toru, z ewentualnym rozpruciem
if (pTrack)
switch (pTrack->eType)
{
case tt_Switch: // jeśli zwrotnica, to przekładamy ją, aby uzyskać dobry segment
{
int i = (end ? pCurrentTrack->iNextDirection : pCurrentTrack->iPrevDirection);
if (i > 0) // jeżeli wjazd z ostrza
pTrack->SwitchForced(i >> 1, Owner); // to przełożenie zwrotnicy - rozprucie!
}
break;
case tt_Cross: // skrzyżowanie trzeba tymczasowo przełączyć, aby wjechać na właściwy tor
{
iSegment = Owner->RouteWish(pTrack); // nr segmentu został ustalony podczas skanowania
// Ra 2014-08: aby ustalić dalszą trasę, należy zapytać AI - trasa jest ustalana podczas
// skanowania
// Ra 15-01: zapytanie AI nie wybiera segmentu - kolejny skanujący może przestawić
// pTrack->CrossSegment(end?pCurrentTrack->iNextDirection:pCurrentTrack->iPrevDirection,i);
// //ustawienie właściwego wskaźnika
// powinno zwracać kierunek do zapamiętania, bo segmenty mogą mieć różny kierunek
// if fDirection=(iSegment>0)?1.0:-1.0; //kierunek na tym segmencie jest ustalany
// bezpośrednio
if (iSegment == 0)
{ // to jest błędna sytuacja - generuje pętle zawracające za skrzyżowaniem - ustalić,
// kiedy powstaje!
iSegment = 1; // doraźna poprawka
}
if ((end ? iSegment : -iSegment) < 0)
fDirection = -fDirection; // wtórna zmiana
pTrack->SwitchForced(abs(iSegment) - 1, NULL); // wybór zapamiętanego segmentu
}
break;
}
if (!pTrack)
{ // gdy nie ma toru w kierunku jazdy
pTrack = pCurrentTrack->NullCreate(
end); // tworzenie toru wykolejącego na przedłużeniu pCurrentTrack
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
pTrack->AxleCounter(+1, Owner); // zajęcie nowego toru
if (pCurrentTrack)
pCurrentTrack->AxleCounter(-1, Owner); // opuszczenie tamtego toru
}
pCurrentTrack = pTrack;
pCurrentSegment = (pCurrentTrack ? pCurrentTrack->CurrentSegment() : NULL);
if (!pCurrentTrack)
Error(Owner->MoverParameters->Name + " at NULL track");
return pCurrentTrack;
};
bool TTrackFollower::Move(double fDistance, bool bPrimary)
{ // przesuwanie wózka po torach o odległość (fDistance), z wyzwoleniem eventów
// bPrimary=true - jest pierwszą osią w pojeździe, czyli generuje eventy i przepisuje pojazd
// Ra: zwraca false, jeśli pojazd ma być usunięty
fDistance *= fDirection; // dystans mnożnony przez kierunek
double s; // roboczy dystans
double dir; // zapamiętany kierunek do sprawdzenia, czy się zmienił
bool bCanSkip; // czy przemieścić pojazd na inny tor
while (true) // pętla wychodzi, gdy przesunięcie wyjdzie zerowe
{ // pętla przesuwająca wózek przez kolejne tory, aż do trafienia w jakiś
if (!pCurrentTrack)
return false; // nie ma toru, to nie ma przesuwania
if (pCurrentTrack->iEvents) // sumaryczna informacja o eventach
{ // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
if (fDistance < 0)
{
if (iSetFlag(iEventFlag, -1)) // zawsze zeruje flagę sprawdzenia, jak mechanik
// dosiądzie, to się nie wykona
if (Owner->Mechanik) // tylko dla jednego członu
// if (TestFlag(iEventFlag,1)) //McZapkie-280503: wyzwalanie event tylko dla
// pojazdow z obsada
if (bPrimary && pCurrentTrack->evEvent1 &&
(!pCurrentTrack->evEvent1->iQueued))
Global::AddToQuery(pCurrentTrack->evEvent1, Owner); // dodanie do
// kolejki
// Owner->RaAxleEvent(pCurrentTrack->Event1); //Ra: dynamic zdecyduje, czy dodać do
// kolejki
// if (TestFlag(iEventallFlag,1))
if (iSetFlag(iEventallFlag,
-1)) // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
if (bPrimary && pCurrentTrack->evEventall1 &&
(!pCurrentTrack->evEventall1->iQueued))
Global::AddToQuery(pCurrentTrack->evEventall1, Owner); // dodanie do kolejki
// Owner->RaAxleEvent(pCurrentTrack->Eventall1); //Ra: dynamic zdecyduje, czy dodać
// do kolejki
}
else if (fDistance > 0)
{
if (iSetFlag(iEventFlag, -2)) // zawsze ustawia flagę sprawdzenia, jak mechanik
// dosiądzie, to się nie wykona
if (Owner->Mechanik) // tylko dla jednego członu
// if (TestFlag(iEventFlag,2)) //sprawdzanie jest od razu w pierwszym
// warunku
if (bPrimary && pCurrentTrack->evEvent2 &&
(!pCurrentTrack->evEvent2->iQueued))
Global::AddToQuery(pCurrentTrack->evEvent2, Owner);
// Owner->RaAxleEvent(pCurrentTrack->Event2); //Ra: dynamic zdecyduje, czy dodać do
// kolejki
// if (TestFlag(iEventallFlag,2))
if (iSetFlag(iEventallFlag,
-2)) // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
if (bPrimary && pCurrentTrack->evEventall2 &&
(!pCurrentTrack->evEventall2->iQueued))
Global::AddToQuery(pCurrentTrack->evEventall2, Owner);
// Owner->RaAxleEvent(pCurrentTrack->Eventall2); //Ra: dynamic zdecyduje, czy dodać
// do kolejki
}
else // if (fDistance==0) //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi
{
if (Owner->Mechanik) // tylko dla jednego członu
if (pCurrentTrack->evEvent0)
if (!pCurrentTrack->evEvent0->iQueued)
Global::AddToQuery(pCurrentTrack->evEvent0, Owner);
// Owner->RaAxleEvent(pCurrentTrack->Event0); //Ra: dynamic zdecyduje, czy dodać do
// kolejki
if (pCurrentTrack->evEventall0)
if (!pCurrentTrack->evEventall0->iQueued)
Global::AddToQuery(pCurrentTrack->evEventall0, Owner);
// Owner->RaAxleEvent(pCurrentTrack->Eventall0); //Ra: dynamic zdecyduje, czy dodać
// do kolejki
}
}
if (!pCurrentSegment) // jeżeli nie ma powiązanego segmentu toru?
return false;
// if (fDistance==0.0) return true; //Ra: jak stoi, to chyba dalej nie ma co kombinować?
s = fCurrentDistance + fDistance; // doliczenie przesunięcia
// Ra: W Point2 toru może znajdować się "dziura", która zamieni energię kinetyczną
// ruchu wzdłużnego na energię potencjalną, zamieniającą się potem na energię
// sprężystości na amortyzatorach. Należałoby we wpisie toru umieścić współczynnik
// podziału energii kinetycznej.
// Współczynnik normalnie 1, z dziurą np. 0.99, a -1 będzie oznaczało 100% odbicia (kozioł).
// Albo w postaci kąta: normalnie 0°, a 180° oznacza 100% odbicia (cosinus powyższego).
/*
if (pCurrentTrack->eType==tt_Cross)
{//zjazdu ze skrzyżowania nie da się określić przez (iPrevDirection) i (iNextDirection)
//int segment=Owner->RouteWish(pCurrentTrack); //numer segmentu dla skrzyżowań
//pCurrentTrack->SwitchForced(abs(segment)-1,NULL); //tymczasowo ustawienie tego segmentu
//pCurrentSegment=pCurrentTrack->CurrentSegment(); //odświeżyć sobie wskaźnik segmentu
(?)
}
*/
if (s < 0)
{ // jeśli przekroczenie toru od strony Point1
bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false;
if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru
Owner->MyTrack->RemoveDynamicObject(
Owner); // zdejmujemy pojazd z dotychczasowego toru
dir = fDirection;
if (pCurrentTrack->eType == tt_Cross)
{
if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment, fDirection), 0))
return false; // wyjście z błędem
}
else if (!SetCurrentTrack(pCurrentTrack->Neightbour(-1, fDirection),
0)) // ustawia fDirection
return false; // wyjście z błędem
if (dir == fDirection) //(pCurrentTrack->iPrevDirection)
{ // gdy kierunek bez zmiany (Point1->Point2)
fCurrentDistance = pCurrentSegment->GetLength();
fDistance = s;
}
else
{ // gdy zmiana kierunku toru (Point1->Point1)
fCurrentDistance = 0;
fDistance = -s;
}
if (bCanSkip)
{ // jak główna oś, to dodanie pojazdu do nowego toru
pCurrentTrack->AddDynamicObject(Owner);
iEventFlag =
3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru
iEventallFlag = 3; // McZapkie-280503: jw, dla eventall1,2
if (!Owner->MyTrack)
return false;
}
continue;
}
else if (s > pCurrentSegment->GetLength())
{ // jeśli przekroczenie toru od strony Point2
bCanSkip = bPrimary ? pCurrentTrack->CheckDynamicObject(Owner) : false;
if (bCanSkip) // tylko główna oś przenosi pojazd do innego toru
Owner->MyTrack->RemoveDynamicObject(
Owner); // zdejmujemy pojazd z dotychczasowego toru
fDistance = s - pCurrentSegment->GetLength();
dir = fDirection;
if (pCurrentTrack->eType == tt_Cross)
{
if (!SetCurrentTrack(pCurrentTrack->Neightbour(iSegment, fDirection), 1))
return false; // wyjście z błędem
}
else if (!SetCurrentTrack(pCurrentTrack->Neightbour(1, fDirection),
1)) // ustawia fDirection
return false; // wyjście z błędem
if (dir != fDirection) //(pCurrentTrack->iNextDirection)
{ // gdy zmiana kierunku toru (Point2->Point2)
fDistance = -fDistance; //(s-pCurrentSegment->GetLength());
fCurrentDistance = pCurrentSegment->GetLength();
}
else // gdy kierunek bez zmiany (Point2->Point1)
fCurrentDistance = 0;
if (bCanSkip)
{ // jak główna oś, to dodanie pojazdu do nowego toru
pCurrentTrack->AddDynamicObject(Owner);
iEventFlag =
3; // McZapkie-020602: umozliwienie uruchamiania event1,2 po zmianie toru
iEventallFlag = 3;
if (!Owner->MyTrack)
return false;
}
continue;
}
else
{ // gdy zostaje na tym samym torze (przesuwanie już nie zmienia toru)
if (bPrimary)
{ // tylko gdy początkowe ustawienie, dodajemy eventy stania do kolejki
if (Owner->MoverParameters->ActiveCab != 0)
// if (Owner->MoverParameters->CabNo!=0)
{
if (pCurrentTrack->evEvent1 && pCurrentTrack->evEvent1->fDelay <= -1.0f)
Global::AddToQuery(pCurrentTrack->evEvent1, Owner);
if (pCurrentTrack->evEvent2 && pCurrentTrack->evEvent2->fDelay <= -1.0f)
Global::AddToQuery(pCurrentTrack->evEvent2, Owner);
}
if (pCurrentTrack->evEventall1 && pCurrentTrack->evEventall1->fDelay <= -1.0f)
Global::AddToQuery(pCurrentTrack->evEventall1, Owner);
if (pCurrentTrack->evEventall2 && pCurrentTrack->evEventall2->fDelay <= -1.0f)
Global::AddToQuery(pCurrentTrack->evEventall2, Owner);
}
fCurrentDistance = s;
// fDistance=0;
return ComputatePosition(); // przeliczenie XYZ, true o ile nie wyjechał na NULL
}
}
};
bool TTrackFollower::ComputatePosition()
{ // ustalenie współrzędnych XYZ
if (pCurrentSegment) // o ile jest tor
{
pCurrentSegment->RaPositionGet(fCurrentDistance, pPosition, vAngles);
if (fDirection < 0) // kąty zależą jeszcze od zwrotu na torze
{ // kąty są w przedziale <-M_PI;M_PI>
vAngles.x = -vAngles.x; // przechyłka jest w przecinwą stronę
vAngles.y = -vAngles.y; // pochylenie jest w przecinwą stronę
vAngles.z +=
(vAngles.z >= M_PI) ? -M_PI : M_PI; // ale kierunek w planie jest obrócony o 180°
}
if (fOffsetH != 0.0)
{ // jeśli przesunięcie względem osi toru, to je doliczyć
}
return true;
}
return false;
}
#if RENDER_CONE
#include "opengl/glew.h"
#include "opengl/glut.h"
void TTrackFollower::Render(float fNr)
{ // funkcja rysująca stożek w miejscu osi
glPushMatrix(); // matryca kamery
glTranslatef(pPosition.x, pPosition.y + 6, pPosition.z); // 6m ponad
glRotated(RadToDeg(-vAngles.z), 0, 1, 0); // obrót względem osi OY
// glRotated(RadToDeg(vAngles.z),0,1,0); //obrót względem osi OY
glDisable(GL_LIGHTING);
glColor3f(1.0, 1.0 - fNr, 1.0 - fNr); // biały dla 0, czerwony dla 1
// glutWireCone(promień podstawy,wysokość,kątność podstawy,ilość segmentów na wysokość)
glutWireCone(0.5, 2, 4, 1); // rysowanie stożka (ostrosłupa o podstawie wieloboka)
glEnable(GL_LIGHTING);
glPopMatrix();
}
#endif
//---------------------------------------------------------------------------
#pragma package(smart_init)