Merge branch 'tmj-dev' into milek-dev

This commit is contained in:
milek7
2018-12-31 23:49:10 +01:00
20 changed files with 575 additions and 489 deletions

View File

@@ -244,24 +244,10 @@ void TAnimContainer::UpdateModel() {
}
if (fRotateSpeed != 0.0)
{
/*
double dif= fDesiredAngle-fAngle;
double s= fRotateSpeed*sign(dif)*Timer::GetDeltaTime();
if ((abs(s)-abs(dif))>0)
fAngle= fDesiredAngle;
else
fAngle+= s;
while (fAngle>360) fAngle-= 360;
while (fAngle<-360) fAngle+= 360;
pSubModel->SetRotate(vRotateAxis,fAngle);
*/
bool anim = false;
auto dif = vDesiredAngles - vRotateAngles;
double s;
s = fRotateSpeed * sign(dif.x) * Timer::GetDeltaTime();
s = std::abs( fRotateSpeed ) * sign(dif.x) * Timer::GetDeltaTime();
if (fabs(s) >= fabs(dif.x))
vRotateAngles.x = vDesiredAngles.x;
else
@@ -269,7 +255,7 @@ void TAnimContainer::UpdateModel() {
vRotateAngles.x += s;
anim = true;
}
s = fRotateSpeed * sign(dif.y) * Timer::GetDeltaTime();
s = std::abs( fRotateSpeed ) * sign(dif.y) * Timer::GetDeltaTime();
if (fabs(s) >= fabs(dif.y))
vRotateAngles.y = vDesiredAngles.y;
else
@@ -277,7 +263,7 @@ void TAnimContainer::UpdateModel() {
vRotateAngles.y += s;
anim = true;
}
s = fRotateSpeed * sign(dif.z) * Timer::GetDeltaTime();
s = std::abs( fRotateSpeed ) * sign(dif.z) * Timer::GetDeltaTime();
if (fabs(s) >= fabs(dif.z))
vRotateAngles.z = vDesiredAngles.z;
else
@@ -285,22 +271,27 @@ void TAnimContainer::UpdateModel() {
vRotateAngles.z += s;
anim = true;
}
while (vRotateAngles.x >= 360)
vRotateAngles.x -= 360;
while (vRotateAngles.x <= -360)
vRotateAngles.x += 360;
while (vRotateAngles.y >= 360)
vRotateAngles.y -= 360;
while (vRotateAngles.y <= -360)
vRotateAngles.y += 360;
while (vRotateAngles.z >= 360)
vRotateAngles.z -= 360;
while (vRotateAngles.z <= -360)
vRotateAngles.z += 360;
if (vRotateAngles.x == 0.0)
if (vRotateAngles.y == 0.0)
if (vRotateAngles.z == 0.0)
iAnim &= ~1; // kąty są zerowe
// HACK: negative speed allows to work around legacy behaviour, where desired angle > 360 meant permanent rotation
if( fRotateSpeed > 0.0 ) {
while( vRotateAngles.x >= 360 )
vRotateAngles.x -= 360;
while( vRotateAngles.x <= -360 )
vRotateAngles.x += 360;
while( vRotateAngles.y >= 360 )
vRotateAngles.y -= 360;
while( vRotateAngles.y <= -360 )
vRotateAngles.y += 360;
while( vRotateAngles.z >= 360 )
vRotateAngles.z -= 360;
while( vRotateAngles.z <= -360 )
vRotateAngles.z += 360;
}
if( ( vRotateAngles.x == 0.0 )
&& ( vRotateAngles.y == 0.0 )
&& ( vRotateAngles.z == 0.0 ) ) {
iAnim &= ~1; // kąty są zerowe
}
if (!anim)
{ // nie potrzeba przeliczać już
fRotateSpeed = 0.0;

View File

@@ -152,6 +152,7 @@ const double EasyAcceleration = 0.85; //[m/ss]
const double HardAcceleration = 9.81;
const double PrepareTime = 2.0; //[s] przebłyski świadomości przy odpalaniu
bool WriteLogFlag = false;
double const deltalog = 0.05; // przyrost czasu
std::string StopReasonTable[] = {
// przyczyny zatrzymania ruchu AI
@@ -833,7 +834,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
double v; // prędkość
double d; // droga
double d_to_next_sem = 10000.0; //ustaiwamy na pewno dalej niż widzi AI
bool isatpassengerstop { false }; // true if the consist is within acceptable range of w4 post
IsAtPassengerStop = false;
TCommandType go = TCommandType::cm_Unknown;
eSignNext = NULL;
// te flagi są ustawiane tutaj, w razie potrzeby
@@ -921,7 +922,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
sSpeedTable[i].iFlags = 0;
}
}
isatpassengerstop = (
IsAtPassengerStop = (
( sSpeedTable[ i ].fDist <= passengerstopmaxdistance )
// Ra 2F1I: odległość plus długość pociągu musi być mniejsza od długości
// peronu, chyba że pociąg jest dłuższy, to wtedy minimalna.
@@ -941,7 +942,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
if( mvOccupied->Vel > 0.3 ) {
// jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0) to będzie zatrzymanie
sSpeedTable[ i ].fVelNext = 0;
} else if( true == isatpassengerstop ) {
} else if( true == IsAtPassengerStop ) {
// jeśli się zatrzymał przy W4, albo stał w momencie zobaczenia W4
if( !AIControllFlag ) {
// w razie przełączenia na AI ma nie podciągać do W4, gdy użytkownik zatrzymał za daleko
@@ -1032,7 +1033,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// jeśli są dalsze stacje, czekamy do godziny odjazdu
if (TrainParams->IsTimeToGo(simulation::Time.data().wHour, simulation::Time.data().wMinute)) {
// z dalszą akcją czekamy do godziny odjazdu
isatpassengerstop = false;
IsAtPassengerStop = false;
// przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
fLastStopExpDist = mvOccupied->DistCounter + 0.050 + 0.001 * fLength;
TrainParams->StationIndexInc(); // przejście do następnej
@@ -1373,7 +1374,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
// 2014-02: jeśli stoi, a ma do przejechania kawałek, to niech jedzie
if( ( mvOccupied->Vel < 0.01 )
&& ( true == TestFlag( sSpeedTable[ i ].iFlags, ( spEnabled | spEvent | spPassengerStopPoint ) ) )
&& ( false == isatpassengerstop ) ) {
&& ( false == IsAtPassengerStop ) ) {
// ma podjechać bliżej - czy na pewno w tym miejscu taki warunek?
a = ( ( d > passengerstopmaxdistance ) || ( ( iDrivigFlags & moveStopCloser ) != 0 ) ?
fAcc :
@@ -1454,7 +1455,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
}
//analiza spisanych z tabelki ograniczeń i nadpisanie aktualnego
if( ( true == isatpassengerstop ) && ( mvOccupied->Vel < 0.01 ) ) {
if( ( true == IsAtPassengerStop ) && ( mvOccupied->Vel < 0.01 ) ) {
// if stopped at a valid passenger stop, hold there
fVelDes = 0.0;
}
@@ -1622,6 +1623,11 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche,
mvOccupied->TrainType == dt_EZT ? -0.55 :
mvOccupied->TrainType == dt_DMU ? -0.45 :
-0.2 );
// HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
if( ( mvOccupied->TrainType == dt_EZT )
&& ( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) ) {
fAccThreshold += 0.10;
}
}
// TrainParams=NewTrainParams;
// if (TrainParams)
@@ -1670,11 +1676,6 @@ void TController::CloseLog()
if (WriteLogFlag)
{
LogFile.close();
// if WriteLogFlag)
// CloseFile(AILogFile);
/* append(AIlogFile);
writeln(AILogFile,ElapsedTime5:2,": QUIT");
close(AILogFile); */
}
};
@@ -1737,11 +1738,8 @@ void TController::Activation()
mvOccupied->DirectionForward(); // kierunek na 0
while (mvOccupied->ActiveDir > 0)
mvOccupied->DirectionBackward();
if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder < 0 ? 1 : 0].CouplingFlag,
ctrain_controll))
{
mvControlling->MainSwitch(
false); // dezaktywacja czuwaka, jeśli przejście do innego członu
if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder < 0 ? 1 : 0].CouplingFlag, ctrain_controll)) {
mvControlling->MainSwitch( false); // dezaktywacja czuwaka, jeśli przejście do innego członu
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca w opuszczanym pojeździe
// mvOccupied->BrakeLevelSet((mvOccupied->BrakeHandle==FVel6)?4:-2); //odcięcie na
// zaworze maszynisty, FVel6 po drugiej stronie nie luzuje
@@ -1751,8 +1749,7 @@ void TController::Activation()
mvOccupied->ActiveCab = mvOccupied->CabNo; // użytkownik moze zmienić ActiveCab wychodząc
mvOccupied->CabDeactivisation(); // tak jest w Train.cpp
// przejście AI na drugą stronę EN57, ET41 itp.
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? 1 : 0].CouplingFlag,
ctrain_controll))
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? 1 : 0].CouplingFlag, ctrain_controll))
{ // jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego
d = iDirection * d->DirectionGet() < 0 ? d->Next() :
d->Prev(); // przechodzimy do następnego członu
@@ -1816,8 +1813,7 @@ void TController::AutoRewident()
// · masa (jako suma) -> jest w (fMass)
while (d)
{ // klasyfikacja pojazdów wg BrakeDelays i mocy (licznik)
if (d->MoverParameters->Power <
1) // - lokomotywa - Power>1 - ale może być nieczynna na końcu...
if (d->MoverParameters->Power < 1) // - lokomotywa - Power>1 - ale może być nieczynna na końcu...
if (TestFlag(d->MoverParameters->BrakeDelays, bdelay_R))
++r; // - wagon pospieszny - jest R
else if (TestFlag(d->MoverParameters->BrakeDelays, bdelay_G))
@@ -1951,7 +1947,13 @@ void TController::AutoRewident()
0.25 );
if( mvOccupied->TrainType == dt_EZT ) {
fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
if( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) {
// HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
fNominalAccThreshold = std::max( -0.60, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
else {
fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
fBrakeReaction = 0.25;
}
else if( mvOccupied->TrainType == dt_DMU ) {
@@ -2083,13 +2085,11 @@ bool TController::CheckVehicles(TOrders user)
if (AIControllFlag) // jeśli prowadzi komputer
p->RaLightsSet(0, 0); // gasimy światła
if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector)
{ // jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o
// jeździe bezprądowej
{ // jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o jeździe bezprądowej
p->iOverheadMask = pantmask;
pantmask = pantmask << 1; // przesunięcie bitów, max. 32 pojazdy z pantografami w składzie
}
d = p->DirectionSet(d ? 1 : -1); // zwraca położenie następnego (1=zgodny,0=odwrócony -
// względem czoła składu)
d = p->DirectionSet(d ? 1 : -1); // zwraca położenie następnego (1=zgodny,0=odwrócony - względem czoła składu)
p->ctOwner = this; // dominator oznacza swoje terytorium
p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła)
}
@@ -2109,9 +2109,6 @@ bool TController::CheckVehicles(TOrders user)
Lights(
frontlights,
rearlights );
#if LOGPRESS == 0
AutoRewident(); // nastawianie hamulca do jazdy pociągowej
#endif
}
else if (OrderCurrentGet() & (Shunt | Connect))
{
@@ -2144,46 +2141,59 @@ bool TController::CheckVehicles(TOrders user)
Lights( 0, light::headlight_right );
}
}
// nastawianie hamulca do jazdy pociągowej
if( OrderCurrentGet() & ( Obey_train | Shunt ) ) {
AutoRewident();
}
}
else // Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja
// o składzie
switch (user) // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie
{
case Change_direction:
while (OrderCurrentGet() & (Change_direction))
JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek
// skanowania!
else { // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie
// Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie
switch (user) {
case Change_direction: {
while (OrderCurrentGet() & (Change_direction)) {
// zmianę kierunku też można olać, ale zmienić kierunek skanowania!
JumpToNextOrder();
}
break;
case Connect:
while (OrderCurrentGet() & (Change_direction))
JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek
// skanowania!
if (OrderCurrentGet() & (Connect))
{ // jeśli miało być łączenie, zakładamy, że jest dobrze (sprawdzić?)
}
case Connect: {
while (OrderCurrentGet() & (Change_direction)) {
// zmianę kierunku też można olać, ale zmienić kierunek skanowania!
JumpToNextOrder();
}
if (OrderCurrentGet() & (Connect)) {
// jeśli miało być łączenie, zakładamy, że jest dobrze (sprawdzić?)
iCoupler = 0; // koniec z doczepianiem
iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania
JumpToNextOrder(); // wykonanie następnej komendy
if (OrderCurrentGet() & (Change_direction))
JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek
// skanowania!
if (OrderCurrentGet() & (Change_direction)) {
// zmianę kierunku też można olać, ale zmienić kierunek skanowania!
JumpToNextOrder();
}
}
break;
case Disconnect:
while (OrderCurrentGet() & (Change_direction))
JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek
// skanowania!
if (OrderCurrentGet() & (Disconnect))
{ // wypadało by sprawdzić, czy odczepiono wagony w odpowiednim miejscu
// (iVehicleCount)
JumpToNextOrder(); // wykonanie następnej komendy
if (OrderCurrentGet() & (Change_direction))
JumpToNextOrder(); // zmianę kierunku też można olać, ale zmienić kierunek
// skanowania!
}
break;
default:
break;
}
case Disconnect: {
while (OrderCurrentGet() & (Change_direction)) {
// zmianę kierunku też można olać, ale zmienić kierunek skanowania!
JumpToNextOrder();
}
if (OrderCurrentGet() & (Disconnect)) {
// wypadało by sprawdzić, czy odczepiono wagony w odpowiednim miejscu (iVehicleCount)
JumpToNextOrder(); // wykonanie następnej komendy
if (OrderCurrentGet() & (Change_direction)) {
// zmianę kierunku też można olać, ale zmienić kierunek skanowania!
JumpToNextOrder();
}
}
break;
}
default: {
break;
}
} // switch
}
// Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61
if( ( mvOccupied->TrainType == dt_EZT )
|| ( mvOccupied->TrainType == dt_DMU )
@@ -2428,7 +2438,7 @@ bool TController::PrepareEngine()
; // zerowanie napędu
mvControlling->ConvOvldFlag = false; // reset nadmiarowego
}
else if (false == mvControlling->Mains) {
else if (false == IsLineBreakerClosed) {
while (DecSpeed(true))
; // zerowanie napędu
if( mvOccupied->TrainType == dt_SN61 ) {
@@ -2441,24 +2451,6 @@ bool TController::PrepareEngine()
|| ( std::max( mvControlling->GetTrainsetVoltage(), std::abs( mvControlling->RunningTraction.TractionVoltage ) ) > mvControlling->EnginePowerSource.CollectorParameters.MinV ) ) {
mvControlling->MainSwitch( true );
}
/*
if (mvControlling->EngineType == DieselEngine) {
// Ra 2014-06: dla SN61 trzeba wrzucić pierwszą pozycję - nie wiem, czy tutaj...
// kiedyś działało...
if (!mvControlling->MainCtrlPos) {
if( mvControlling->RList[ 0 ].R == 0.0 ) {
// gdy na pozycji 0 dawka paliwa jest zerowa, to zgaśnie dlatego trzeba zwiększyć pozycję
mvControlling->IncMainCtrl( 1 );
}
if( ( !mvControlling->ScndCtrlPos ) // jeśli bieg nie został ustawiony
&& ( !mvControlling->MotorParam[ 0 ].AutoSwitch ) // gdy biegi ręczne
&& ( mvControlling->MotorParam[ 0 ].mIsat == 0.0 ) ) { // bl,mIsat,fi,mfi
// pierwszy bieg
mvControlling->IncScndCtrl( 1 );
}
}
}
*/
}
else {
OK = ( OrderDirectionChange( iDirection, mvOccupied ) == -1 );
@@ -2860,7 +2852,7 @@ bool TController::IncSpeed()
auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 125 : 100 ) * 1000.0 };
auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) };
auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) };
auto const useseriesmodevoltage { 0.80 * mvControlling->EnginePowerSource.CollectorParameters.MaxV };
auto const useseriesmodevoltage { mvControlling->EnginePowerSource.CollectorParameters.MaxV * ( IsHeavyCargoTrain ? 0.70 : 0.80 ) };
auto const useseriesmode = (
( mvControlling->Imax > mvControlling->ImaxLo )
|| ( fVoltage < useseriesmodevoltage )
@@ -3204,8 +3196,8 @@ void TController::SpeedCntrl(double DesiredSpeed)
else if (mvControlling->ScndCtrlPosNo > 1)
{
int DesiredPos = 1 + mvControlling->ScndCtrlPosNo * ((DesiredSpeed - 1.0) / mvControlling->Vmax);
while (mvControlling->ScndCtrlPos > DesiredPos) mvControlling->DecScndCtrl(1);
while (mvControlling->ScndCtrlPos < DesiredPos) mvControlling->IncScndCtrl(1);
while( ( mvControlling->ScndCtrlPos > DesiredPos ) && ( true == mvControlling->DecScndCtrl( 1 ) ) ) { ; } // all work is done in the condition loop
while( ( mvControlling->ScndCtrlPos < DesiredPos ) && ( true == mvControlling->IncScndCtrl( 1 ) ) ) { ; } // all work is done in the condition loop
}
};
@@ -3827,36 +3819,58 @@ TController::UpdateSituation(double dt) {
TDynamicObject *p = pVehicles[0]; // pojazd na czole składu
while (p)
{ // sprawdzenie odhamowania wszystkich połączonych pojazdów
auto *vehicle { p->MoverParameters };
if (Ready) {
// bo jak coś nie odhamowane, to dalej nie ma co sprawdzać
if (p->MoverParameters->BrakePress >= 0.4) // wg UIC określone sztywno na 0.04
if (vehicle->BrakePress >= 0.4) // wg UIC określone sztywno na 0.04
{
Ready = false; // nie gotowy
// Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka...
if (AIControllFlag) // skład jak dotąd był wyluzowany
{
if( ( mvOccupied->BrakeCtrlPos == 0 ) // jest pozycja jazdy
&& ( ( p->MoverParameters->Hamulec->GetBrakeStatus() & b_dmg ) == 0 ) // brake isn't broken
&& ( p->MoverParameters->PipePress - 5.0 > -0.1 ) // jeśli ciśnienie jak dla jazdy
&& ( p->MoverParameters->Hamulec->GetCRP() > p->MoverParameters->PipePress + 0.12 ) ) { // za dużo w zbiorniku
&& ( ( vehicle->Hamulec->GetBrakeStatus() & b_dmg ) == 0 ) // brake isn't broken
&& ( vehicle->PipePress - 5.0 > -0.1 ) // jeśli ciśnienie jak dla jazdy
&& ( vehicle->Hamulec->GetCRP() > vehicle->PipePress + 0.12 ) ) { // za dużo w zbiorniku
// indywidualne luzowanko
p->MoverParameters->BrakeReleaser( 1 );
vehicle->BrakeReleaser( 1 );
}
if (p->MoverParameters->Power > 0.01) // jeśli ma silnik
if (p->MoverParameters->FuseFlag) // wywalony nadmiarowy
Need_TryAgain = true; // reset jak przy wywaleniu nadmiarowego
}
}
}
if (fReady < p->MoverParameters->BrakePress)
fReady = p->MoverParameters->BrakePress; // szukanie najbardziej zahamowanego
if (fReady < vehicle->BrakePress)
fReady = vehicle->BrakePress; // szukanie najbardziej zahamowanego
if( ( dy = p->VectorFront().y ) != 0.0 ) {
// istotne tylko dla pojazdów na pochyleniu
// ciężar razy składowa styczna grawitacji
fAccGravity -= p->MoverParameters->TotalMassxg * dy * ( p->DirectionGet() == iDirection ? 1 : -1 );
fAccGravity -= vehicle->TotalMassxg * dy * ( p->DirectionGet() == iDirection ? 1 : -1 );
}
if( ( vehicle->Power > 0.01 ) // jeśli ma silnik
&& ( vehicle->FuseFlag ) ) { // wywalony nadmiarowy
Need_TryAgain = true; // reset jak przy wywaleniu nadmiarowego
}
p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła)
}
// test state of main switch in all powered vehicles under control
IsLineBreakerClosed = ( mvOccupied->Power > 0.01 ? mvOccupied->Mains : true );
p = pVehicle;
while( ( true == IsLineBreakerClosed )
&& ( ( p = p->PrevC( coupling::control) ) != nullptr ) ) {
auto const *vehicle { p->MoverParameters };
if( vehicle->Power > 0.01 ) {
IsLineBreakerClosed = ( IsLineBreakerClosed && vehicle->Mains );
}
}
p = pVehicle;
while( ( true == IsLineBreakerClosed )
&& ( ( p = p->NextC( coupling::control ) ) != nullptr ) ) {
auto const *vehicle { p->MoverParameters };
if( vehicle->Power > 0.01 ) {
IsLineBreakerClosed = ( IsLineBreakerClosed && vehicle->Mains );
}
}
if( iDirection ) {
// siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m
fAccGravity *= iDirection;
@@ -4087,6 +4101,12 @@ TController::UpdateSituation(double dt) {
// dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji
fBrakeDist += 2 * mvOccupied->Vel;
}
if( ( mvOccupied->Vel > 0.05 )
&& ( mvControlling->EngineType == TEngineType::ElectricInductionMotor )
&& ( ( mvControlling->TrainType & dt_EZT ) != 0 ) ) {
// HACK: make the induction motor powered EMUs start braking slightly earlier
fBrakeDist += 10.0;
}
/*
// take into account effect of gravity (but to stay on safe side of calculations, only downhill)
if( fAccGravity > 0.025 ) {
@@ -4743,8 +4763,8 @@ TController::UpdateSituation(double dt) {
fMinProximityDist : // cars can bunch up tighter
fMaxProximityDist ) ); // other vehicle types less so
*/
double k = coupler->Connected->Vel; // prędkość pojazdu z przodu (zakładając,
// że jedzie w tę samą stronę!!!)
// prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!)
double k = coupler->Connected->Vel;
if( k - vel < 5 ) {
// porównanie modułów prędkości [km/h]
// zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej
@@ -4752,6 +4772,26 @@ TController::UpdateSituation(double dt) {
ActualProximityDist,
vehicle->fTrackBlock );
if( ActualProximityDist <= (
( mvOccupied->CategoryFlag & 2 ) ?
100.0 : // cars
250.0 ) ) { // others
// regardless of driving mode at close distance take precaution measures:
// match the other vehicle's speed or slow down if the other vehicle is stopped
VelDesired =
min_speed(
VelDesired,
std::max(
k,
( mvOccupied->CategoryFlag & 2 ) ?
40.0 : // cars
20.0 ) ); // others
if( vel > VelDesired + fVelPlus ) {
// if going too fast force some prompt braking
AccPreferred = std::min( -0.65, AccPreferred );
}
}
double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości
if( distance < 0.0 ) {
// jeśli odległość jest zbyt mała
@@ -4801,7 +4841,7 @@ TController::UpdateSituation(double dt) {
}
}
ReactionTime = (
vel != 0.0 ?
mvOccupied->Vel > 0.01 ?
0.1 : // orientuj się, bo jest goraco
2.0 ); // we're already standing still, so take it easy
}
@@ -5219,10 +5259,10 @@ TController::UpdateSituation(double dt) {
return; // ...and don't touch any other controls
}
if (mvControlling->ConvOvldFlag ||
!mvControlling->Mains) // WS może wywalić z powodu błędu w drutach
{ // wywalił bezpiecznik nadmiarowy przetwornicy
PrepareEngine(); // próba ponownego załączenia
if( ( true == mvControlling->ConvOvldFlag ) // wywalił bezpiecznik nadmiarowy przetwornicy
|| ( false == IsLineBreakerClosed ) ) { // WS może wywalić z powodu błędu w drutach
// próba ponownego załączenia
PrepareEngine();
}
// włączanie bezpiecznika
if ((mvControlling->EngineType == TEngineType::ElectricSeriesMotor) ||
@@ -5784,7 +5824,7 @@ void TController::OrdersInit(double fVel)
// Ale mozna by je zapodac ze scenerii
};
std::string TController::StopReasonText()
std::string TController::StopReasonText() const
{ // informacja tekstowa o przyczynie zatrzymania
if (eStopReason != 7) // zawalidroga będzie inaczej
return StopReasonTable[eStopReason];

376
Driver.h
View File

@@ -129,12 +129,7 @@ class TSpeedPos
double fDist{ 0.0 }; // aktualna odległość (ujemna gdy minięte)
double fVelNext{ -1.0 }; // prędkość obowiązująca od tego miejsca
double fSectionVelocityDist{ 0.0 }; // długość ograniczenia prędkości
// double fAcc;
int iFlags{ spNone }; // flagi typu wpisu do tabelki
// 1=istotny,2=tor,4=odwrotnie,8-zwrotnica (może się zmienić),16-stan
// zwrotnicy,32-minięty,64=koniec,128=łuk
// 0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5
// 0x4000=semafor,0x10000=zatkanie
bool bMoved{ false }; // czy przesunięty (dotyczy punktu zatrzymania w peronie)
Math3D::vector3 vPos; // współrzędne XYZ do liczenia odległości
struct
@@ -174,88 +169,76 @@ static const int BrakeAccTableSize = 20;
//----------------------------------------------------------------------------
class TController {
// TBD: few authorized inspectors, or bunch of public getters?
friend class TTrain;
friend class drivingaid_panel;
friend class timetable_panel;
friend class debug_panel;
friend class whois_event;
private: // obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie)
int iLast{ 0 }; // ostatnia wypełniona pozycja w tabeli <iFirst (modulo iSpeedTableSize)
int iTableDirection{ 0 }; // kierunek zapełnienia tabelki względem pojazdu z AI
std::vector<TSpeedPos> sSpeedTable;
double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze
TTrack *tLast = nullptr; // ostatni analizowany tor
basic_event *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu
std::size_t SemNextIndex{ std::size_t(-1) };
std::size_t SemNextStopIndex{ std::size_t( -1 ) };
double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki
// parametry aktualnego składu
double fLength = 0.0; // długość składu (do wyciągania z ograniczeń)
double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji
public:
double fAccGravity = 0.0; // przyspieszenie składowej stycznej grawitacji
basic_event *eSignNext = nullptr; // sygnał zmieniający prędkość, do pokazania na [F2]
std::string asNextStop; // nazwa następnego punktu zatrzymania wg rozkładu
int iStationStart = 0; // numer pierwszej stacji pokazywanej na podglądzie rozkładu
// parametry sterowania pojazdem (stan, hamowanie)
private:
double fShuntVelocity = 40.0; // maksymalna prędkość manewrowania, zależy m.in. od składu // domyślna prędkość manewrowa
int iVehicles = 0; // ilość pojazdów w składzie
int iEngineActive = 0; // ABu: Czy silnik byl juz zalaczony; Ra: postęp w załączaniu
bool Psyche = false;
int iDrivigFlags = // flagi bitowe ruchu
moveStopPoint | // podjedź do W4 możliwie blisko
moveStopHere | // nie podjeżdżaj do semafora, jeśli droga nie jest wolna
moveStartHorn; // podaj sygnał po podaniu wolnej drogi
double fDriverBraking = 0.0; // po pomnożeniu przez v^2 [km/h] daje ~drogę hamowania [m]
double fDriverDist = 0.0; // dopuszczalna odległość podjechania do przeszkody
double fVelMax = -1.0; // maksymalna prędkość składu (sprawdzany każdy pojazd)
public:
double fBrakeDist = 0.0; // przybliżona droga hamowania
double BrakeAccFactor() const;
double fBrakeReaction = 1.0; //opóźnienie zadziałania hamulca - czas w s / (km/h)
double fNominalAccThreshold = 0.0; // nominalny próg opóźnienia dla zadziałania hamulca
double fAccThreshold = 0.0; // aktualny próg opóźnienia dla zadziałania hamulca
double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziałania hamulca
// dla fBrake_aX:
// indeks [0] - wartości odpowiednie dla aktualnej prędkości
// a potem jest 20 wartości dla różnych prędkości zmieniających się co 5 % Vmax pojazdu obsadzonego
double fBrake_a0[BrakeAccTableSize+1] = { 0.0 }; // opóźnienia hamowania przy ustawieniu zaworu maszynisty w pozycji 1.0
double fBrake_a1[BrakeAccTableSize+1] = { 0.0 }; // przyrost opóźnienia hamowania po przestawieniu zaworu maszynisty o 0,25 pozycji
double BrakingInitialLevel{ 1.0 };
double BrakingLevelIncrease{ 0.25 };
bool IsCargoTrain{ false };
bool IsHeavyCargoTrain{ false };
double fLastStopExpDist = -1.0; // odległość wygasania ostateniego przystanku
double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI
double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
double BrakeChargingCooldown {}; // prevents the ai from trying to charge the train brake too frequently
double fReady = 0.0; // poziom odhamowania wagonów
bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow
private:
double LastUpdatedTime = 0.0; // czas od ostatniego logu
double ElapsedTime = 0.0; // czas od poczatku logu
double deltalog = 0.05; // przyrost czasu
double LastReactionTime = 0.0;
double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi
double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations
TAction eAction { TAction::actUnknown }; // aktualny stan
public:
TController( bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary = true );
~TController();
// ai operations logic
// methods
public:
void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę
void MoveTo(TDynamicObject *to);
void TakeControl(bool yes);
inline
bool Primary() const {
return ( ( iDrivigFlags & movePrimary ) != 0 ); };
inline
TMoverParameters const *Controlling() const {
return mvControlling; }
void DirectionInitial();
inline
int Direction() const {
return iDirection; }
inline
TAction GetAction() {
return eAction; }
private:
void Activation(); // umieszczenie obsady w odpowiednim członie
void ControllingSet(); // znajduje człon do sterowania
void SetDriverPsyche();
bool IncBrake();
bool DecBrake();
bool IncSpeed();
bool DecSpeed(bool force = false);
void SpeedSet();
void SpeedCntrl(double DesiredSpeed);
double ESMVelocity(bool Main);
bool UpdateHeating();
// uaktualnia informacje o prędkości
void SetVelocity(double NewVel, double NewVelNext, TStopReason r = stopNone);
int CheckDirection();
void WaitingSet(double Seconds);
void DirectionForward(bool forward);
int OrderDirectionChange(int newdir, TMoverParameters *Vehicle);
void Lights(int head, int rear);
std::string StopReasonText() const;
double BrakeAccFactor() const;
// modifies brake distance for low target speeds, to ease braking rate in such situations
float
braking_distance_multiplier( float const Targetvelocity ) const;
inline
int DrivigFlags() const {
return iDrivigFlags; };
// members
public:
bool AIControllFlag = false; // rzeczywisty/wirtualny maszynista
/*
int iRouteWanted = 3; // oczekiwany kierunek jazdy (0-stop,1-lewo,2-prawo,3-prosto) np. odpala migacz lub czeka na stan zwrotnicy
*/
private:
int iOverheadZero = 0; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami
int iOverheadDown = 0; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami
private:
bool Psyche = false;
int HelperState = 0; //stan pomocnika maszynisty
TDynamicObject *pVehicle = nullptr; // pojazd w którym siedzi sterujący
TDynamicObject *pVehicles[2]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane)
TMoverParameters *mvControlling = nullptr; // jakim pojazdem steruje (może silnikowym w EZT)
TMoverParameters *mvOccupied = nullptr; // jakim pojazdem hamuje
Mtable::TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty
int iRadioChannel = 1; // numer aktualnego kanału radiowego
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
sound_source tsGuardSignal { sound_placement::internal };
std::string VehicleName;
std::array<int, 2> m_lighthints { -1 }; // suggested light patterns
public:
int HelperState = 0; //stan pomocnika maszynisty
double AccPreferred = 0.0; // preferowane przyspieszenie (wg psychiki kierującego, zmniejszana przy wykryciu kolizji)
double AccDesired = AccPreferred; // przyspieszenie, jakie ma utrzymywać (<0:nie przyspieszaj,<-0.1:hamuj)
double VelDesired = 0.0; // predkość, z jaką ma jechać, wynikająca z analizy tableki; <=VelSignal
@@ -269,18 +252,8 @@ private:
double VelRoad = -1.0; // aktualna prędkość drogowa (ze znaku W27) (PutValues albo komendą) // prędkość drogowa bez ograniczenia
double VelNext = 120.0; // prędkość, jaka ma być po przejechaniu długości ProximityDist
double VelRestricted = -1.0; // speed of travel after passing a permissive signal at stop
private:
double FirstSemaphorDist = 10000.0; // odległość do pierwszego znalezionego semafora
public:
double ActualProximityDist = 1.0; // odległość brana pod uwagę przy wyliczaniu prędkości i przyspieszenia
private:
Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego
// odnosi sie komenda
TOrders OrderList[maxorders]; // lista rozkazów
int OrderPos = 0,
OrderTop = 0; // rozkaz aktualny oraz wolne miejsce do wstawiania nowych
std::ofstream LogFile; // zapis parametrow fizycznych
std::ofstream AILogFile; // log AI
int iDirection = 0; // kierunek jazdy względem sprzęgów pojazdu, w którym siedzi AI (1=przód,-1=tył)
int iDirectionOrder = 0; //żadany kierunek jazdy (służy do zmiany kierunku)
int iVehicleCount = -2; // wartość neutralna // ilość pojazdów do odłączenia albo zabrania ze składu (-1=wszystkie)
@@ -288,146 +261,187 @@ private:
int iDriverFailCount = 0; // licznik błędów AI
bool Need_TryAgain = false; // true, jeśli druga pozycja w elektryku nie załapała
bool Need_BrakeRelease = true;
public:
bool IsAtPassengerStop{ false }; // true if the consist is within acceptable range of w4 post
double fMinProximityDist = 30.0; // stawanie między 30 a 60 m przed przeszkodą // minimalna oległość do przeszkody, jaką należy zachować
double fOverhead1 = 3000.0; // informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!)
double fOverhead2 = -1.0; // informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości)
int iOverheadZero = 0; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami
int iOverheadDown = 0; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami
double fVoltage = 0.0; // uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas
private:
double fMaxProximityDist = 50.0; // stawanie między 30 a 60 m przed przeszkodą // akceptowalna odległość stanięcia przed przeszkodą
TStopReason eStopReason = stopSleep; // powód zatrzymania przy ustawieniu zerowej prędkości // na początku śpi
std::string VehicleName;
double fVelPlus = 0.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
double fVelMinus = 0.0; // margines obniżenia prędkości, powodujący załączenie napędu
double fWarningDuration = 0.0; // ile czasu jeszcze trąbić
double WaitingTime = 0.0; // zliczany czas oczekiwania do samoistnego ruszenia
double WaitingExpireTime = 31.0; // tyle ma czekać, zanim się ruszy // maksymlany czas oczekiwania do samoistnego ruszenia
double IdleTime {}; // keeps track of time spent at a stop
public:
double fStopTime = 0.0; // czas postoju przed dalszą jazdą (np. na przystanku)
double fShuntVelocity = 40.0; // maksymalna prędkość manewrowania, zależy m.in. od składu // domyślna prędkość manewrowa
int iDrivigFlags = // flagi bitowe ruchu
moveStopPoint | // podjedź do W4 możliwie blisko
moveStopHere | // nie podjeżdżaj do semafora, jeśli droga nie jest wolna
moveStartHorn; // podaj sygnał po podaniu wolnej drogi
double fDriverBraking = 0.0; // po pomnożeniu przez v^2 [km/h] daje ~drogę hamowania [m]
double fDriverDist = 0.0; // dopuszczalna odległość podjechania do przeszkody
double fVelMax = -1.0; // maksymalna prędkość składu (sprawdzany każdy pojazd)
double fBrakeDist = 0.0; // przybliżona droga hamowania
double fBrakeReaction = 1.0; //opóźnienie zadziałania hamulca - czas w s / (km/h)
double fNominalAccThreshold = 0.0; // nominalny próg opóźnienia dla zadziałania hamulca
double fAccThreshold = 0.0; // aktualny próg opóźnienia dla zadziałania hamulca
double AbsAccS_pub = 0.0; // próg opóźnienia dla zadziałania hamulca
// dla fBrake_aX:
// indeks [0] - wartości odpowiednie dla aktualnej prędkości
// a potem jest 20 wartości dla różnych prędkości zmieniających się co 5 % Vmax pojazdu obsadzonego
double fBrake_a0[BrakeAccTableSize+1] = { 0.0 }; // opóźnienia hamowania przy ustawieniu zaworu maszynisty w pozycji 1.0
double fBrake_a1[BrakeAccTableSize+1] = { 0.0 }; // przyrost opóźnienia hamowania po przestawieniu zaworu maszynisty o 0,25 pozycji
double BrakingInitialLevel{ 1.0 };
double BrakingLevelIncrease{ 0.25 };
double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI
double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
double BrakeChargingCooldown {}; // prevents the ai from trying to charge the train brake too frequently
double LastReactionTime = 0.0;
double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi
double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations
TAction eAction { TAction::actUnknown }; // aktualny stan
private: //---//---//---//---// koniec zmiennych, poniżej metody //---//---//---//---//
void SetDriverPsyche();
bool PrepareEngine();
bool ReleaseEngine();
bool IncBrake();
bool DecBrake();
bool IncSpeed();
bool DecSpeed(bool force = false);
void SpeedSet();
void SpeedCntrl(double DesiredSpeed);
void Doors(bool const Open, int const Side = 0);
// returns true if any vehicle in the consist has an open door
bool doors_open() const;
void RecognizeCommand(); // odczytuje komende przekazana lokomotywie
void Activation(); // umieszczenie obsady w odpowiednim członie
void ControllingSet(); // znajduje człon do sterowania
void AutoRewident(); // ustawia hamulce w składzie
double ESMVelocity(bool Main);
public:
// orders
// methods
public:
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm);
bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm );
void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę
bool UpdateHeating();
// procedury dotyczace rozkazow dla maszynisty
// uaktualnia informacje o prędkości
void SetVelocity(double NewVel, double NewVelNext, TStopReason r = stopNone);
public:
private:
void RecognizeCommand(); // odczytuje komende przekazana lokomotywie
void JumpToNextOrder();
void JumpToFirstOrder();
void OrderPush(TOrders NewOrder);
void OrderNext(TOrders NewOrder);
inline TOrders OrderCurrentGet();
inline TOrders OrderNextGet();
bool CheckVehicles(TOrders user = Wait_for_orders);
int CheckDirection();
private:
void CloseLog();
void OrderCheck();
public:
void OrdersInit(double fVel);
void OrdersClear();
void OrdersDump();
TController( bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary = true );
std::string OrderCurrent() const;
void WaitingSet(double Seconds);
private:
std::string Order2Str(TOrders Order) const;
void DirectionForward(bool forward);
int OrderDirectionChange(int newdir, TMoverParameters *Vehicle);
void Lights(int head, int rear);
// members
Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego odnosi sie komenda // NOTE: not used
TOrders OrderList[ maxorders ]; // lista rozkazów
int OrderPos = 0,
OrderTop = 0; // rozkaz aktualny oraz wolne miejsce do wstawiania nowych
// scantable
// methods
public:
int CrossRoute(TTrack *tr);
inline void MoveDistanceAdd( double distance ) {
dMoveLen += distance * iDirection; } //jak jedzie do tyłu to trzeba uwzględniać, że distance jest ujemna
private:
// Ra: metody obsługujące skanowanie toru
std::vector<basic_event *> CheckTrackEvent(TTrack *Track, double const fDirection ) const;
std::vector<basic_event *> CheckTrackEvent( TTrack *Track, double const fDirection ) const;
bool TableAddNew();
bool TableNotFound(basic_event const *Event) const;
void TableTraceRoute(double fDistance, TDynamicObject *pVehicle);
void TableCheck(double fDistance);
TCommandType TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc);
// modifies brake distance for low target speeds, to ease braking rate in such situations
float
braking_distance_multiplier( float const Targetvelocity ) const;
bool TableNotFound( basic_event const *Event ) const;
void TableTraceRoute( double fDistance, TDynamicObject *pVehicle );
void TableCheck( double fDistance );
TCommandType TableUpdate( double &fVelDes, double &fDist, double &fNext, double &fAcc );
// returns most recently calculated distance to potential obstacle ahead
double TrackBlock() const;
void TablePurger();
void TableSort();
inline double MoveDistanceGet() const {
return dMoveLen; }
return dMoveLen;
}
inline void MoveDistanceReset() {
dMoveLen = 0.0; }
public:
inline void MoveDistanceAdd(double distance) {
dMoveLen += distance * iDirection; //jak jedzie do tyłu to trzeba uwzględniać, że distance jest ujemna
dMoveLen = 0.0;
}
std::size_t TableSize() const { return sSpeedTable.size(); }
void TableClear();
int TableDirection() { return iTableDirection; }
private: // Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu
bool BackwardTrackBusy(TTrack *Track);
basic_event *CheckTrackEventBackward(double fDirection, TTrack *Track);
TTrack *BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, basic_event *&Event);
// Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu
bool BackwardTrackBusy( TTrack *Track );
basic_event *CheckTrackEventBackward( double fDirection, TTrack *Track );
TTrack *BackwardTraceRoute( double &fDistance, double &fDirection, TTrack *Track, basic_event *&Event );
void SetProximityVelocity( double dist, double vel, glm::dvec3 const *pos );
TCommandType BackwardScan();
public:
void PhysicsLog();
std::string StopReasonText();
~TController();
void TakeControl(bool yes);
Mtable::TTrainParameters const * TrainTimetable() const;
std::string TrainName() const;
std::string Relation() const;
int StationCount() const;
int StationIndex() const;
bool IsStop() const;
std::string NextStop() const;
inline
bool Primary() const {
return ( ( iDrivigFlags & movePrimary ) != 0 ); };
inline
int DrivigFlags() const {
return iDrivigFlags; };
// returns most recently calculated distance to potential obstacle ahead
double
TrackBlock() const;
void MoveTo(TDynamicObject *to);
void DirectionInitial();
std::string TableText(std::size_t const Index) const;
int CrossRoute(TTrack *tr);
/*
void RouteSwitch(int d);
*/
std::string OwnerName() const;
TMoverParameters const *Controlling() const {
return mvControlling; }
int Direction() const {
return iDirection; }
// members
int iLast{ 0 }; // ostatnia wypełniona pozycja w tabeli <iFirst (modulo iSpeedTableSize)
int iTableDirection{ 0 }; // kierunek zapełnienia tabelki względem pojazdu z AI
std::vector<TSpeedPos> sSpeedTable;
double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze
TTrack *tLast = nullptr; // ostatni analizowany tor
basic_event *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu
std::size_t SemNextIndex{ std::size_t(-1) };
std::size_t SemNextStopIndex{ std::size_t( -1 ) };
double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki
basic_event *eSignNext = nullptr; // sygnał zmieniający prędkość, do pokazania na [F2]
// timetable
// methods
public:
std::string TrainName() const;
private:
std::string Relation() const;
Mtable::TTrainParameters const * TrainTimetable() const;
int StationIndex() const;
int StationCount() const;
bool IsStop() const;
std::string NextStop() const;
// members
Mtable::TTrainParameters *TrainParams = nullptr; // rozkład jazdy zawsze jest, nawet jeśli pusty
std::string asNextStop; // nazwa następnego punktu zatrzymania wg rozkładu
int iStationStart = 0; // numer pierwszej stacji pokazywanej na podglądzie rozkładu
double fLastStopExpDist = -1.0; // odległość wygasania ostateniego przystanku
int iRadioChannel = 1; // numer aktualnego kanału radiowego
int iGuardRadio = 0; // numer kanału radiowego kierownika (0, gdy nie używa radia)
sound_source tsGuardSignal { sound_placement::internal };
// consist
// methods
public:
private:
bool CheckVehicles(TOrders user = Wait_for_orders);
bool PrepareEngine();
bool ReleaseEngine();
void Doors(bool const Open, int const Side = 0);
// returns true if any vehicle in the consist has an open door
bool doors_open() const;
void AutoRewident(); // ustawia hamulce w składzie
// members
double fLength = 0.0; // długość składu (do wyciągania z ograniczeń)
double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji
double fAccGravity = 0.0; // przyspieszenie składowej stycznej grawitacji
int iVehicles = 0; // ilość pojazdów w składzie
int iEngineActive = 0; // ABu: Czy silnik byl juz zalaczony; Ra: postęp w załączaniu
bool IsCargoTrain{ false };
bool IsHeavyCargoTrain{ false };
bool IsLineBreakerClosed{ false }; // state of line breaker in all powered vehicles under control
double fReady = 0.0; // poziom odhamowania wagonów
bool Ready = false; // ABu: stan gotowosci do odjazdu - sprawdzenie odhamowania wagonow
TDynamicObject *pVehicles[ 2 ]; // skrajne pojazdy w składzie (niekoniecznie bezpośrednio sterowane)
// logs
// methods
void PhysicsLog();
void CloseLog();
// members
std::ofstream LogFile; // zapis parametrow fizycznych
double LastUpdatedTime = 0.0; // czas od ostatniego logu
double ElapsedTime = 0.0; // czas od poczatku logu
// getters
public:
TDynamicObject const *Vehicle() const {
return pVehicle; }
TDynamicObject *Vehicle( side const Side ) const {
return pVehicles[ Side ]; }
private:
std::string OwnerName() const;
// leftovers
/*
int iRouteWanted = 3; // oczekiwany kierunek jazdy (0-stop,1-lewo,2-prawo,3-prosto) np. odpala migacz lub czeka na stan zwrotnicy
*/
};

