mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
2. Możliwość zdefiniowania koloru tła ekranu ładowania w eu07.ini. 3. Dodanie logowania ruchu ramek WM_COPYDATA do oddzielnego pliku. 4. Dodana ramka skrócona aktywnych AI. 5. Dodana ramka sterowania uszkodzeniami pojazdów. 6. Dodanie kręciołka od świateł (w tym trakcja wielokrotna). 7. Rozbudowa asynchronów, m.in. tempomat, zadawanie siły (w kN), przeciwpoślizg, czyste ED itd. 8. Dodanie animacji drtzwi odskokowo-przesuwnych. 9. Dodanie możliwości uszkadzania pojazdów (EN57). 10. Uruchomienie sprzęgu WN, zwłaszcza w asynchronach - do przejrzenia logowanie braków napięcia. 11. Wyłączanie radiostopu przez wyłączanie radia, a nie przez ruch zaworem maszynisty. 12. Usunięcie wyłącznika ciśnieniowego w EN57 (proteza, trzeba zrobić wpis na to). 13. Wstępna wersja hamowania rekuperacyjnego wraz z przechodzeniem na hamowanie oporowe. 14. Cała masa nowych zmiennych stanu dostępna dla ekranu (Pythona). 15. Nowa stara smuga z dawnego SPKSu. 16. Inne, które mogłem zapomnieć lub nie uszczegółowić. 17. Poprawione wyświetlanie haslera
724 lines
27 KiB
C++
724 lines
27 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, 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) ? (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?
|
|
};
|