forked from tmj-fstate/maszyna
-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathTrkFoll.cpp
297 lines (286 loc) · 14.1 KB
/
TrkFoll.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
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 "stdafx.h"
#include "TrkFoll.h"
#include "simulation.h"
#include "Globals.h"
#include "DynObj.h"
#include "Driver.h"
#include "Logs.h"
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 * 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 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
}
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 != nullptr ? pCurrentTrack->CurrentSegment() : nullptr );
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
auto const ismoving { /* ( std::abs( fDistance ) > 0.01 ) && */ ( Owner->GetVelocity() > 0.01 ) };
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 == nullptr ) { return false; } // nie ma toru, to nie ma przesuwania
// TODO: refactor following block as track method
if( pCurrentTrack->m_events ) { // sumaryczna informacja o eventach
// omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma)
int const eventfilter { (
false == ismoving ? 0 : // only moving vehicles activate events type 1/2
false == bPrimary ? 0 : // only primary axle activates events type 1/2
Owner->ctOwner == nullptr ?
( fDistance > 0 ? 1 : -1 ) : // loose vehicle has no means to determine 'intended' direction so the filter does effectively nothing in such case
( fDirection > 0 ? 1 : -1 ) * Owner->ctOwner->Direction() * ( Owner->ctOwner->Vehicle()->DirectionGet() == Owner->DirectionGet() ? 1 : -1 ) ) };
if( false == ismoving ) {
//McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi
if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->primary() ) ) {
// tylko dla jednego członu
pCurrentTrack->QueueEvents( pCurrentTrack->m_events0, Owner );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events0all, Owner );
}
else if( (fDistance < 0) && ( eventfilter < 0 ) ) {
// event1, eventall1
if( SetFlag( iEventFlag, -1 ) ) {
// zawsze zeruje flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->primary() ) ) {
// tylko dla jednego członu
// McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner );
}
}
if( SetFlag( iEventallFlag, -1 ) ) {
// McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner );
}
}
else if( ( fDistance > 0 ) && ( eventfilter > 0 ) ) {
// event2, eventall2
if( SetFlag( iEventFlag, -2 ) ) {
// zawsze ustawia flagę sprawdzenia, jak mechanik dosiądzie, to się nie wykona
if( ( Owner->Mechanik != nullptr )
&& ( Owner->Mechanik->primary() ) ) {
// tylko dla jednego członu
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner );
}
}
if( SetFlag( iEventallFlag, -2 ) ) {
// sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner );
}
}
}
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 ) );
if( bCanSkip ) {
// tylko główna oś przenosi pojazd do innego toru
// zdejmujemy pojazd z dotychczasowego toru
Owner->MyTrack->RemoveDynamicObject( Owner );
}
dir = fDirection;
if (pCurrentTrack->eType == tt_Cross)
{
if (!SetCurrentTrack(pCurrentTrack->Connected(iSegment, fDirection), 0))
return false; // wyjście z błędem
}
else if (!SetCurrentTrack(pCurrentTrack->Connected(-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 ) );
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->Connected(iSegment, fDirection), 1))
return false; // wyjście z błędem
}
else if (!SetCurrentTrack(pCurrentTrack->Connected(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->CabNo != 0) {
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner, -1.0 );
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner, -1.0 );
}
pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner, -1.0 );
pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner, -1.0 );
}
fCurrentDistance = s;
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 "GL/glew.h"
#include "GL/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
//---------------------------------------------------------------------------