View File

@@ -622,8 +622,12 @@ void
TDynamicObject::toggle_lights() {
if( true == SectionLightsActive ) {
// switch all lights off
// switch all lights off...
for( auto &section : Sections ) {
// ... but skip cab sections, their lighting ignores battery state
auto const sectionname { section.compartment->pName };
if( sectionname.find( "cab" ) == 0 ) { continue; }
section.light_level = 0.0f;
}
SectionLightsActive = false;

View File

@@ -1370,6 +1370,7 @@ public:
bool MotorBlowersSwitch( bool State, side const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle
bool MotorBlowersSwitchOff( bool State, side const Side, range_t const Notify = range_t::consist ); // traction motor fan state toggle
bool MainSwitch( bool const State, range_t const Notify = range_t::consist );/*! wylacznik glowny*/
void MainSwitch_( bool const State );
bool ConverterSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl przetwornicy*/
bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/

View File

@@ -490,7 +490,7 @@ int TMoverParameters::DettachStatus(int ConnectNo)
// if (CouplerType==Articulated) return false; //sprzęg nie do rozpięcia - może być tylko urwany
// Couplers[ConnectNo].CoupleDist=Distance(Loc,Couplers[ConnectNo].Connected->Loc,Dim,Couplers[ConnectNo].Connected->Dim);
CouplerDist(ConnectNo);
if (Couplers[ConnectNo].CouplerType == TCouplerType::Screw ? Couplers[ConnectNo].CoupleDist < 0.0 : true)
if (Couplers[ConnectNo].CouplerType == TCouplerType::Screw ? Couplers[ConnectNo].CoupleDist < 0.01 : true)
return -Couplers[ConnectNo].CouplingFlag; // można rozłączać, jeśli dociśnięty
return (Couplers[ConnectNo].CoupleDist > 0.2) ? -Couplers[ConnectNo].CouplingFlag :
Couplers[ConnectNo].CouplingFlag;
@@ -563,7 +563,7 @@ bool TMoverParameters::DirectionForward()
SendCtrlToNext("Direction", ActiveDir, CabNo);
return true;
}
else if ((ActiveDir == 1) && (MainCtrlPos == 0) && (TrainType == dt_EZT))
else if ((ActiveDir == 1) && (MainCtrlPos == 0) && (TrainType == dt_EZT) && (EngineType != TEngineType::ElectricInductionMotor))
return MinCurrentSwitch(true); //"wysoki rozruch" EN57
return false;
};
@@ -635,8 +635,9 @@ bool TMoverParameters::ChangeCab(int direction)
{
// if (ActiveCab+direction=0) then LastCab:=ActiveCab;
ActiveCab = ActiveCab + direction;
if ((BrakeSystem == TBrakeSystem::Pneumatic) && (BrakeCtrlPosNo > 0))
{
if( ( BrakeCtrlPosNo > 0 )
&& ( ( BrakeSystem == TBrakeSystem::Pneumatic )
|| ( BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) ) {
// if (BrakeHandle==FV4a) //!!!POBIERAĆ WARTOŚĆ Z KLASY ZAWORU!!!
// BrakeLevelSet(-2); //BrakeCtrlPos=-2;
// else if ((BrakeHandle==FVel6)||(BrakeHandle==St113))
@@ -2399,7 +2400,7 @@ bool TMoverParameters::EpFuseSwitch(bool State)
bool TMoverParameters::DirectionBackward(void)
{
bool DB = false;
if ((ActiveDir == 1) && (MainCtrlPos == 0) && (TrainType == dt_EZT))
if ((ActiveDir == 1) && (MainCtrlPos == 0) && (TrainType == dt_EZT) && (EngineType != TEngineType::ElectricInductionMotor))
if (MinCurrentSwitch(false))
{
DB = true; //
@@ -2739,66 +2740,76 @@ bool TMoverParameters::MotorBlowersSwitchOff( bool State, side const Side, range
// Q: 20160713
// włączenie / wyłączenie obwodu głownego
// *************************************************************************************************
bool TMoverParameters::MainSwitch( bool const State, range_t const Notify )
{
bool TMoverParameters::MainSwitch( bool const State, range_t const Notify ) {
bool const initialstate { Mains || dizel_startup };
if( ( Mains != State )
&& ( MainCtrlPosNo > 0 ) ) {
MainSwitch_( State );
if( ( false == State )
|| ( ( ( ScndCtrlPos == 0 ) || ( EngineType == TEngineType::ElectricInductionMotor ) )
&& ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) )
&& ( true == NoVoltRelay )
&& ( true == OvervoltageRelay )
&& ( LastSwitchingTime > CtrlDelay )
&& ( false == TestFlag( DamageFlag, dtrain_out ) )
&& ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) {
if( true == State ) {
// switch on
if( ( EngineType == TEngineType::DieselEngine )
|| ( EngineType == TEngineType::DieselElectric ) ) {
// launch diesel engine startup procedure
dizel_startup = true;
}
else {
Mains = true;
}
}
else {
Mains = false;
// potentially knock out the pumps if their switch doesn't force them on
WaterPump.is_active &= WaterPump.is_enabled;
FuelPump.is_active &= FuelPump.is_enabled;
}
if( ( TrainType == dt_EZT )
&& ( false == State ) ) {
ConvOvldFlag = true;
}
if( Mains != initialstate ) {
LastSwitchingTime = 0;
}
if( Notify != range_t::local ) {
// pass the command to other vehicles
SendCtrlToNext(
"MainSwitch",
( State ? 1 : 0 ),
CabNo,
( Notify == range_t::unit ?
coupling::control | coupling::permanent :
coupling::control ) );
}
}
if( Notify != range_t::local ) {
// pass the command to other vehicles
// TBD: pass the requested state, or the actual state?
SendCtrlToNext(
"MainSwitch",
( State ? 1 : 0 ),
CabNo,
( Notify == range_t::unit ?
coupling::control | coupling::permanent :
coupling::control ) );
}
return ( ( Mains || dizel_startup ) != initialstate );
}
void TMoverParameters::MainSwitch_( bool const State ) {
if( ( Mains == State )
|| ( MainCtrlPosNo == 0 ) ) {
// nothing to do
return;
}
bool const initialstate { Mains || dizel_startup };
if( ( false == State )
|| ( ( ( ScndCtrlPos == 0 ) || ( EngineType == TEngineType::ElectricInductionMotor ) )
&& ( ( ConvOvldFlag == false ) || ( TrainType == dt_EZT ) )
&& ( true == NoVoltRelay )
&& ( true == OvervoltageRelay )
&& ( LastSwitchingTime > CtrlDelay )
&& ( false == TestFlag( DamageFlag, dtrain_out ) )
&& ( false == TestFlag( EngDmgFlag, 1 ) ) ) ) {
if( true == State ) {
// switch on
if( ( EngineType == TEngineType::DieselEngine )
|| ( EngineType == TEngineType::DieselElectric ) ) {
// launch diesel engine startup procedure
dizel_startup = true;
}
else {
Mains = true;
}
}
else {
Mains = false;
// potentially knock out the pumps if their switch doesn't force them on
WaterPump.is_active &= WaterPump.is_enabled;
FuelPump.is_active &= FuelPump.is_enabled;
}
if( ( TrainType == dt_EZT )
&& ( false == State ) ) {
ConvOvldFlag = true;
}
if( Mains != initialstate ) {
LastSwitchingTime = 0;
}
}
}
// *************************************************************************************************
// Q: 20160713
// włączenie / wyłączenie przetwornicy
@@ -3555,9 +3566,8 @@ void TMoverParameters::UpdatePipePressure(double dt)
dpMainValve = 0;
if ((BrakeCtrlPosNo > 1) /*&& (ActiveCab != 0)*/)
// with BrakePressureTable[BrakeCtrlPos] do
{
if( BrakeCtrlPosNo > 1 ) {
if ((EngineType != TEngineType::ElectricInductionMotor))
dpLocalValve = LocHandle->GetPF(std::max(LocalBrakePosA, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0);
else
@@ -3573,13 +3583,21 @@ void TMoverParameters::UpdatePipePressure(double dt)
temp = ScndPipePress;
}
Handle->SetReductor(BrakeCtrlPos2);
if( ( ( BrakeOpModes & bom_PS ) == 0 )
|| ( ( ActiveCab != 0 )
&& ( BrakeOpModeFlag != bom_PS ) ) ) {
if ((BrakeOpModeFlag != bom_PS))
if ((BrakeOpModeFlag < bom_EP) || ((Handle->GetPos(bh_EB) - 0.5) < BrakeCtrlPosR) ||
(BrakeHandle != TBrakeHandle::MHZ_EN57))
dpMainValve = Handle->GetPF(BrakeCtrlPosR, PipePress, temp, dt, EqvtPipePress);
else
dpMainValve = Handle->GetPF(0, PipePress, temp, dt, EqvtPipePress);
if( ( BrakeOpModeFlag < bom_EP )
|| ( ( Handle->GetPos( bh_EB ) - 0.5 ) < BrakeCtrlPosR )
|| ( ( BrakeHandle != TBrakeHandle::MHZ_EN57 )
&& ( BrakeHandle != TBrakeHandle::MHZ_K8P ) ) ) {
dpMainValve = Handle->GetPF( BrakeCtrlPosR, PipePress, temp, dt, EqvtPipePress );
}
else {
dpMainValve = Handle->GetPF( 0, PipePress, temp, dt, EqvtPipePress );
}
}
if (dpMainValve < 0) // && (PipePressureVal > 0.01) //50
if (Compressor > ScndPipePress)
@@ -4627,14 +4645,6 @@ double TMoverParameters::TractionForce( double dt ) {
switch( EngineType ) {
case TEngineType::ElectricSeriesMotor: {
/*
if ((Mains)) // nie wchodzić w funkcję bez potrzeby
if ( (std::max(GetTrainsetVoltage(), std::abs(Voltage)) < EnginePowerSource.CollectorParameters.MinV) ||
(std::max(GetTrainsetVoltage(), std::abs(Voltage)) * EnginePowerSource.CollectorParameters.OVP >
EnginePowerSource.CollectorParameters.MaxV))
if( MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ) ) // TODO: check whether we need to send this EMU-wide
EventFlag = true; // wywalanie szybkiego z powodu niewłaściwego napięcia
*/
// update the state of voltage relays
auto const voltage { std::max( GetTrainsetVoltage(), std::abs( RunningTraction.TractionVoltage ) ) };
NoVoltRelay = ( voltage >= EnginePowerSource.CollectorParameters.MinV );
@@ -4646,6 +4656,18 @@ double TMoverParameters::TractionForce( double dt ) {
break;
}
case TEngineType::ElectricInductionMotor: {
// TODO: check if we can use instead the code for electricseriesmotor
if( ( Mains ) ) {
// nie wchodzić w funkcję bez potrzeby
if( ( std::max( GetTrainsetVoltage(), std::abs( RunningTraction.TractionVoltage ) ) < EnginePowerSource.CollectorParameters.MinV )
|| ( std::max( GetTrainsetVoltage(), std::abs( RunningTraction.TractionVoltage ) ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) {
MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ); // TODO: check whether we need to send this EMU-wide
}
}
break;
}
case TEngineType::DieselElectric: {
// TODO: move this to the auto relay check when the electric engine code paths are unified
StLinFlag = MotorConnectorsCheck();
@@ -5062,13 +5084,6 @@ double TMoverParameters::TractionForce( double dt ) {
case TEngineType::ElectricInductionMotor:
{
if( ( Mains ) ) {
// nie wchodzić w funkcję bez potrzeby
if( ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) < EnginePowerSource.CollectorParameters.MinV )
|| ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) {
MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ); // TODO: check whether we need to send this EMU-wide
}
}
if( true == Mains ) {
//tempomat
if (ScndCtrlPosNo > 1)
@@ -5531,8 +5546,9 @@ bool TMoverParameters::MaxCurrentSwitch(bool State)
bool TMoverParameters::MinCurrentSwitch(bool State)
{
bool MCS = false;
if (((EngineType == TEngineType::ElectricSeriesMotor) && (IminHi > IminLo)) || (TrainType == dt_EZT))
{
if( ( ( EngineType == TEngineType::ElectricSeriesMotor ) && ( IminHi > IminLo ) )
|| ( ( TrainType == dt_EZT ) && ( EngineType != TEngineType::ElectricInductionMotor ) ) ) {
if (State && (Imin == IminLo))
{
Imin = IminHi;
@@ -9461,22 +9477,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
}
else if (Command == "MainSwitch")
{
if (CValue1 == 1) {
if( ( EngineType == TEngineType::DieselEngine )
|| ( EngineType == TEngineType::DieselElectric ) ) {
dizel_startup = true;
}
else {
Mains = true;
}
}
else {
Mains = false;
// potentially knock out the pumps if their switch doesn't force them on
WaterPump.is_active &= WaterPump.is_enabled;
FuelPump.is_active &= FuelPump.is_enabled;
}
MainSwitch_( CValue1 > 0.0 );
OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype );
}
else if (Command == "Direction")

View File

@@ -174,10 +174,26 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
/*
iVboPtr = Pos; // pozycja w VBO
*/
if (!parser.expectToken("type:"))
ErrorLog("Bad model: expected submodel type definition not found while loading model \"" + Model->NameGet() + "\"" );
auto token { parser.getToken<std::string>() };
if( token != "type:" ) {
std::string errormessage {
"Bad model: expected submodel type definition not found while loading model \"" + Model->NameGet() + "\""
+ "\ncurrent model data stream content: \"" };
auto count { 10 };
while( ( true == parser.getTokens() )
&& ( false == ( token = parser.peek() ).empty() )
&& ( token != "parent:" ) ) {
// skip data until next submodel, dump first few tokens in the error message
if( --count > 0 ) {
errormessage += token + " ";
}
}
errormessage += "(...)\"";
ErrorLog( errormessage );
return 0;
}
{
std::string type = parser.getToken<std::string>();
auto const type { parser.getToken<std::string>() };
if (type == "mesh")
eType = GL_TRIANGLES; // submodel - trójkaty
else if (type == "point")
@@ -190,7 +206,6 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
eType = TP_STARS; // wiele punktów świetlnych
};
parser.ignoreToken();
std::string token;
parser.getTokens(1, false); // nazwa submodelu bez zmieny na małe
parser >> token;
Name(token);

View File

@@ -99,13 +99,11 @@ auto python_taskqueue::init() -> bool {
stringioclassname != nullptr ?
PyObject_CallObject( stringioclassname, nullptr ) :
nullptr );
m_error = { (
m_stderr = { (
stringioobject == nullptr ? nullptr :
PySys_SetObject( "stderr", stringioobject ) != 0 ? nullptr :
stringioobject ) };
if( m_error == nullptr ) { goto release_and_exit; }
if( false == run_file( "abstractscreenrenderer" ) ) { goto release_and_exit; }
// release the lock, save the state for future use
@@ -325,13 +323,13 @@ python_taskqueue::error() {
if( PyErr_Occurred() == nullptr ) { return; }
if( m_error != nullptr ) {
if( m_stderr != nullptr ) {
// std err pythona jest buforowane
PyErr_Print();
auto *errortext { PyObject_CallMethod( m_error, "getvalue", nullptr ) };
auto *errortext { PyObject_CallMethod( m_stderr, "getvalue", nullptr ) };
ErrorLog( PyString_AsString( errortext ) );
// czyscimy bufor na kolejne bledy
PyObject_CallMethod( m_error, "truncate", "i", 0 );
PyObject_CallMethod( m_stderr, "truncate", "i", 0 );
}
else {
// nie dziala buffor pythona
@@ -353,7 +351,7 @@ python_taskqueue::error() {
}
auto *tracebacktext { PyObject_Str( traceback ) };
if( tracebacktext != nullptr ) {
WriteLog( PyString_AsString( tracebacktext ) );
ErrorLog( PyString_AsString( tracebacktext ) );
}
else {
WriteLog( "Python Interpreter: failed to retrieve the stack traceback" );

View File

@@ -93,7 +93,7 @@ private:
void error();
// members
PyObject *m_main { nullptr };
PyObject *m_error { nullptr };
PyObject *m_stderr { nullptr };
PyThreadState *m_mainthread{ nullptr };
worker_array m_workers;
threading::condition_variable m_condition; // wakes up the workers

View File

@@ -547,13 +547,18 @@ PyObject *TTrain::GetTrainState() {
PyDict_SetItemString( dict, "velnext", PyGetFloat( driver->VelNext ) );
PyDict_SetItemString( dict, "actualproximitydist", PyGetFloat( driver->ActualProximityDist ) );
// train data
auto const *timetable{ driver->TrainTimetable() };
PyDict_SetItemString( dict, "trainnumber", PyGetString( driver->TrainName().c_str() ) );
PyDict_SetItemString( dict, "train_brakingmassratio", PyGetFloat( timetable->BrakeRatio ) );
PyDict_SetItemString( dict, "train_enginetype", PyGetString( timetable->LocSeries.c_str() ) );
PyDict_SetItemString( dict, "train_engineload", PyGetFloat( timetable->LocLoad ) );
PyDict_SetItemString( dict, "train_stationindex", PyGetInt( driver->StationIndex() ) );
auto const stationcount { driver->StationCount() };
PyDict_SetItemString( dict, "train_stationcount", PyGetInt( stationcount ) );
if( stationcount > 0 ) {
// timetable stations data, if there's any
auto const *timetable { driver->TrainTimetable() };
for( auto stationidx = 1; stationidx <= stationcount; ++stationidx ) {
auto const stationlabel { "train_station" + std::to_string( stationidx ) + "_" };
auto const &timetableline { timetable->TimeTable[ stationidx ] };
@@ -567,7 +572,9 @@ PyObject *TTrain::GetTrainState() {
PyDict_SetItemString( dict, ( stationlabel + "dm" ).c_str(), PyGetInt( timetableline.Dm ) );
}
}
PyDict_SetItemString( dict, "train_atpassengerstop", PyGetBool( driver->IsAtPassengerStop ) );
// world state data
PyDict_SetItemString( dict, "scenario", PyGetString( Global.SceneryFile.c_str() ) );
PyDict_SetItemString( dict, "hours", PyGetInt( simulation::Time.data().wHour ) );
PyDict_SetItemString( dict, "minutes", PyGetInt( simulation::Time.data().wMinute ) );
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
@@ -811,7 +818,7 @@ void TTrain::OnCommand_secondcontrollerincrease( TTrain *Train, command_data con
if( Command.action != GLFW_RELEASE ) {
// on press or hold
if( ( Train->mvControlled->EngineType == TEngineType::DieselElectric )
&& ( true == Train->mvControlled->ShuntMode ) ) {
&& ( true == Train->mvControlled->ShuntMode ) ) {
Train->mvControlled->AnPos = clamp(
Train->mvControlled->AnPos + 0.025,
0.0, 1.0 );
@@ -905,6 +912,9 @@ void TTrain::OnCommand_secondcontrollerdecreasefast( TTrain *Train, command_data
}
void TTrain::OnCommand_secondcontrollerset( TTrain *Train, command_data const &Command ) {
if (Command.action == GLFW_RELEASE)
return;
auto const targetposition { std::min<int>( Command.param1, Train->mvControlled->ScndCtrlPosNo ) };
while( ( targetposition < Train->mvControlled->GetVirtualScndPos() )
&& ( true == Train->mvControlled->DecScndCtrl( 1 ) ) ) {
@@ -966,10 +976,13 @@ void TTrain::OnCommand_independentbrakedecreasefast( TTrain *Train, command_data
void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &Command ) {
Train->mvControlled->LocalBrakePosA = (
clamp(
Command.param1,
0.0, 1.0 ) );
if( Command.action != GLFW_RELEASE ) {
Train->mvControlled->LocalBrakePosA = (
clamp(
Command.param1,
0.0, 1.0 ) );
}
/*
Train->mvControlled->LocalBrakePos = (
std::round(
@@ -1351,13 +1364,11 @@ void TTrain::OnCommand_trainbrakeoperationmodeincrease(TTrain *Train, command_da
if( ( ( Train->mvOccupied->BrakeOpModeFlag << 1 ) & Train->mvOccupied->BrakeOpModes ) != 0 ) {
// next mode
Train->mvOccupied->BrakeOpModeFlag <<= 1;
// audio feedback
Train->dsbPneumaticSwitch.play();
// visual feedback
Train->ggBrakeOperationModeCtrl.UpdateValue(
Train->mvOccupied->BrakeOpModeFlag > 0 ?
std::log2( Train->mvOccupied->BrakeOpModeFlag ) :
0 );
0 ); // audio fallback
}
}
}
@@ -1369,8 +1380,6 @@ void TTrain::OnCommand_trainbrakeoperationmodedecrease(TTrain *Train, command_da
if( ( ( Train->mvOccupied->BrakeOpModeFlag >> 1 ) & Train->mvOccupied->BrakeOpModes ) != 0 ) {
// previous mode
Train->mvOccupied->BrakeOpModeFlag >>= 1;
// audio feedback
Train->dsbPneumaticSwitch.play();
// visual feedback
Train->ggBrakeOperationModeCtrl.UpdateValue(
Train->mvOccupied->BrakeOpModeFlag > 0 ?
@@ -5423,8 +5432,8 @@ bool TTrain::Update( double const Deltatime )
btLampkaRadioStop.Turn( mvOccupied->Radio && mvOccupied->RadioStopFlag );
btLampkaHamulecReczny.Turn(mvOccupied->ManualBrakePos > 0);
// NBMX wrzesien 2003 - drzwi oraz sygnał odjazdu
btLampkaDoorLeft.Turn(mvOccupied->DoorLeftOpened);
btLampkaDoorRight.Turn(mvOccupied->DoorRightOpened);
btLampkaDoorLeft.Turn( DynamicObject->dDoorMoveL > 0.0 );// mvOccupied->DoorLeftOpened);
btLampkaDoorRight.Turn( DynamicObject->dDoorMoveR > 0.0 ); //mvOccupied ->DoorRightOpened);
btLampkaBlokadaDrzwi.Turn(mvOccupied->DoorBlockedFlag());
btLampkaDoorLockOff.Turn( false == mvOccupied->DoorLockEnabled );
btLampkaDepartureSignal.Turn( mvControlled->DepartureSignal );
@@ -5733,7 +5742,12 @@ bool TTrain::Update( double const Deltatime )
InstrumentLightType == 0 ? mvControlled->Battery || mvControlled->ConverterFlag :
InstrumentLightType == 1 ? mvControlled->Mains :
InstrumentLightType == 2 ? mvControlled->ConverterFlag :
InstrumentLightType == 3 ? mvControlled->Battery || mvControlled->ConverterFlag :
false ) };
if( InstrumentLightType == 3 ) {
// TODO: link the light state with the state of the master key
InstrumentLightActive = true;
}
btInstrumentLight.Turn( InstrumentLightActive && lightpower );
btDashboardLight.Turn( DashboardLightActive && lightpower );
btTimetableLight.Turn( TimetableLightActive && lightpower );
@@ -5791,7 +5805,9 @@ bool TTrain::Update( double const Deltatime )
ggHornLowButton.Update();
ggHornHighButton.Update();
ggWhistleButton.Update();
ggHelperButton.UpdateValue(DynamicObject->Mechanik->HelperState);
if( DynamicObject->Mechanik != nullptr ) {
ggHelperButton.UpdateValue( DynamicObject->Mechanik->HelperState );
}
ggHelperButton.Update();
for( auto &universal : ggUniversals ) {
universal.Update();
@@ -5859,7 +5875,8 @@ bool TTrain::Update( double const Deltatime )
// NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc
// TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement
if( DynamicObject->Mechanik != nullptr && !DynamicObject->Mechanik->AIControllFlag ) {
if( ( DynamicObject->Mechanik == nullptr )
|| ( false == DynamicObject->Mechanik->AIControllFlag ) ) {
// don't mess with the ai driving, at least not while switches don't follow ai-set vehicle state
if( ( mvControlled->Battery )
|| ( mvControlled->ConverterFlag ) ) {
@@ -7284,8 +7301,8 @@ void TTrain::set_cab_controls( int const Cab ) {
0.f ) );
// doors
// NOTE: we're relying on the cab models to have switches reversed for the rear cab(?)
ggDoorLeftButton.PutValue( mvOccupied->DoorLeftOpened ? 1.f : 0.f );
ggDoorRightButton.PutValue( mvOccupied->DoorRightOpened ? 1.f : 0.f );
ggDoorLeftButton.PutValue( /*mvOccupied->DoorLeftOpened*/ DynamicObject->dDoorMoveL > 0.0 ? 1.f : 0.f );
ggDoorRightButton.PutValue( /*mvOccupied->DoorRightOpened*/ DynamicObject->dDoorMoveR > 0.0 ? 1.f : 0.f );
// door lock
ggDoorSignallingButton.PutValue(
mvOccupied->DoorLockEnabled ?
@@ -7491,14 +7508,18 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
btInstrumentLight.Load( Parser, DynamicObject );
InstrumentLightType = 0;
}
else if( Label == "i-instrumentlight_M:" ) {
else if( Label == "i-instrumentlight_m:" ) {
btInstrumentLight.Load( Parser, DynamicObject );
InstrumentLightType = 1;
}
else if( Label == "i-instrumentlight_C:" ) {
else if( Label == "i-instrumentlight_c:" ) {
btInstrumentLight.Load( Parser, DynamicObject );
InstrumentLightType = 2;
}
else if( Label == "i-instrumentlight_a:" ) {
btInstrumentLight.Load( Parser, DynamicObject );
InstrumentLightType = 3;
}
else if (Label == "i-doors:")
{
int i = Parser.getToken<int>() - 1;
@@ -7734,6 +7755,12 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
gauge.Load(Parser, DynamicObject, 0.1);
gauge.AssignDouble(&mvOccupied->PipePress);
}
else if( Label == "scndpress:" ) {
// manometr przewodu hamulcowego
auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka
gauge.Load( Parser, DynamicObject, 0.1 );
gauge.AssignDouble( &mvOccupied->ScndPipePress );
}
else if (Label == "limpipepress:")
{
// manometr zbiornika sterujacego zaworu maszynisty

View File

@@ -509,7 +509,7 @@ public: // reszta może by?publiczna
TButton btInstrumentLight;
TButton btDashboardLight;
TButton btTimetableLight;
int InstrumentLightType{ 0 }; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw.
int InstrumentLightType{ 0 }; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw., 3-rozrzad
bool InstrumentLightActive{ false };
bool DashboardLightActive{ false };
bool TimetableLightActive{ false };

View File

@@ -480,6 +480,9 @@ drivermouse_input::default_bindings() {
{ "brakeprofiler_sw:", {
user_command::brakeactingspeedsetrapid,
user_command::brakeactingspeedsetpassenger } },
{ "brakeopmode_sw:", {
user_command::trainbrakeoperationmodeincrease,
user_command::trainbrakeoperationmodedecrease } },
{ "maxcurrent_sw:", {
user_command::motoroverloadrelaythresholdtoggle,
user_command::none } },

View File

@@ -443,8 +443,8 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
std::abs( mover.enrot ) * 60,
std::abs( mover.nrot ) * mover.Transmision.Ratio * 60,
mover.RventRot * 60,
mover.MotorBlowers[side::front].revolutions,
mover.MotorBlowers[side::rear].revolutions,
std::abs( mover.MotorBlowers[side::front].revolutions ),
std::abs( mover.MotorBlowers[side::rear].revolutions ),
mover.dizel_heat.rpmw,
mover.dizel_heat.rpmw2 );
@@ -470,6 +470,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
// brakes
mover.fBrakeCtrlPos,
mover.LocalBrakePosA,
mover.BrakeOpModeFlag,
update_vehicle_brake().c_str(),
mover.LoadFlag,
// cylinders
@@ -482,7 +483,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
mover.ScndPipePress,
mover.CntrlPipePress,
// tanks
mover.Volume,
mover.Hamulec->GetBRP(),
mover.Compressor,
mover.Hamulec->GetCRP() );
@@ -526,37 +527,7 @@ debug_panel::update_section_vehicle( std::vector<text_line> &Output ) {
vehicle.GetPosition().z );
Output.emplace_back( m_buffer.data(), Global.UITextColor );
/*
textline = " TC:" + to_string( mover.TotalCurrent, 0 );
*/
/*
if( mover.ManualBrakePos > 0 ) {
textline += "; manual brake on";
}
*/
/*
// McZapkie: warto wiedziec w jakim stanie sa przelaczniki
switch(
mover.ActiveDir *
( mover.Imin == mover.IminLo ?
1 :
2 ) ) {
case 2: { textline += " >> "; break; }
case 1: { textline += " -> "; break; }
case 0: { textline += " -- "; break; }
case -1: { textline += " <- "; break; }
case -2: { textline += " << "; break; }
}
// McZapkie: komenda i jej parametry
if( mover.CommandIn.Command != ( "" ) ) {
textline =
"C:" + mover.CommandIn.Command
+ " V1=" + to_string( mover.CommandIn.Value1, 0 )
+ " V2=" + to_string( mover.CommandIn.Value2, 0 );
}
*/
}
std::string
@@ -899,7 +870,10 @@ debug_panel::render_section( std::string const &Header, std::vector<text_line> c
if( false == ImGui::CollapsingHeader( Header.c_str() ) ) { return false; }
for( auto const &line : Lines ) {
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
ImGui::PushStyleColor( ImGuiCol_Text, { line.color.r, line.color.g, line.color.b, line.color.a } );
ImGui::TextUnformatted( line.data.c_str() );
ImGui::PopStyleColor();
// ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
}
return true;
}

View File

@@ -190,11 +190,13 @@ opengl_vbogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream
m_buffercapacity = datasize;
}
// actual draw procedure starts here
auto &chunkrecord { m_chunkrecords[ Geometry.chunk - 1 ] };
// sanity check; shouldn't be needed but, eh
if( chunkrecord.size == 0 ) { return; }
// setup...
if( m_activebuffer != m_buffer ) {
bind_buffer();
}
auto &chunkrecord = m_chunkrecords[ Geometry.chunk - 1 ];
auto const &chunk = gfx::geometry_bank::chunk( Geometry );
if( false == chunkrecord.is_good ) {
// we may potentially need to upload new buffer data before we can draw it

View File

@@ -580,7 +580,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
// without rain/snow we can render the cab early to limit the overdraw
if( ( false == FreeFlyModeFlag )
&& ( Global.Overcast <= 1.f ) ) { // precipitation happens when overcast is in 1-2 range
#ifdef EU07_DISABLECABREFLECTIONS
switch_units( true, true, false );
#endif
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
// cache shadow colour in case we need to account for cab light
auto const shadowcolor { m_shadowcolor };
@@ -603,7 +605,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
Render_precipitation();
// cab render
if( false == FreeFlyModeFlag ) {
#ifdef EU07_DISABLECABREFLECTIONS
switch_units( true, true, false );
#endif
setup_shadow_map( m_cabshadowtexture, m_cabshadowtexturematrix );
// cache shadow colour in case we need to account for cab light
auto const shadowcolor{ m_shadowcolor };
@@ -2612,7 +2616,8 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// material configuration:
Bind_Material( null_handle );
// limit impact of dense fog on the lights
::glFogf( GL_FOG_DENSITY, static_cast<GLfloat>( 1.0 / std::min<float>( Global.fFogEnd, m_fogrange * 2 ) ) );
auto const lightrange { std::max<float>( 500, m_fogrange * 2 ) }; // arbitrary, visibility at least 750m
::glFogf( GL_FOG_DENSITY, static_cast<GLfloat>( 1.0 / lightrange ) );
::glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT );
::glDisable( GL_LIGHTING );
@@ -3147,7 +3152,8 @@ opengl_renderer::Render_Alpha( TAnimModel *Instance ) {
void
opengl_renderer::Render_Alpha( TTraction *Traction ) {
/*
// NOTE: test disabled as this call is only executed as part of the colour pass
double distancesquared;
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
@@ -3160,6 +3166,8 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
break;
}
}
*/
auto const distancesquared { glm::length2( ( Traction->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
if( ( distancesquared < Traction->m_rangesquaredmin )
|| ( distancesquared >= Traction->m_rangesquaredmax ) ) {
return;
@@ -3208,7 +3216,8 @@ void
opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) {
auto const &data { Lines.data() };
/*
// NOTE: test disabled as this call is only executed as part of the colour pass
double distancesquared;
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
@@ -3221,6 +3230,8 @@ opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) {
break;
}
}
*/
auto const distancesquared { glm::length2( ( data.area.center - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor };
if( ( distancesquared < data.rangesquared_min )
|| ( distancesquared >= data.rangesquared_max ) ) {
return;

View File

@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
//#define EU07_USE_DEBUG_CABSHADOWMAP
//#define EU07_USE_DEBUG_CAMERA
//#define EU07_USE_DEBUG_SOUNDEMITTERS
//#define EU07_DISABLECABREFLECTIONS
struct opengl_light : public basic_light {

View File

@@ -36,7 +36,7 @@ scenarioloader_mode::init() {
bool
scenarioloader_mode::update() {
WriteLog( "\nLoading scenario..." );
WriteLog( "\nLoading scenario \"" + Global.SceneryFile + "\"..." );
auto timestart = std::chrono::system_clock::now();

View File

@@ -57,7 +57,7 @@ init() {
"Controllers:\n master: %d(%d), secondary: %s\nEngine output: %.1f, current: %.0f\nRevolutions:\n engine: %.0f, motors: %.0f\n engine fans: %.0f, motor fans: %.0f+%.0f, cooling fans: %.0f+%.0f",
" (shunt mode)",
"\nTemperatures:\n engine: %.2f, oil: %.2f, water: %.2f%c%.2f",
"Brakes:\n train: %.2f, independent: %.2f, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f",
"Brakes:\n train: %.2f, independent: %.2f, mode: %d, delay: %s, load flag: %d\nBrake cylinder pressures:\n train: %.2f, independent: %.2f, status: 0x%.2x\nPipe pressures:\n brake: %.2f (hat: %.2f), main: %.2f, control: %.2f\nTank pressures:\n auxiliary: %.2f, main: %.2f, control: %.2f",
" pantograph: %.2f%cMT",
"Forces:\n tractive: %.1f, brake: %.1f, friction: %.2f%s\nAcceleration:\n tangential: %.2f, normal: %.2f (path radius: %s)\nVelocity: %.2f, distance traveled: %.2f\nPosition: [%.2f, %.2f, %.2f]",
@@ -72,6 +72,7 @@ init() {
"brake acting speed",
"brake acting speed: cargo",
"brake acting speed: rapid",
"brake operation mode",
"motor overload relay threshold",
"water pump",
"water pump breaker",
@@ -194,7 +195,7 @@ init() {
"Nastawniki:\n glowny: %d(%d), dodatkowy: %s\nMoc silnika: %.1f, prad silnika: %.0f\nObroty:\n silnik: %.0f, motory: %.0f\n went.silnika: %.0f, went.motorow: %.0f+%.0f, went.chlodnicy: %.0f+%.0f",
" (tryb manewrowy)",
"\nTemperatury:\n silnik: %.2f, olej: %.2f, woda: %.2f%c%.2f",
"Hamulce:\n zespolony: %.2f, pomocniczy: %.2f, nastawa: %s, ladunek: %d\nCisnienie w cylindrach:\n zespolony: %.2f, pomocniczy: %.2f, status: 0x%.2x\nCisnienia w przewodach:\n glowny: %.2f (kapturek: %.2f), zasilajacy: %.2f, kontrolny: %.2f\nCisnienia w zbiornikach:\n pomocniczy: %.2f, glowny: %.2f, sterujacy: %.2f",
"Hamulce:\n zespolony: %.2f, pomocniczy: %.2f, tryb: %d, nastawa: %s, ladunek: %d\nCisnienie w cylindrach:\n zespolony: %.2f, pomocniczy: %.2f, status: 0x%.2x\nCisnienia w przewodach:\n glowny: %.2f (kapturek: %.2f), zasilajacy: %.2f, kontrolny: %.2f\nCisnienia w zbiornikach:\n pomocniczy: %.2f, glowny: %.2f, sterujacy: %.2f",
" pantograf: %.2f%cZG",
"Sily:\n napedna: %.1f, hamowania: %.1f, tarcie: %.2f%s\nPrzyspieszenia:\n styczne: %.2f, normalne: %.2f (promien: %s)\nPredkosc: %.2f, pokonana odleglosc: %.2f\nPozycja: [%.2f, %.2f, %.2f]",
@@ -209,6 +210,7 @@ init() {
"nastawa hamulca",
"nastawa hamulca: towarowy",
"nastawa hamulca: pospieszny",
"tryb pracy hamulca",
"zakres pradu rozruchu",
"pompa wody",
"wylacznik samoczynny pompy wody",
@@ -318,6 +320,7 @@ init() {
"brakeprofile_sw:",
"brakeprofileg_sw:",
"brakeprofiler_sw:",
"brakeopmode_sw:",
"maxcurrent_sw:",
"waterpump_sw:",
"waterpumpbreaker_sw:",

View File

@@ -61,6 +61,7 @@ enum string {
cab_brakeprofile_sw,
cab_brakeprofileg_sw,
cab_brakeprofiler_sw,
cab_brakeopmode_sw,
cab_maxcurrent_sw,
cab_waterpump_sw,
cab_waterpumpbreaker_sw,

View File

@@ -1 +1 @@
#define VERSION_INFO "M7 09.12.2018, based on tmj-57327f96"
#define VERSION_INFO "M7 31.12.2018, based on tmj-bdbbaaf"