forked from eu07/maszyna
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTraction.cpp
723 lines (690 loc) · 26.9 KB
/
Traction.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
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
/*
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, Maciej Czapkiewicz and others
*/
#include "system.hpp"
#include "classes.hpp"
#pragma hdrstop
#include "Traction.h"
#include "mctools.hpp"
#include "Globals.h"
#include "Usefull.h"
#include "TractionPower.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
/*
=== Koncepcja dwustronnego zasilania sekcji sieci trakcyjnej, Ra 2014-02 ===
0. Każde przęsło sieci może mieć wpisaną nazwę zasilacza, a także napięcie
nominalne i maksymalny prąd, które stanowią redundancję do danych zasilacza.
Rezystancja może się zmieniać, materiał i grubość drutu powinny być wspólny
dla segmentu. Podanie punktów umożliwia łączenie przęseł w listy dwukierunkowe,
co usprawnia wyszukiwania kolejnych przeseł podczas jazdy. Dla bieżni wspólnej
powinna być podana nazwa innego przęsła w parametrze "parallel". Wskaźniki
na przęsła bieżni wspólnej mają być układane w jednokierunkowy pierścień.
1. Problemem jest ustalenie topologii sekcji dla linii dwutorowych. Nad każdym
torem powinna znajdować się oddzielna sekcja sieci, aby mogła zostać odłączona
w przypadku zwarcia. Sekcje nad równoległymi torami są również łączone
równolegle przez kabiny sekcyjne, co zmniejsza płynące prądy i spadki napięć.
2. Drugim zagadnieniem jest zasilanie sekcji jednocześnie z dwóch stron, czyli
sekcja musi mieć swoją nazwę oraz wskazanie dwóch zasilaczy ze wskazaniem
geograficznym ich położenia. Dodatkową trudnością jest brak połączenia
pomiędzy segmentami naprężania. Podsumowując, każdy segment naprężania powinien
mieć przypisanie do sekcji zasilania, a dodatkowo skrajne segmenty powinny
wskazywać dwa różne zasilacze.
3. Zasilaczem sieci może być podstacja, która w wersji 3kV powinna generować
pod obciążeniem napięcie maksymalne rzędu 3600V, a spadek napięcia następuje
na jej rezystancji wewnętrznej oraz na przewodach trakcyjnych. Zasilaczem może
być również kabina sekcyjna, która jest zasilana z podstacji poprzez przewody
trakcyjne.
4. Dla uproszczenia można przyjąć, że zasilanie pojazdu odbywać się będzie z
dwóch sąsiednich podstacji, pomiędzy którymi może być dowolna liczba kabin
sekcyjnych. W przypadku wyłączenia jednej z tych podstacji, zasilanie może
być pobierane z kolejnej. Łącznie należy rozważać 4 najbliższe podstacje,
przy czym do obliczeń można przyjmować 2 z nich.
5. Przęsła sieci są łączone w listę dwukierunkową, więc wystarczy nazwę
sekcji wpisać w jednym z nich, wpisanie w każdym nie przeszkadza.
Alternatywnym sposobem łączenia segmentów naprężania może być wpisywanie
nazw przęseł jako "parallel", co może być uciążliwe dla autorów scenerii.
W skrajnych przęsłach należałoby dodatkowo wpisać nazwę zasilacza, będzie
to jednocześnie wskazanie przęsła, do którego podłączone są przewody
zasilające. Konieczne jest odróżnienie nazwy sekcji od nazwy zasilacza, co
można uzyskać różnicując ich nazwy albo np. specyficznie ustawiając wartość
prądu albo napięcia przęsła.
6. Jeśli dany segment naprężania jest wspólny dla dwóch sekcji zasilania,
to jedno z przęseł musi mieć nazwę "*" (gwiazdka), co będzie oznaczało, że
ma zamontowany izolator. Dla uzyskania efektów typu łuk elektryczny, należało
by wskazać położenie izolatora i jego długość (ew. typ).
7. Również w parametrach zasilacza należało by określić, czy jest podstacją,
czy jedynie kabiną sekcyjną. Różnić się one będą fizyką działania.
8. Dla zbudowanej topologii sekcji i zasilaczy należało by zbudować dynamiczny
schemat zastępczy. Dynamika polega na wyłączaniu sekcji ze zwarciem oraz
przeciążonych podstacji. Musi być też możliwość wyłączenia sekcji albo
podstacji za pomocą eventu.
9. Dla każdej sekcji musi być tworzony obiekt, wskazujący na podstacje
zasilające na końcach, stan włączenia, zwarcia, przepięcia. Do tego obiektu
musi wskazywać każde przęsło z aktywnym zasilaniem.
z.1 z.2 z.3
-=-a---1*1---c-=---c---=-c--2*2--e---=---e-3-*-3--g-=-
-=-b---1*1---d-=---d---=-d--2*2--f---=---e-3-*-3--h-=-
nazwy sekcji (@): a,b,c,d,e,f,g,h
nazwy zasilaczy (#): 1,2,3
przęsło z izolatorem: *
przęsła bez wskazania nazwy sekcji/zasilacza: -
segment napręzania: =-x-=
segment naprężania z izolatorem: =---@---#*#---@---=
segment naprężania bez izolatora: =--------@------=
Obecnie brak nazwy sekcji nie jest akceptowany i każde przęsło musi mieć wpisaną
jawnie nazwę sekcji, ewentualnie nazwę zasilacza (zostanie zastąpiona wskazaniem
sekcji z sąsiedniego przęsła).
*/
TTraction::TTraction()
{
pPoint1 = pPoint2 = pPoint3 = pPoint4 = vector3(0, 0, 0);
// vFront=vector3(0,0,1);
// vUp=vector3(0,1,0);
// vLeft=vector3(1,0,0);
fHeightDifference = 0;
iNumSections = 0;
iLines = 0;
// dwFlags= 0;
Wires = 2;
// fU=fR= 0;
uiDisplayList = 0;
asPowerSupplyName = "";
// mdPole= NULL;
// ReplacableSkinID= 0;
hvNext[0] = hvNext[1] = NULL;
iLast = 1; //że niby ostatni drut
psPowered = psPower[0] = psPower[1] = NULL; // na początku zasilanie nie podłączone
psSection = NULL; // na początku nie podłączone
hvParallel = NULL; // normalnie brak bieżni wspólnej
fResistance[0] = fResistance[1] = -1.0; // trzeba dopiero policzyć
iTries = 0; // ile razy próbować podłączyć, ustawiane później
}
TTraction::~TTraction()
{
if (!Global::bUseVBO)
glDeleteLists(uiDisplayList, 1);
}
void TTraction::Optimize()
{
if (Global::bUseVBO)
return;
uiDisplayList = glGenLists(1);
glNewList(uiDisplayList, GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, 0);
// glColor3ub(0,0,0); McZapkie: to do render
// glPushMatrix();
// glTranslatef(pPosition.x,pPosition.y,pPosition.z);
if (Wires != 0)
{
// Dlugosc odcinka trakcji 'Winger
double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z);
if (Wires == 2)
WireOffset = 0;
// Przewoz jezdny 1 'Marcin
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y,
pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glVertex3f(pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y,
pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glEnd();
// Nie wiem co 'Marcin
vector3 pt1, pt2, pt3, pt4, v1, v2;
v1 = pPoint4 - pPoint3;
v2 = pPoint2 - pPoint1;
float step = 0;
if (iNumSections > 0)
step = 1.0f / (float)iNumSections;
float f = step;
float mid = 0.5;
float t;
// Przewod nosny 'Marcin
if (Wires != 1)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint3.x, pPoint3.y, pPoint3.z);
for (int i = 0; i < iNumSections - 1; i++)
{
pt3 = pPoint3 + v1 * f;
t = (1 - fabs(f - mid) * 2);
if ((Wires < 4) || ((i != 0) && (i != iNumSections - 2)))
glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference, pt3.z);
f += step;
}
glVertex3f(pPoint4.x, pPoint4.y, pPoint4.z);
glEnd();
}
// Drugi przewod jezdny 'Winger
if (Wires > 2)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint1.y,
pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glVertex3f(pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pPoint2.y,
pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
glEnd();
}
f = step;
if (Wires == 4)
{
glBegin(GL_LINE_STRIP);
glVertex3f(pPoint3.x, pPoint3.y - 0.65f * fHeightDifference, pPoint3.z);
for (int i = 0; i < iNumSections - 1; i++)
{
pt3 = pPoint3 + v1 * f;
t = (1 - fabs(f - mid) * 2);
glVertex3f(
pt3.x,
pt3.y - sqrt(t) * fHeightDifference -
((i == 0) || (i == iNumSections - 2) ? 0.25f * fHeightDifference : +0.05),
pt3.z);
f += step;
}
glVertex3f(pPoint4.x, pPoint4.y - 0.65f * fHeightDifference, pPoint4.z);
glEnd();
}
f = step;
// Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger
if (Wires != 1)
{
glBegin(GL_LINES);
for (int i = 0; i < iNumSections - 1; i++)
{
float flo, flo1;
flo = (Wires == 4 ? 0.25f * fHeightDifference : 0);
flo1 = (Wires == 4 ? +0.05 : 0);
pt3 = pPoint3 + v1 * f;
pt4 = pPoint1 + v2 * f;
t = (1 - fabs(f - mid) * 2);
if ((i % 2) == 0)
{
glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference -
((i == 0) || (i == iNumSections - 2) ? flo : flo1),
pt3.z);
glVertex3f(pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pt4.y,
pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
}
else
{
glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference -
((i == 0) || (i == iNumSections - 2) ? flo : flo1),
pt3.z);
glVertex3f(pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset, pt4.y,
pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset);
}
if ((Wires == 4) && ((i == 1) || (i == iNumSections - 3)))
{
glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference - 0.05, pt3.z);
glVertex3f(pt3.x, pt3.y - sqrt(t) * fHeightDifference, pt3.z);
}
// endif;
f += step;
}
glEnd();
}
glEndList();
}
}
/*
void TTraction::InitCenter(vector3 Angles, vector3 pOrigin)
{
pPosition= (pPoint2+pPoint1)*0.5f;
fSquaredRadius= SquareMagnitude((pPoint2-pPoint1)*0.5f);
} */
void TTraction::RenderDL(float mgn) // McZapkie: mgn to odleglosc od obserwatora
{
// McZapkie: ustalanie przezroczystosci i koloru linii:
if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana
{
// glDisable(GL_LIGHTING); //aby nie używało wektorów normalnych do kolorowania
glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste
if (!Global::bSmoothTraction)
glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient
float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness
if (linealpha > 1.2)
linealpha = 1.2; // zbyt grube nie są dobre
glLineWidth(linealpha);
if (linealpha > 1.0)
linealpha = 1.0;
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia
float r, g, b;
switch (Material)
{ // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były
// trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor
case 1:
if (TestFlag(DamageFlag, 1))
{
r = 0.00000;
g = 0.32549;
b = 0.2882353; // zielona miedź
}
else
{
r = 0.35098;
g = 0.22549;
b = 0.1; // czerwona miedź
}
break;
case 2:
if (TestFlag(DamageFlag, 1))
{
r = 0.10;
g = 0.10;
b = 0.10; // czarne Al
}
else
{
r = 0.25;
g = 0.25;
b = 0.25; // srebrne Al
}
break;
// tymczasowo pokazanie zasilanych odcinków
case 4:
r = 0.5;
g = 0.5;
b = 1.0;
break; // niebieskie z podłączonym zasilaniem
case 5:
r = 1.0;
g = 0.0;
b = 0.0;
break; // czerwone z podłączonym zasilaniem 1
case 6:
r = 0.0;
g = 1.0;
b = 0.0;
break; // zielone z podłączonym zasilaniem 2
case 7:
r = 1.0;
g = 1.0;
b = 0.0;
break; //żółte z podłączonym zasilaniem z obu stron
}
if (DebugModeFlag)
if (hvParallel)
{ // jeśli z bieżnią wspólną, to dodatkowo przyciemniamy
r *= 0.6;
g *= 0.6;
b *= 0.6;
}
r *= Global::ambientDayLight[0]; // w zaleźności od koloru swiatła
g *= Global::ambientDayLight[1];
b *= Global::ambientDayLight[2];
if (linealpha > 1.0)
linealpha = 1.0; // trzeba ograniczyć do <=1
glColor4f(r, g, b, linealpha);
if (!uiDisplayList)
Optimize(); // generowanie DL w miarę potrzeby
glCallList(uiDisplayList);
glLineWidth(1.0);
glEnable(GL_LINE_SMOOTH);
// glEnable(GL_LIGHTING); //bez tego się modele nie oświetlają
}
}
int TTraction::RaArrayPrepare()
{ // przygotowanie tablic do skopiowania do VBO (zliczanie wierzchołków)
// if (bVisible) //o ile w ogóle widać
switch (Wires)
{
case 1:
iLines = 2;
break;
case 2:
iLines = iNumSections ? 4 * (iNumSections)-2 + 2 : 4;
break;
case 3:
iLines = iNumSections ? 4 * (iNumSections)-2 + 4 : 6;
break;
case 4:
iLines = iNumSections ? 4 * (iNumSections)-2 + 6 : 8;
break;
default:
iLines = 0;
}
// else iLines=0;
return iLines;
};
void TTraction::RaArrayFill(CVertNormTex *Vert)
{ // wypełnianie tablic VBO
CVertNormTex *old = Vert;
double ddp = hypot(pPoint2.x - pPoint1.x, pPoint2.z - pPoint1.z);
if (Wires == 2)
WireOffset = 0;
// jezdny
Vert->x = pPoint1.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint1.y;
Vert->z = pPoint1.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
++Vert;
Vert->x = pPoint2.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint2.y;
Vert->z = pPoint2.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
++Vert;
// Nie wiem co 'Marcin
vector3 pt1, pt2, pt3, pt4, v1, v2;
v1 = pPoint4 - pPoint3;
v2 = pPoint2 - pPoint1;
float step = 0;
if (iNumSections > 0)
step = 1.0f / (float)iNumSections;
float f = step;
float mid = 0.5;
float t;
// Przewod nosny 'Marcin
if (Wires > 1)
{ // lina nośna w kawałkach
Vert->x = pPoint3.x;
Vert->y = pPoint3.y;
Vert->z = pPoint3.z;
++Vert;
for (int i = 0; i < iNumSections - 1; i++)
{
pt3 = pPoint3 + v1 * f;
t = (1 - fabs(f - mid) * 2);
Vert->x = pt3.x;
Vert->y = pt3.y - sqrt(t) * fHeightDifference;
Vert->z = pt3.z;
++Vert;
Vert->x = pt3.x; // drugi raz, bo nie jest line_strip
Vert->y = pt3.y - sqrt(t) * fHeightDifference;
Vert->z = pt3.z;
++Vert;
f += step;
}
Vert->x = pPoint4.x;
Vert->y = pPoint4.y;
Vert->z = pPoint4.z;
++Vert;
}
// Drugi przewod jezdny 'Winger
if (Wires == 3)
{
Vert->x = pPoint1.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint1.y;
Vert->z = pPoint1.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
++Vert;
Vert->x = pPoint2.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pPoint2.y;
Vert->z = pPoint2.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
++Vert;
}
f = step;
// Przewody pionowe (wieszaki) 'Marcin, poprawki na 2 przewody jezdne 'Winger
if (Wires > 1)
{
for (int i = 0; i < iNumSections - 1; i++)
{
pt3 = pPoint3 + v1 * f;
pt4 = pPoint1 + v2 * f;
t = (1 - fabs(f - mid) * 2);
Vert->x = pt3.x;
Vert->y = pt3.y - sqrt(t) * fHeightDifference;
Vert->z = pt3.z;
++Vert;
if ((i % 2) == 0)
{
Vert->x = pt4.x - (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pt4.y;
Vert->z = pt4.z - (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
}
else
{
Vert->x = pt4.x + (pPoint2.z / ddp - pPoint1.z / ddp) * WireOffset;
Vert->y = pt4.y;
Vert->z = pt4.z + (-pPoint2.x / ddp + pPoint1.x / ddp) * WireOffset;
}
++Vert;
f += step;
}
}
if ((Vert - old) != iLines)
WriteLog("!!! Wygenerowano punktów " + AnsiString(Vert - old) + ", powinno być " +
AnsiString(iLines));
};
void TTraction::RenderVBO(float mgn, int iPtr)
{ // renderowanie z użyciem VBO
if (Wires != 0 && !TestFlag(DamageFlag, 128)) // rysuj jesli sa druty i nie zerwana
{
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_LIGHTING); // aby nie używało wektorów normalnych do kolorowania
glColor4f(0, 0, 0, 1); // jak nieznany kolor to czarne nieprzezroczyste
if (!Global::bSmoothTraction)
glDisable(GL_LINE_SMOOTH); // na liniach kiepsko wygląda - robi gradient
float linealpha = 5000 * WireThickness / (mgn + 1.0); //*WireThickness
if (linealpha > 1.2)
linealpha = 1.2; // zbyt grube nie są dobre
glLineWidth(linealpha);
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia
float r, g, b;
switch (Material)
{ // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były
// trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor
case 1:
if (TestFlag(DamageFlag, 1))
{
r = 0.00000;
g = 0.32549;
b = 0.2882353; // zielona miedź
}
else
{
r = 0.35098;
g = 0.22549;
b = 0.1; // czerwona miedź
}
break;
case 2:
if (TestFlag(DamageFlag, 1))
{
r = 0.10;
g = 0.10;
b = 0.10; // czarne Al
}
else
{
r = 0.25;
g = 0.25;
b = 0.25; // srebrne Al
}
break;
// tymczasowo pokazanie zasilanych odcinków
case 4:
r = 0.5;
g = 0.5;
b = 1.0;
break; // niebieskie z podłączonym zasilaniem
case 5:
r = 1.0;
g = 0.0;
b = 0.0;
break; // czerwone z podłączonym zasilaniem 1
case 6:
r = 0.0;
g = 1.0;
b = 0.0;
break; // zielone z podłączonym zasilaniem 2
case 7:
r = 1.0;
g = 1.0;
b = 0.0;
break; //żółte z podłączonym zasilaniem z obu stron
}
r = r * Global::ambientDayLight[0]; // w zaleznosci od koloru swiatla
g = g * Global::ambientDayLight[1];
b = b * Global::ambientDayLight[2];
if (linealpha > 1.0)
linealpha = 1.0; // trzeba ograniczyć do <=1
glColor4f(r, g, b, linealpha);
glDrawArrays(GL_LINES, iPtr, iLines);
glLineWidth(1.0);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_LIGHTING); // bez tego się modele nie oświetlają
}
};
int TTraction::TestPoint(vector3 *Point)
{ // sprawdzanie, czy przęsła można połączyć
if (!hvNext[0])
if (pPoint1.Equal(Point))
return 0;
if (!hvNext[1])
if (pPoint2.Equal(Point))
return 1;
return -1;
};
void TTraction::Connect(int my, TTraction *with, int to)
{ //łączenie segmentu (with) od strony (my) do jego (to)
if (my)
{ // do mojego Point2
hvNext[1] = with;
iNext[1] = to;
}
else
{ // do mojego Point1
hvNext[0] = with;
iNext[0] = to;
}
if (to)
{ // do jego Point2
with->hvNext[1] = this;
with->iNext[1] = my;
}
else
{ // do jego Point1
with->hvNext[0] = this;
with->iNext[0] = my;
}
if (hvNext[0]) // jeśli z obu stron podłączony
if (hvNext[1])
iLast = 0; // to nie jest ostatnim
if (with->hvNext[0]) // temu też, bo drugi raz łączenie się nie nie wykona
if (with->hvNext[1])
with->iLast = 0; // to nie jest ostatnim
};
bool TTraction::WhereIs()
{ // ustalenie przedostatnich przęseł
if (iLast)
return (iLast == 1); // ma już ustaloną informację o położeniu
if (hvNext[0] ? hvNext[0]->iLast == 1 : false) // jeśli poprzedni jest ostatnim
iLast = 2; // jest przedostatnim
else if (hvNext[1] ? hvNext[1]->iLast == 1 : false) // jeśli następny jest ostatnim
iLast = 2; // jest przedostatnim
return (iLast == 1); // ostatnie będą dostawać zasilanie
};
void TTraction::Init()
{ // przeliczenie parametrów
vParametric = pPoint2 - pPoint1; // wektor mnożników parametru dla równania parametrycznego
};
void TTraction::ResistanceCalc(int d, double r, TTractionPowerSource *ps)
{ //(this) jest przęsłem zasilanym, o rezystancji (r), policzyć rezystancję zastępczą sąsiednich
if (d >= 0)
{ // podążanie we wskazanym kierunku
TTraction *t = hvNext[d], *p;
if (ps)
psPower[d ^ 1] = ps; // podłączenie podanego
else
ps = psPower[d ^ 1]; // zasilacz od przeciwnej strony niż idzie analiza
d = iNext[d]; // kierunek
// double r; //sumaryczna rezystancja
if (DebugModeFlag) // tylko podczas testów
Material = 4; // pokazanie, że to przęsło ma podłączone zasilanie
while (t ? !t->psPower[d] : false) // jeśli jest jakiś kolejny i nie ma ustalonego zasilacza
{ // ustawienie zasilacza i policzenie rezystancji zastępczej
if (DebugModeFlag) // tylko podczas testów
if (t->Material != 4) // przęsła zasilającego nie modyfikować
{
if (t->Material < 4)
t->Material = 4; // tymczasowo, aby zmieniła kolor
t->Material |= d ? 2 : 1; // kolor zależny od strony, z której jest zasilanie
}
t->psPower[d] = ps; // skopiowanie wskaźnika zasilacza od danej strony
t->fResistance[d] = r; // wpisanie rezystancji w kierunku tego zasilacza
r += t->fResistivity * Length3(t->vParametric); // doliczenie oporu kolejnego odcinka
p = t; // zapamiętanie dotychczasowego
t = p->hvNext[d ^ 1]; // podążanie w tę samą stronę
d = p->iNext[d ^ 1];
// w przypadku zapętlenia sieci może się zawiesić?
}
}
else
{ // podążanie w obu kierunkach, można by rekurencją, ale szkoda zasobów
r = 0.5 * fResistivity *
Length3(vParametric); // powiedzmy, że w zasilanym przęśle jest połowa
if (fResistance[0] == 0.0)
ResistanceCalc(0, r); // do tyłu (w stronę Point1)
if (fResistance[1] == 0.0)
ResistanceCalc(1, r); // do przodu (w stronę Point2)
}
};
void TTraction::PowerSet(TTractionPowerSource *ps)
{ // podłączenie przęsła do zasilacza
if (ps->bSection)
psSection = ps; // ustalenie sekcji zasilania
else
{ // ustalenie punktu zasilania (nie ma jeszcze połączeń między przęsłami)
psPowered = ps; // ustawienie bezpośredniego zasilania dla przęsła
psPower[0] = psPower[1] = ps; // a to chyba nie jest dobry pomysł, bo nawet zasilane przęsło
// powinno mieć wskazania na inne
fResistance[0] = fResistance[1] = 0.0; // a liczy się tylko rezystancja zasilacza
}
};
double TTraction::VoltageGet(double u, double i)
{ // pobranie napięcia na przęśle po podłączeniu do niego rezystancji (res) - na razie jest to prąd
if (!psSection)
if (!psPowered)
return NominalVoltage; // jak nie ma zasilacza, to napięcie podane w przęśle
// na początek można założyć, że wszystkie podstacje mają to samo napięcie i nie płynie prąd
// pomiędzy nimi
// dla danego przęsła mamy 3 źródła zasilania
// 1. zasilacz psPower[0] z rezystancją fResistance[0] oraz jego wewnętrzną
// 2. zasilacz psPower[1] z rezystancją fResistance[1] oraz jego wewnętrzną
// 3. zasilacz psPowered z jego wewnętrzną rezystancją dla przęseł zasilanych bezpośrednio
double res = (i != 0.0) ? fabs(u / i) : 10000.0;
if (psPowered)
return psPowered->CurrentGet(res) *
res; // yB: dla zasilanego nie baw się w gwiazdy, tylko bierz bezpośrednio
double r0t, r1t, r0g, r1g;
double u0, u1, i0, i1;
r0t = fResistance[0]; //średni pomysł, ale lepsze niż nic
r1t = fResistance[1]; // bo nie uwzględnia spadków z innych pojazdów
if (psPower[0] && psPower[1])
{ // gdy przęsło jest zasilane z obu stron - mamy trójkąt: res, r0t, r1t
// yB: Gdy wywali podstacja, to zaczyna się robić nieciekawie - napięcie w sekcji na jednym
// końcu jest równe zasilaniu,
// yB: a na drugim końcu jest równe 0. Kolejna sprawa to rozróżnienie uszynienia sieci na
// podstacji/odłączniku (czyli
// yB: potencjał masy na sieci) od braku zasilania (czyli odłączenie źródła od sieci i brak
// jego wpływu na napięcie).
if ((r0t > 0.0) && (r1t > 0.0))
{ // rezystancje w mianowniku nie mogą być zerowe
r0g = res + r0t + (res * r0t) / r1t; // przeliczenie z trójkąta na gwiazdę
r1g = res + r1t + (res * r1t) / r0t;
// pobierane są prądy dla każdej rezystancji, a suma jest mnożona przez rezystancję
// pojazdu w celu uzyskania napięcia
i0 = psPower[0]->CurrentGet(r0g); // oddzielnie dla sprawdzenia
i1 = psPower[1]->CurrentGet(r1g);
return (i0 + i1) * res;
}
else if (r0t >= 0.0)
return psPower[0]->CurrentGet(res + r0t) * res;
else if (r1t >= 0.0)
return psPower[1]->CurrentGet(res + r1t) * res;
else
return 0.0; // co z tym zrobić?
}
else if (psPower[0] && (r0t >= 0.0))
{ // jeśli odcinek podłączony jest tylko z jednej strony
return psPower[0]->CurrentGet(res + r0t) * res;
}
else if (psPower[1] && (r1t >= 0.0))
return psPower[1]->CurrentGet(res + r1t) * res;
return 0.0; // gdy nie podłączony wcale?
};