From 318dd9a0fe97389d6a3340ef1c72e0f7ee533874 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 21 Aug 2017 01:29:01 +0200 Subject: [PATCH] build 170820. tweaks and fixes to car detection, proximity scanning, car handling; support for basic diffuse-only gfx renderer mode --- Driver.cpp | 1019 ++++++++++++++++++++------------------------ Driver.h | 6 +- DynObj.cpp | 513 +++++++++------------- DynObj.h | 4 +- Globals.cpp | 12 +- Globals.h | 1 + McZapkie/Mover.cpp | 8 +- Model3d.cpp | 17 - Model3d.h | 1 - World.cpp | 21 +- renderer.cpp | 53 ++- version.h | 2 +- 12 files changed, 743 insertions(+), 914 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 9972d848..7b653b34 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -187,7 +187,7 @@ void TSpeedPos::CommandCheck() } }; -bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) +bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len, TOrders const &Orders ) { // przeliczenie odległości od punktu (*p), w kierunku (*dir), zaczynając od pojazdu // dla kolejnych pozycji podawane są współrzędne poprzedniego obiektu w (*p) vector3 v = vPos - *p; // wektor od poprzedniego obiektu (albo pojazdu) do punktu zmiany @@ -245,49 +245,53 @@ bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) *p = vPos; // nowy punkt odniesienia *dir = Normalize(v); // nowy wektor kierunku od poprzedniego obiektu do aktualnego } - if (iFlags & spTrack) // jeśli tor + if (iFlags & spTrack) // road/track { - if (trTrack) // może być NULL, jeśli koniec toru (???) - { - fVelNext = trTrack->VelocityGet(); // aktualizacja prędkości (może być zmieniana - // eventem) - int i; - if ((i = iFlags & 0xF0000000) != 0) - { // jeśli skrzyżowanie, ograniczyć prędkość przy skręcaniu - if (abs(i) > 0x10000000) //±1 to jazda na wprost, ±2 nieby też, ale z przecięciem - // głównej drogi - chyba że jest równorzędne... - fVelNext = 30.0; // uzależnić prędkość od promienia; albo niech będzie - // ograniczona w skrzyżowaniu (velocity z ujemną wartością) + if (trTrack) { + // może być NULL, jeśli koniec toru (???) + fVelNext = trTrack->VelocityGet(); // aktualizacja prędkości (może być zmieniana eventem) + + if( trTrack->iCategoryFlag & 1 ) { + // railways +/* if( ( iFlags & spElapsed ) == 0 ) { // jeśli nie wjechał + // TODO: remove this block when the detection of vehicles ahead is working properly if( false == trTrack->Dynamics.empty() ) { + // to zabronić wjazdu (chyba że ten z przodu też jedzie prosto) + fVelNext = 25.0; // can't force full stop as it can prevent vehicles from leaving the track. slow down should be enough to ensure slow enough movement to stop if( Global::iWriteLogEnabled & 8 ) { - WriteLog( "Tor " + trTrack->NameGet() + " zajety przed pojazdem. Num=" + std::to_string( trTrack->Dynamics.size() ) + "Dist= " + std::to_string( fDist ) ); - fVelNext = 0.0; // to zabronić wjazdu (chyba że ten z przodu też jedzie prosto) + WriteLog( "Track " + trTrack->NameGet() + " is occupied. Vehicle count: " + std::to_string( trTrack->Dynamics.size() ) + ", distance: " + std::to_string( fDist ) + " m." ); + } + } + } +*/ + if( iFlags & spSwitch ) { + // jeśli odcinek zmienny + if( ( ( trTrack->GetSwitchState() & 1 ) != 0 ) != + ( ( iFlags & spSwitchStatus ) != 0 ) ) { + // czy stan się zmienił? + // Ra: zakładam, że są tylko 2 możliwe stany + iFlags ^= spSwitchStatus; + if( ( iFlags & spElapsed ) == 0 ) { + // jeszcze trzeba skanowanie wykonać od tego toru + // problem jest chyba, jeśli zwrotnica się przełoży zaraz po zjechaniu z niej + // na Mydelniczce potrafi skanować na wprost mimo pojechania na bok + return true; } } } } - if (iFlags & spSwitch) // jeśli odcinek zmienny - { - if (((trTrack->GetSwitchState() & 1) != 0) != - ((iFlags & spSwitchStatus) != 0)) // czy stan się zmienił? - { // Ra: zakładam, że są tylko 2 możliwe stany - iFlags ^= spSwitchStatus; - // fVelNext=trTrack->VelocityGet(); //nowa prędkość - if ((iFlags & spElapsed) == 0) - return true; // jeszcze trzeba skanowanie wykonać od tego toru - // problem jest chyba, jeśli zwrotnica się przełoży zaraz po zjechaniu z niej - // na Mydelniczce potrafi skanować na wprost mimo pojechania na bok - } - // poniższe nie dotyczy trybu łączenia? - if( ( ( iFlags & spElapsed ) == 0 ) - && ( false == trTrack->Dynamics.empty() ) ) { - // jeśli jeszcze nie wjechano na tor, a coś na nim jest - if( Global::iWriteLogEnabled & 8 ) { - WriteLog( "Rozjazd " + trTrack->NameGet() + " zajety przed pojazdem. Num=" + std::to_string( trTrack->Dynamics.size() ) + "Dist= " + std::to_string( fDist ) ); + else { + // roads and others + if( iFlags & 0xF0000000 ) { + // jeśli skrzyżowanie, ograniczyć prędkość przy skręcaniu + if( ( iFlags & 0xF0000000 ) > 0x10000000 ) { + // ±1 to jazda na wprost, ±2 nieby też, ale z przecięciem głównej drogi - chyba że jest równorzędne... + // TODO: uzależnić prędkość od promienia; + // albo niech będzie ograniczona w skrzyżowaniu (velocity z ujemną wartością) + fVelNext = 30.0; } - fVelNext = 0.0; // to niech stanie w zwiększonej odległości } } } @@ -314,7 +318,7 @@ std::string TSpeedPos::TableText() { // pozycja tabelki pr?dko?ci if (iFlags & spEnabled) { // o ile pozycja istotna - return "Flags:" + to_hex_str(iFlags, 6) + ", Dist:" + to_string(fDist, 1, 6) + + return "Flags:" + to_hex_str(iFlags, 8) + ", Dist:" + to_string(fDist, 1, 6) + ", Vel:" + (fVelNext == -1.0 ? " - " : to_string(static_cast(fVelNext), 0, 3)) + ", Name:" + GetName(); //if (iFlags & spTrack) // jeśli tor // return "Flags=#" + IntToHex(iFlags, 8) + ", Dist=" + FloatToStrF(fDist, ffFixed, 7, 1) + @@ -374,7 +378,7 @@ void TSpeedPos::Set(TTrack *track, double dist, int flag) trTrack = track; // TODO: (t) może być NULL i nie odczytamy końca poprzedniego :/ if (trTrack) { - iFlags = flag | (trTrack->eType == tt_Normal ? 2 : 10); // zapamiętanie kierunku wraz z typem + iFlags = flag | (trTrack->eType == tt_Normal ? spTrack : (spTrack | spSwitch) ); // zapamiętanie kierunku wraz z typem if (iFlags & spSwitch) if (trTrack->GetSwitchState() & 1) iFlags |= spSwitchStatus; @@ -570,8 +574,8 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if( ( pTrack->VelocityGet() == 0.0 ) // zatrzymanie || ( pTrack->iAction ) // jeśli tor ma własności istotne dla skanowania - || ( pTrack->VelocityGet() != fLastVel ) ) // następuje zmiana prędkości - { // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu + || ( pTrack->VelocityGet() != fLastVel ) ) { // następuje zmiana prędkości + // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu if (TableAddNew()) { // teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania sSpeedTable[ iLast ].Set( @@ -697,7 +701,7 @@ void TController::TableCheck(double fDistance) { // aktualizacja rekordów z wyjątkiem ostatniego if (sSpeedTable[i].iFlags & spEnabled) // jeśli pozycja istotna { - if (sSpeedTable[i].Update(&pos, &dir, len)) + if (sSpeedTable[i].Update(&pos, &dir, len, OrderCurrentGet())) { if( Global::iWriteLogEnabled & 8 ) { WriteLog( "Speed table for " + OwnerName() + " detected switch change at " + sSpeedTable[ i ].trTrack->NameGet() + " (generating fresh trace)" ); @@ -740,7 +744,7 @@ void TController::TableCheck(double fDistance) } } } - sSpeedTable[iLast].Update(&pos, &dir, len); // aktualizacja ostatniego + sSpeedTable[iLast].Update(&pos, &dir, len, OrderCurrentGet()); // aktualizacja ostatniego // WriteLog("TableCheck: Upate last track. Dist=" + AnsiString(sSpeedTable[iLast].fDist)); if( sSpeedTable[ iLast ].fDist < fDistance ) { TableTraceRoute( fDistance, pVehicles[ 1 ] ); // doskanowanie dalszego odcinka @@ -1154,10 +1158,11 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } //sprawdzenie eventów pasywnych przed nami - if ((mvOccupied->CategoryFlag & 1) ? - sSpeedTable[i].fDist > pVehicles[0]->fTrackBlock - 20.0 : - false) // jak sygnał jest dalej niż zawalidroga + if( ( mvOccupied->CategoryFlag & 1 ) + && ( sSpeedTable[ i ].fDist > pVehicles[ 0 ]->fTrackBlock - 20.0 ) ) { + // jak sygnał jest dalej niż zawalidroga v = 0.0; // to może być podany dla tamtego: jechać tak, jakby tam stop był + } else { // zawalidrogi nie ma (albo pojazd jest samochodem), sprawdzić sygnał if (sSpeedTable[i].iFlags & spShuntSemaphor) // jeśli Tm - w zasadzie to sprawdzić @@ -1824,8 +1829,7 @@ bool TController::CheckVehicles(TOrders user) 1 : 0); //światła manewrowe (Tb1) na pojeździe z napędem if (OrderCurrentGet() & Connect) // jeśli łączenie, skanować dalej - pVehicles[0]->fScanDist = - 5000.0; // odległość skanowania w poszukiwaniu innych pojazdów + pVehicles[0]->fScanDist = 5000.0; // odległość skanowania w poszukiwaniu innych pojazdów } else if (OrderCurrentGet() == Disconnect) if (mvOccupied->ActiveDir > 0) // jak ma kierunek do przodu @@ -1936,17 +1940,7 @@ void TController::WaitingSet(double Seconds) void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) { // ustawienie nowej prędkości - WaitingTime = -WaitingExpireTime; // przypisujemy -WaitingExpireTime, a potem porównujemy z - // zerem - MaxVelFlag = false; // Ra: to nie jest używane - MinVelFlag = false; // Ra: to nie jest używane - /* nie używane - if ((NewVel>NewVelNext) //jeśli oczekiwana większa niż następna - || (NewVelVel)) //albo aktualna jest mniejsza niż aktualna - fProximityDist=-800.0; //droga hamowania do zmiany prędkości - else - fProximityDist=-300.0; //Ra: ujemne wartości są ignorowane - */ + WaitingTime = -WaitingExpireTime; // przypisujemy -WaitingExpireTime, a potem porównujemy z zerem if (NewVel == 0.0) // jeśli ma stanąć { if (r != stopNone) // a jest powód podany @@ -1981,24 +1975,6 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) VelNext = NewVelNext; // prędkość przy następnym obiekcie } -/* //funkcja do niczego nie potrzebna (ew. do przesunięcia pojazdu o odległość NewDist) -bool TController::SetProximityVelocity(double NewDist,double NewVelNext) -{//informacja o prędkości w pewnej odległości -#if 0 - if (NewVelNext==0.0) - WaitingTime=0.0; //nie trzeba już czekać - //if ((NewVelNext>=0)&&((VelNext>=0)&&(NewVelNextVel / (std::max(0.0, ActualProximityDist) + 1); @@ -3394,7 +3370,7 @@ bool TController::UpdateSituation(double dt) } // Winger 020304 - if (AIControllFlag) + if (true == AIControllFlag) { if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { @@ -3416,6 +3392,10 @@ bool TController::UpdateSituation(double dt) if (mvOccupied->Vel > 1.0) // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 // akceptuje niewielkie prędkości Doors(false); +/* + // NOTE: this section moved all cars to the edge of their respective roads + // it may have some use eventually for collision avoidance, + // but when enabled all the time it produces silly effect // przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi if (mvOccupied->CategoryFlag & 2) // jeśli samochód // if (fabs(mvOccupied->OffsetTrackH)Dim.W) //Ra: szerokość drogi tu @@ -3424,6 +3404,7 @@ bool TController::UpdateSituation(double dt) // drogi mvOccupied->ChangeOffsetH(0.01 * mvOccupied->Vel * dt); // Ra: co to miało być, to nie wiem +*/ if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { if ((fOverhead2 >= 0.0) || iOverheadZero) @@ -3462,23 +3443,20 @@ bool TController::UpdateSituation(double dt) } } } - if (iDrivigFlags & moveStartHornNow) // czy ma zatrąbić przed ruszeniem? - if (Ready) // gotów do jazdy - if (iEngineActive) // jeszcze się odpalić musi - if (fStopTime >= 0) // i nie musi czekać - { // uruchomienie trąbienia - fWarningDuration = 0.3; // czas trąbienia - // if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie - mvOccupied->WarningSignal = - pVehicle->iHornWarning; // wysokość tonu (2=wysoki) - iDrivigFlags |= moveStartHornDone; // nie trąbić aż do ruszenia - iDrivigFlags &= ~moveStartHornNow; // trąbienie zostało zorganizowane - } + if( ( true == TestFlag( iDrivigFlags, moveStartHornNow ) ) + && ( true == Ready ) + && ( iEngineActive != 0 ) + && ( fStopTime >= 0 ) ) { + // uruchomienie trąbienia przed ruszeniem + fWarningDuration = 0.3; // czas trąbienia + mvOccupied->WarningSignal = pVehicle->iHornWarning; // wysokość tonu (2=wysoki) + iDrivigFlags |= moveStartHornDone; // nie trąbić aż do ruszenia + iDrivigFlags &= ~moveStartHornNow; // trąbienie zostało zorganizowane + } } ElapsedTime += dt; WaitingTime += dt; - // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca - fBrakeTime -= dt; + fBrakeTime -= dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi if (WriteLogFlag) @@ -3498,15 +3476,12 @@ bool TController::UpdateSituation(double dt) // Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość if ((LastReactionTime > std::min(ReactionTime, 2.0))) { - // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna - // STÓJ + // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna STÓJ // yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy // wdrażaniu hamowania, żeby nie ruszało kranem jak głupie // Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory // Ra: trzeba by tak: // 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max). - fBrakeDist = fDriverBraking * mvOccupied->Vel * - (40.0 + mvOccupied->Vel); // przybliżona droga hamowania // dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km // dla 100km/h i 9.8km dla 160km/h // dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km @@ -3514,21 +3489,28 @@ bool TController::UpdateSituation(double dt) // ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m] // fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w // zależności od prędkości i siły (ciśnienia) hamowania - // następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane - // zalecane ciśnienie - if (fMass > 1000000.0) - fBrakeDist *= 2.0; // korekta dla ciężkich, bo przeżynają - da to coś? - if ((-fAccThreshold>0.05)&&(mvOccupied->CategoryFlag==1)) - fBrakeDist = mvOccupied->Vel * mvOccupied->Vel / 25.92 / -fAccThreshold; - if (mvOccupied->BrakeDelayFlag == bdelay_G) - fBrakeDist = fBrakeDist + 2 * mvOccupied->Vel; // dla nastawienia G - // koniecznie należy wydłużyć drogę na czas reakcji + // następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane zalecane ciśnienie + + // przybliżona droga hamowania + fBrakeDist = fDriverBraking * mvOccupied->Vel * ( 40.0 + mvOccupied->Vel ); + if( fMass > 1000000.0 ) { + // korekta dla ciężkich, bo przeżynają - da to coś? + fBrakeDist *= 2.0; + } + if( ( -fAccThreshold > 0.05 ) + && ( mvOccupied->CategoryFlag == 1 ) ) { + fBrakeDist = mvOccupied->Vel * mvOccupied->Vel / 25.92 / -fAccThreshold; + } + if( mvOccupied->BrakeDelayFlag == bdelay_G ) { + // dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji + fBrakeDist += 2 * mvOccupied->Vel; + } // double scanmax=(mvOccupied->Vel>0.0)?3*fDriverDist+fBrakeDist:10.0*fDriverDist; - double scanmax = (mvOccupied->Vel > 5.0) ? - 400 + fBrakeDist : - 30.0 * fDriverDist; // 1500m dla stojących pociągów; Ra 2015-01: przy - //double scanmax = Max0R(400 + fBrakeDist, 1500); - // dłuższej drodze skanowania AI jeździ spokojniej + double scanmax = ( + mvOccupied->Vel > 5.0 ? + 400 + fBrakeDist : + 30.0 * fDriverDist ); // 1500m dla stojących pociągów; + // Ra 2015-01: przy dłuższej drodze skanowania AI jeździ spokojniej // 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP). // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, // czy stan się nie zmienił. @@ -3540,6 +3522,43 @@ bool TController::UpdateSituation(double dt) // 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość. // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji // - rzadziej). + // check for potential colliders + { + auto const scandistance = 300.0 + fBrakeDist; + auto rearvehicle = ( + pVehicles[ 0 ] == pVehicles[ 1 ] ? + pVehicles[ 0 ] : + pVehicles[ 1 ] ); + if( iDirection > 0 ) { + // towards coupler 0 + if( ( rearvehicle->NextConnected != nullptr ) + && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 1 : 0 ) ].CouplingFlag == ctrain_virtual ) ) { + // scan behind if we had something connected there and are moving away + rearvehicle->ABuScanObjects( -1, fMaxProximityDist ); + } + pVehicles[ 0 ]->ABuScanObjects( 1, scandistance ); + } + else { + // towards coupler 1 + if( ( rearvehicle->PrevConnected != nullptr ) + && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 0 : 1 ) ].CouplingFlag == ctrain_virtual ) ) { + // scan behind if we had something connected there and are moving away + rearvehicle->ABuScanObjects( 1, fMaxProximityDist ); + } + pVehicles[ 0 ]->ABuScanObjects( -1, scandistance ); + } + } +/* + pVehicles[ 0 ]->fScanDist = ( + mvOccupied->Vel > 5.0 ? + 400 + fBrakeDist : + 300.0 ); + pVehicles[ 0 ]->Update_scan(); + if( pVehicles[ 1 ] != pVehicles[ 0 ] ) { + pVehicles[ 1 ]->fScanDist = pVehicles[ 0 ]->fScanDist; + pVehicles[ 1 ]->Update_scan(); + } +*/ if (AIControllFlag) { // tu bedzie logika sterowania if (mvOccupied->CommandIn.Command != "") @@ -3586,13 +3605,15 @@ bool TController::UpdateSituation(double dt) } } } + switch (OrderList[OrderPos]) { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach - case Connect: // podłączanie do składu - if (iDrivigFlags & moveConnect) - { // jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć - fMinProximityDist = -0.01; - fMaxProximityDist = 0.0; //[m] dojechać maksymalnie + case Connect: { + // podłączanie do składu + if (iDrivigFlags & moveConnect) { + // jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć + fMinProximityDist = -0.5; + fMaxProximityDist = 0.0; //[m] dojechać maksymalnie fVelPlus = 0.5; // dopuszczalne przekroczenie prędkości na ograniczeniu bez // hamowania fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu @@ -3647,52 +3668,33 @@ bool TController::UpdateSituation(double dt) else SetVelocity(2.0, 0.0); // jazda w ustawionym kierunku z prędkością 2 (18s) } // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna - /* //Ra 2014-02: lepiej tam, bo jak tam się odźwieży skład, to tu pVehicles[0] - będzie czymś innym - else - {//jeśli człowiek ma podłączyć, to czekamy na zmianę stanu sprzęgów na końcach - dotychczasowego składu - bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) - if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0 - ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag>0); - //==iCoupler); //udało się? (mogło częściowo) - else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 - ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag>0); - //==iCoupler); //udało się? (mogło częściowo) - if (ok) - {//jeżeli został podłączony - iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania - JumpToNextOrder(); //wykonanie następnej komendy - } - } - */ } - else - { // jak daleko, to jazda jak dla Shunt na kolizję - fMinProximityDist = 0.0; + else { + // jak daleko, to jazda jak dla Shunt na kolizję + fMinProximityDist = 2.0; fMaxProximityDist = 5.0; //[m] w takim przedziale odległości powinien stanąć - fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez - // hamowania + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania fVelMinus = 1.0; // margines prędkości powodujący załączenie napędu - // VelReduced=5; //[km/h] - // if (mvOccupied->Vel<0.5) //jeśli już prawie stanął - if (pVehicles[0]->fTrackBlock <= - 20.0) // przy zderzeniu fTrackBlock nie jest miarodajne - iDrivigFlags |= - moveConnect; // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock + if( pVehicles[ 0 ]->fTrackBlock <= 20.0 ) { + // przy zderzeniu fTrackBlock nie jest miarodajne + // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock + iDrivigFlags |= moveConnect; + } } break; - case Disconnect: // 20.07.03 - manewrowanie wagonami + } + case Disconnect: { + // 20.07.03 - manewrowanie wagonami fMinProximityDist = 1.0; fMaxProximityDist = 10.0; //[m] fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu - if (AIControllFlag) - { - if (iVehicleCount >= 0) // jeśli była podana ilość wagonów - { - if (iDrivigFlags & movePress) // jeśli dociskanie w celu odczepienia - { // 3. faza odczepiania. + if (AIControllFlag) { + if (iVehicleCount >= 0) { + // jeśli była podana ilość wagonów + if (iDrivigFlags & movePress) { + // jeśli dociskanie w celu odczepienia + // 3. faza odczepiania. SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2 if ((mvControlling->MainCtrlPos > 0) || (mvOccupied->BrakeSystem == ElectroPneumatic)) // jeśli jazda @@ -3714,10 +3716,8 @@ bool TController::UpdateSituation(double dt) // if (p->GetTrack()->) //a nie stoi na torze warsztatowym // (ustalić po czym poznać taki tor) ++n; // to liczymy człony jako jeden - p->MoverParameters->BrakeReleaser( - 1); // wyluzuj pojazd, aby dało się dopychać - p->MoverParameters->BrakeLevelSet( - 0); // hamulec na zero, aby nie hamował + p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać + p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował if (n) { // jeśli jeszcze nie koniec p = p->Prev(); // kolejny w stronę czoła składu (licząc od @@ -3727,11 +3727,12 @@ bool TController::UpdateSituation(double dt) n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone } } while (n--); - if (p ? p->MoverParameters->Couplers[d].CouplingFlag == 0 : true) + if( p ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) { + // no target, or already just virtual coupling + WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); iVehicleCount = -2; // odczepiono, co było do odczepienia - else if (!p->Dettach(d)) // zwraca maskę bitową połączenia; usuwa - // własność pojazdów - { // tylko jeśli odepnie + } else if ( p->Dettach(d) == coupling::faux ) { + // tylko jeśli odepnie WriteLog( mvOccupied->Name + " odczepiony." ); iVehicleCount = -2; } // a jak nie, to dociskać dalej @@ -3750,15 +3751,14 @@ bool TController::UpdateSituation(double dt) // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach // powino zostać wyłączone) // WriteLog("Zahamowanie składu"); - // while ((mvOccupied->BrakeCtrlPos>3)&&mvOccupied->DecBrakeLevel()); - // while ((mvOccupied->BrakeCtrlPos<3)&&mvOccupied->IncBrakeLevel()); mvOccupied->BrakeLevelSet(mvOccupied->BrakeSystem == ElectroPneumatic ? 1 : 3); - double p = mvOccupied->BrakePressureActual - .PipePressureVal; // tu może być 0 albo -1 nawet - if (p < 3.9) - p = 3.9; // TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia - // sensu 0 oraz -1 w tym miejscu + double p = mvOccupied->BrakePressureActual.PipePressureVal; + if( p < 3.9 ) { + // tu może być 0 albo -1 nawet + // TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu + p = 3.9; + } if (mvOccupied->BrakeSystem == ElectroPneumatic ? mvOccupied->BrakePress > 2 : mvOccupied->PipePress < p + 0.1) @@ -3772,10 +3772,8 @@ bool TController::UpdateSituation(double dt) mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45? mvOccupied->DecLocalBrakeLevel(10); // zwolnienie hamulca iDrivigFlags |= movePress; // następnie będzie dociskanie - DirectionForward(mvOccupied->ActiveDir < - 0); // zmiana kierunku jazdy na przeciwny (dociskanie) - CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie - // odczepi + DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie) + CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi fStopTime = 0.0; // nie ma na co czekać z odczepianiem } } @@ -3787,8 +3785,7 @@ bool TController::UpdateSituation(double dt) if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da { // ponowna zmiana kierunku WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" ); - DirectionForward(mvOccupied->ActiveDir < - 0); // zmiana kierunku jazdy na właściwy + DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy iDrivigFlags &= ~movePress; // koniec dociskania JumpToNextOrder(); // zmieni światła TableClear(); // skanowanie od nowa @@ -3798,63 +3795,58 @@ bool TController::UpdateSituation(double dt) } } break; - case Shunt: + } + case Shunt: { // na jaką odleglość i z jaką predkością ma podjechać - fMinProximityDist = 2.0; - fMaxProximityDist = 4.0; //[m] + fMinProximityDist = 5.0; + fMaxProximityDist = 10.0; //[m] fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus = 3.0; // margines prędkości powodujący załączenie napędu - if (fVelMinus > 0.1 * fShuntVelocity) - fVelMinus = - 0.1 * - fShuntVelocity; // były problemy z jazdą np. 3km/h podczas ładowania wagonów + // margines prędkości powodujący załączenie napędu + // były problemy z jazdą np. 3km/h podczas ładowania wagonów + fVelMinus = std::min( 0.1 * fShuntVelocity, 3.0 ); break; - case Obey_train: + } + case Obey_train: { // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody - if (mvOccupied->CategoryFlag & 1) // jeśli pociąg - { - fMinProximityDist = 10.0; + if( mvOccupied->CategoryFlag & 1 ) { + // jeśli pociąg + fMinProximityDist = 15.0; fMaxProximityDist = - (mvOccupied->Vel > 0.0) ? - 20.0 : + ( mvOccupied->Vel > 0.0 ) ? + 25.0 : 50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów - if (iDrivigFlags & moveLate) - { - fVelMinus = 1.0; // jeśli spóźniony, to gna - fVelPlus = - 5.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + if( iDrivigFlags & moveLate ) { + // jeśli spóźniony, to gna + fVelMinus = 1.0; + // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelPlus = 5.0; } - else - { // gdy nie musi się sprężać - fVelMinus = - int(0.05 * VelDesired); // margines prędkości powodujący załączenie napędu - if (fVelMinus > 5.0) - fVelMinus = 5.0; - else if (fVelMinus < 1.0) - fVelMinus = 1.0; //żeby nie ruszał przy 0.1 - fVelPlus = int( - 0.5 + - 0.05 * VelDesired); // normalnie dopuszczalne przekroczenie to 5% prędkości - if (fVelPlus > 5.0) - fVelPlus = 5.0; // ale nie więcej niż 5km/h + else { + // gdy nie musi się sprężać + // margines prędkości powodujący załączenie napędu; min 1.0 żeby nie ruszał przy 0.1 + fVelMinus = clamp( std::round( 0.05 * VelDesired ), 1.0, 5.0 ); + // normalnie dopuszczalne przekroczenie to 5% prędkości ale nie więcej niż 5km/h + fVelPlus = std::min( 5.0, std::ceil( 0.05 * VelDesired ) ); } } - else // samochod (sokista też) - { - fMinProximityDist = 7.0; - fMaxProximityDist = 10.0; //[m] - fVelPlus = - 10.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus = 2.0; // margines prędkości powodujący załączenie napędu + else { + // samochod (sokista też) + fMinProximityDist = std::max( 4.0, mvOccupied->Vel * 0.2 ); + fMaxProximityDist = std::max( 8.0, mvOccupied->Vel * 0.375 ); //[m] + // margines prędkości powodujący załączenie napędu + fVelMinus = 2.0; + // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelPlus = std::min( 10.0, mvOccupied->Vel * 0.1 ); } - // VelReduced=4; //[km/h] break; - default: + } + default: { fMinProximityDist = 0.01; fMaxProximityDist = 2.0; //[m] fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania fVelMinus = 5.0; // margines prędkości powodujący załączenie napędu - } // switch + } + } // switch OrderList[OrderPos] switch (OrderList[OrderPos]) { // co robi maszynista @@ -3889,25 +3881,6 @@ bool TController::UpdateSituation(double dt) #endif break; case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora - /* - if ((mvOccupied->ActiveDir!=0)) - {//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy - VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie - ograniczana - SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?) - //Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci - AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika - VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż - trajektoria ruchu - ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian - //hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal - - a teraz jak to zrobić? - TCommandType - comm=TableUpdate(mvOccupied->Vel,VelDesired,ActualProximityDist,VelNext,AccDesired); - //szukanie optymalnych wartości - } - */ - // break; case Shunt: case Obey_train: case Connect: @@ -3918,17 +3891,21 @@ bool TController::UpdateSituation(double dt) if (OrderList[OrderPos] != Obey_train) // spokojne manewry { VelSignal = Global::Min0RSpeed(VelSignal, 40); // jeśli manewry, to ograniczamy prędkość - if (AIControllFlag) - { // to poniżej tylko dla AI - if (iVehicleCount >= 0) // jeśli jest co odczepić - if (!(iDrivigFlags & movePress)) - if (mvOccupied->Vel > 0.0) - if (!iCoupler) // jeśli nie ma wcześniej potrzeby podczepienia - { - SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie - // WriteLog("Zatrzymanie w celu odczepienia"); - } + + // NOTE: this section should be moved to disconnect or plain removed, but it seems to be (mis)used by some scenarios + // to keep vehicle idling without moving :| + if( ( true == AIControllFlag ) + && ( iVehicleCount >= 0 ) + && ( false == TestFlag( iDrivigFlags, movePress ) ) + && ( iCoupler == 0 ) +// && ( mvOccupied->Vel > 0.0 ) + && ( pVehicle->PrevConnected == nullptr ) + && ( pVehicle->NextConnected == nullptr ) ) { + SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie + // WriteLog("Zatrzymanie w celu odczepienia"); + AccPreferred = std::min( 0.0, AccPreferred ); } + } else SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? @@ -3978,9 +3955,10 @@ bool TController::UpdateSituation(double dt) SetVelocity(-1, -1); // jak się nastał, to niech jedzie WaitingTime = 0.0; } - else - SetVelocity(-1, - -1); // użytkownikowi pozwalamy jechać (samochodem?) + else { + // użytkownikowi pozwalamy jechać (samochodem?) + SetVelocity( -1, -1 ); + } } } else if ((VelSignal == 0.0) && (VelNext > 0.0) && (mvOccupied->Vel < 1.0)) @@ -3990,58 +3968,42 @@ bool TController::UpdateSituation(double dt) // manewrowym !!!! SetVelocity(VelNext, VelNext, stopSem); // omijanie SBL } // koniec samoistnego odjeżdżania - if (AIControllFlag) - if ((HelpMeFlag) || (mvControlling->DamageFlag > 0)) - { + + if( ( true == AIControllFlag ) + && ( ( true == HelpMeFlag ) + || ( mvControlling->DamageFlag > 0 ) ) ) { HelpMeFlag = false; - /* - if (WriteLogFlag) - with Controlling do - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," HelpMe! - (",DamageFlag,")"); - close(AILogFile); - } - */ - } - if (AIControllFlag) - if (OrderList[OrderPos] & - Change_direction) // może być zmieszane z jeszcze jakąś komendą - { // sprobuj zmienic kierunek - SetVelocity(0, 0, stopDir); // najpierw trzeba się zatrzymać - if (mvOccupied->Vel < 0.1) - { // jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon - Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne - // przemieszczenie AI - PrepareEngine(); - JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo - // Obey_train) - if (OrderList[OrderPos] & (Shunt | Connect)) // jeśli dalej mamy manewry - if ((iDrivigFlags & moveStopHere) == 0) // o ile nie stać w miejscu - { // jechać od razu w przeciwną stronę i nie trąbić z tego tytułu - iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem - SetVelocity(fShuntVelocity, fShuntVelocity); // to od razu jedziemy - } - // iDrivigFlags|=moveStartHorn; //a później już można trąbić - /* - if (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," Direction changed!"); - close(AILogFile); - } - */ + } + + if( ( true == AIControllFlag) + && ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) { + // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą) + SetVelocity( 0, 0, stopDir ); // najpierw trzeba się zatrzymać + if( mvOccupied->Vel < 0.1 ) { + // jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon + Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI + PrepareEngine(); + JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train) + if( OrderList[ OrderPos ] & ( Shunt | Connect ) ) { + // jeśli dalej mamy manewry + if( false == TestFlag( iDrivigFlags, moveStopHere ) ) { + // o ile nie ma stać w miejscu, + // jechać od razu w przeciwną stronę i nie trąbić z tego tytułu: + iDrivigFlags &= ~moveStartHorn; + SetVelocity( fShuntVelocity, fShuntVelocity ); + } } - // else - // VelSignal:=0.0; //na wszelki wypadek niech zahamuje - } // Change_direction (tylko dla AI) + } + } // Change_direction (tylko dla AI) + + if( ( true == AIControllFlag ) + && ( iEngineActive == 0 ) + && ( OrderList[ OrderPos ] & ( Change_direction | Connect | Disconnect | Shunt | Obey_train ) ) ) { + // jeśli coś ma robić to niech odpala do skutku + PrepareEngine(); + } + // ustalanie zadanej predkosci - if (AIControllFlag) // jeśli prowadzi AI - if (!iEngineActive) // jeśli silnik nie odpalony, to próbować naprawić - if (OrderList[OrderPos] & (Change_direction | Connect | Disconnect | Shunt | - Obey_train)) // jeśli coś ma robić - PrepareEngine(); // to niech odpala do skutku if (iDrivigFlags & moveActive) // jeśli może skanować sygnały i reagować na komendy { // jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy // Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od @@ -4056,16 +4018,10 @@ bool TController::UpdateSituation(double dt) SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?) // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika - VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż - // trajektoria ruchu - ActualProximityDist = scanmax; // funkcja Update() może pozostawić wartości bez - // zmian - // hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak - // VelSignal - a teraz jak to zrobić? - TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, - AccDesired); // szukanie optymalnych wartości - // if (VelSignal!=VelDesired) //jeżeli prędkość zalecana jest inna (ale tryb też - // może być inny) + VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu + ActualProximityDist = scanmax; // funkcja Update() może pozostawić wartości bez zmian + // szukanie optymalnych wartości + TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); switch (comm) { // ustawienie VelSignal - trochę proteza = do przemyślenia case cm_Ready: // W4 zezwolił na jazdę @@ -4143,111 +4099,86 @@ bool TController::UpdateSituation(double dt) vel = -vel; // ujemna, gdy jedzie w przeciwną stronę, niż powinien if (VelDesired < 0.0) VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną + // Ra: jazda na widoczność - if (pVehicles[0]->fTrackBlock < 1000.0) // przy 300m stał z zapamiętaną kolizją - { // Ra 2F3F: przy jeździe pociągowej nie powinien dojeżdżać do poprzedzającego - // składu - if ((mvOccupied->CategoryFlag & 1) ? - ((OrderCurrentGet() & (Connect | Obey_train)) == Obey_train) : - false) // jeśli jesteśmy pociągiem a jazda pociągowa i nie ściąganie ze - // szlaku - { - pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(), - 1000.0); // skanowanie sprawdzające - // Ra 2F3F: i jest problem, jak droga za semaforem kieruje na jakiś pojazd - // (np. w Skwarkach na ET22) - if (pVehicles[0]->fTrackBlock < 1000.0) // i jeśli nadal coś jest - if (VelNext != 0.0) // a następny sygnał zezwala na jazdę - if (pVehicles[0]->fTrackBlock < - ActualProximityDist) // i jest bliżej (tu by trzeba było wstawić - // odległość do semafora, z pominięciem SBL - VelDesired = 0.0; // to stoimy - } - else - pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(), - 300.0); // skanowanie sprawdzające - } - // if (mvOccupied->Vel>=0.1) //o ile jedziemy; jak stoimy to też trzeba jakoś - // zatrzymywać +/* + // condition disabled, it'd prevent setting reduced acceleration in the last connect stage if ((iDrivigFlags & moveConnect) == 0) // przy końcówce podłączania nie hamować +*/ { // sprawdzenie jazdy na widoczność - TCoupling *c = - pVehicles[0]->MoverParameters->Couplers + - (pVehicles[0]->DirectionGet() > 0 ? 0 : 1); // sprzęg z przodu składu - if (c->Connected) // a mamy coś z przodu - if (c->CouplingFlag == - 0) // jeśli to coś jest podłączone sprzęgiem wirtualnym - { // wyliczanie optymalnego przyspieszenia do jazdy na widoczność - double k = c->Connected->Vel; // prędkość pojazdu z przodu (zakładając, - // że jedzie w tę samą stronę!!!) - if (k < vel + 10) // porównanie modułów prędkości [km/h] - { // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej - double d = - pVehicles[0]->fTrackBlock - 0.5 * vel - - fMaxProximityDist; // odległość bezpieczna zależy od prędkości - if (d < 0) // jeśli odległość jest zbyt mała - { // AccPreferred=-0.9; //hamowanie maksymalne, bo jest za blisko - if (k < 10.0) // k - prędkość tego z przodu - { // jeśli tamten porusza się z niewielką prędkością albo stoi - if (OrderCurrentGet() & Connect) - { // jeśli spinanie, to jechać dalej - AccPreferred = 0.2; // nie hamuj - VelNext = VelDesired = 2.0; // i pakuj się na tamtego - } - else // a normalnie to hamować - { - AccPreferred = -1.0; // to hamuj maksymalnie - VelNext = VelDesired = 0.0; // i nie pakuj się na - // tamtego + auto const vehicle = pVehicles[ 0 ]; // base calculactions off relevant end of the consist + auto const coupler = + vehicle->MoverParameters->Couplers + ( + vehicle->DirectionGet() > 0 ? + 0 : + 1 ); // sprzęg z przodu składu + if( ( coupler->Connected ) + && ( coupler->CouplingFlag == 0 ) ) { + // mamy coś z przodu podłączone sprzęgiem wirtualnym + // wyliczanie optymalnego przyspieszenia do jazdy na widoczność + ActualProximityDist = std::min( + ActualProximityDist, + vehicle->fTrackBlock - ( + mvOccupied->CategoryFlag & 2 ? + 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ę!!!) + if( k < vel + 10 ) { + // porównanie modułów prędkości [km/h] + // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej + double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości + if( distance < 0 ) { + // jeśli odległość jest zbyt mała + if( k < 10.0 ) // k - prędkość tego z przodu + { // jeśli tamten porusza się z niewielką prędkością albo stoi + if( OrderCurrentGet() & Connect ) { + // jeśli spinanie, to jechać dalej + AccPreferred = std::min( 0.25, AccPreferred ); // nie hamuj + VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); + VelNext = 2.0; // i pakuj się na tamtego + } + else { + // a normalnie to hamować + VelNext = 0.0; + if( vehicle->fTrackBlock <= fMinProximityDist ) { + VelDesired = 0.0; } } - else // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość - { - if (k < vel) // jak tamten jedzie wolniej - if (d < fBrakeDist) // a jest w drodze hamowania - { - if (AccPreferred > fAccThreshold) - AccPreferred = - fAccThreshold; // to przyhamuj troszkę - VelNext = VelDesired = int(k); // to chyba już sobie - // dohamuje według - // uznania - } - } - ReactionTime = 0.1; // orientuj się, bo jest goraco } - else - { // jeśli odległość jest większa, ustalić maksymalne możliwe - // przyspieszenie (hamowanie) - k = (k * k - vel * vel) / (25.92 * d); // energia kinetyczna - // dzielona przez masę i - // drogę daje - // przyspieszenie - if (k > 0.0) - k *= 1.5; // jedź szybciej, jeśli możesz - // double ak=(c->Connected->V>0?1.0:-1.0)*c->Connected->AccS; - // //przyspieszenie tamtego - if (d < fBrakeDist) // a jest w drodze hamowania - if (k < AccPreferred) - { // jeśli nie ma innych powodów do wolniejszej jazdy - AccPreferred = k; - if (VelNext > c->Connected->Vel) - { - VelNext = - c->Connected - ->Vel; // ograniczenie do prędkości tamtego - ActualProximityDist = - d; // i odległość od tamtego jest istotniejsza - } - ReactionTime = 0.2; // zwiększ czujność + else { + // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość + if( vehicle->fTrackBlock < ( + mvOccupied->CategoryFlag & 2 ? + fMaxProximityDist + 0.5 * vel : // cars + 2.0 * fMaxProximityDist + 2.0 * vel ) ) { //others + // jak tamten jedzie wolniej a jest w drodze hamowania + AccPreferred = std::min( -0.9, AccPreferred ); + VelNext = Global::Min0RSpeed( std::round( k ) - 5.0, VelDesired ); + if( vehicle->fTrackBlock <= ( + mvOccupied->CategoryFlag & 2 ? + fMaxProximityDist : // cars + 2.0 * fMaxProximityDist ) ) { //others + // try to force speed change if obstacle is really close + VelDesired = VelNext; } -#if LOGVELOCITY - WriteLog("Collision: AccPreferred=" + AnsiString(k)); -#endif + } + } + ReactionTime = ( + vel != 0.0 ? + 0.1 : // orientuj się, bo jest goraco + 2.0 ); // we're already standing still, so take it easy + } + else { + if( OrderCurrentGet() & Connect ) { + // if there's something nearby in the connect mode don't speed up too much + VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); } } } + } } + // sprawdzamy możliwe ograniczenia prędkości if (OrderCurrentGet() & (Shunt | Obey_train)) // w Connect nie, bo moveStopHere // odnosi się do stanu po połączeniu @@ -4280,13 +4211,12 @@ bool TController::UpdateSituation(double dt) TrainParams ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej if (VelDesired > 0.0) - if( ( ( SemNextIndex != -1 ) + if( ( ( iDrivigFlags & moveStopHere ) == 0 ) + || ( ( SemNextIndex != -1 ) && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) - && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) - || ( ( iDrivigFlags & moveStopHere ) == 0 ) ) - { // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w + && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) { + // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w // składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić - if (iDrivigFlags & moveGuardSignal) { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas // stania @@ -4304,21 +4234,20 @@ bool TController::UpdateSituation(double dt) // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić // obsługę kanałów radiowych itd. - if (!iGuardRadio) // jeśli nie przez radio - tsGuardSignal->Play( - 1.0, 0, !FreeFlyModeFlag, - pVehicle->GetPosition()); // dla true jest głośniej - else + if( !iGuardRadio ) { + // jeśli nie przez radio + tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej + } + else { // if (iGuardRadio==iRadioChannel) //zgodność kanału // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu // (albo może mieć radio przenośne) - kierownik mógłby powtarzać // przy braku reakcji - if (SquareMagnitude(pVehicle->GetPosition() - - Global::pCameraPosition) < - 2000 * 2000) // w odległości mniejszej niż 2km - tsGuardSignal->Play( - 1.0, 0, true, - pVehicle->GetPosition()); // dźwięk niby przez radio + if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { + // w odległości mniejszej niż 2km + tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio + } + } } } if (mvOccupied->V == 0.0) @@ -4389,7 +4318,7 @@ bool TController::UpdateSituation(double dt) { // AccDesired=0.0; AccDesired = 0.01; // proteza trochę: to } - else if (ActualProximityDist*25.92*fBrake_a0[0] > 2*vel*vel) + else if( (mvControlling->CategoryFlag == 1) && (ActualProximityDist*25.92*fBrake_a0[0] > 2*vel*vel)) { // jeśli ma stanąć, a mieści się w drodze hamowania AccDesired = AccPreferred; } @@ -4420,20 +4349,16 @@ bool TController::UpdateSituation(double dt) AccDesired = 0.0; } else // 25.92 (=3.6*3.6*2) - przelicznik z km/h na m/s - // niech nie hamuje, - // chyba że coś z - // przodu + // niech nie hamuje, chyba że coś z przodu AccDesired = -(vel * vel) / (25.92 * (ActualProximityDist + 0.1-0.5*(fMinProximityDist+fMaxProximityDist))); //-fMinProximityDist));//-0.1; - ////mniejsze opóźnienie przy - // małej różnicy + ////mniejsze opóźnienie przy małej różnicy ReactionTime = 0.1; // i orientuj się szybciej, jak masz stanąć } else if (vel < VelNext + fVelPlus) // jeśli niewielkie // przekroczenie, ale ma jechać - AccDesired = - Min0R(0.0, AccPreferred); // to olej (zacznij luzować) + AccDesired = std::min( 0.0, AccPreferred ); // to olej (zacznij luzować) else { // jeśli większe przekroczenie niż fVelPlus [km/h], ale ma jechać // Ra 2F1I: jak było (VelNext+fVelPlus) tu, to hamował zbyt @@ -4471,7 +4396,7 @@ bool TController::UpdateSituation(double dt) } else { // jest bliżej niż fMinProximityDist - VelDesired = std::min( VelDesired, VelNext ); // utrzymuj predkosc bo juz blisko + VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); // utrzymuj predkosc bo juz blisko if( vel < VelNext + fVelPlus ) { // jeśli niewielkie przekroczenie, ale ma jechać AccDesired = std::min( 0.0, AccPreferred ); // to olej (zacznij luzować) @@ -4487,10 +4412,19 @@ bool TController::UpdateSituation(double dt) } else { // jeśli daleko jechać nie można - if( ActualProximityDist > fMaxProximityDist ) { + if( ActualProximityDist > ( + mvOccupied->CategoryFlag & 2 ? + fMinProximityDist : // cars + fMaxProximityDist ) ) { // trains and others // ale ma kawałek do sygnalizatora - if( AccPreferred > 0 ) { AccDesired = AccPreferred; } // dociagnij do semafora; - else { VelDesired = 0.0; } //stoj + if( AccPreferred > 0.0 ) { + // dociagnij do semafora; + AccDesired = AccPreferred; + } + else { + //stoj + VelDesired = 0.0; + } } else { // VelNext=0 i stoi bliżej niż fMaxProximityDist @@ -4527,6 +4461,8 @@ bool TController::UpdateSituation(double dt) // koniec wybiegu i hamowania } #endif // DEBUGFAC + // last step sanity check, until the whole calculation is straightened out + AccDesired = std::min( AccDesired, AccPreferred ); if (AIControllFlag) { // część wykonawcza tylko dla AI, dla człowieka jedynie napisy @@ -4562,46 +4498,48 @@ bool TController::UpdateSituation(double dt) SetDriverPsyche(); } } - if (-AccDesired * BrakeAccFactor() < ((fReady > 0.4)||(VelNext>vel-40.0) ? fBrake_a0[0]*0.8 : -fAccThreshold)) - AccDesired = std::max(-0.06, AccDesired); - else - ReactionTime = 0.25; // i orientuj się szybciej, jeśli hamujesz + // NOTE: stop-gap measure, effect limited to trains only while car calculations seem off + if( mvControlling->CategoryFlag == 1 ) { + if( -AccDesired * BrakeAccFactor() < ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ? fBrake_a0[ 0 ] * 0.8 : -fAccThreshold ) ) + AccDesired = std::max( -0.06, AccDesired ); + else + ReactionTime = 0.25; // i orientuj się szybciej, jeśli hamujesz + } if (mvOccupied->BrakeSystem == Pneumatic) // napełnianie uderzeniowe if (mvOccupied->BrakeHandle == FV4a) { - if (mvOccupied->BrakeCtrlPos == -2) - mvOccupied->BrakeLevelSet(0); - // if - // ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->PipeBrakePress<0.01))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) - // mvOccupied->IncBrakeLevel(); - if ((mvOccupied->PipePress < 3.0) && (AccDesired > -0.03)) - mvOccupied->BrakeReleaser(1); - if ((mvOccupied->BrakeCtrlPos == 0) && (AbsAccS < 0.0) && - (AccDesired > -0.03)) - // if FuzzyLogicAI(CntrlPipePress-PipePress,0.01,1)) - // if - // ((mvOccupied->BrakePress>0.5)&&(mvOccupied->LocalBrakePos<0.5))//{((Volume/BrakeVVolume/10)<0.485)}) - if ((mvOccupied->EqvtPipePress < 4.95) && - (fReady > 0.35)) //{((Volume/BrakeVVolume/10)<0.485)}) - { - if (iDrivigFlags & - moveOerlikons) // a reszta składu jest na to gotowa - mvOccupied->BrakeLevelSet(-1); // napełnianie w Oerlikonie + if( mvOccupied->BrakeCtrlPos == -2 ) { + mvOccupied->BrakeLevelSet( 0 ); + } + if( ( mvOccupied->PipePress < 3.0 ) + && ( AccDesired > -0.03 ) ) { + mvOccupied->BrakeReleaser( 1 ); + } + if( ( mvOccupied->BrakeCtrlPos == 0 ) + && ( AbsAccS < 0.0 ) + && ( AccDesired > -0.03 ) ) { + + if( ( mvOccupied->EqvtPipePress < 4.95 ) + && ( fReady > 0.35 ) ) { // a reszta składu jest na to gotowa + + if( iDrivigFlags & moveOerlikons ) { + // napełnianie w Oerlikonie + mvOccupied->BrakeLevelSet( -1 ); + } } - else if (Need_BrakeRelease) - { + else if( Need_BrakeRelease ) { Need_BrakeRelease = false; - mvOccupied->BrakeReleaser(1); - // DecBrakeLevel(); //z tym by jeszcze miało jakiś sens + mvOccupied->BrakeReleaser( 1 ); } - // if - // ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->BrakePress<0.3))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) - if ((mvOccupied->BrakeCtrlPos < 0) && - (mvOccupied->EqvtPipePress > - (fReady < 0.25 ? - 5.1 : - 5.2))) //{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)}) - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); + } + + if( ( mvOccupied->BrakeCtrlPos < 0 ) + && ( mvOccupied->EqvtPipePress > ( + fReady < 0.25 ? + 5.1 : + 5.2 ) ) ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); + } } #if LOGVELOCITY WriteLog("Dist=" + FloatToStrF(ActualProximityDist, ffFixed, 7, 1) + @@ -4610,13 +4548,15 @@ bool TController::UpdateSituation(double dt) ", VelSignal=" + AnsiString(VelSignal) + ", VelNext=" + AnsiString(VelNext)); #endif - if (AccDesired > 0.1) - if (vel < 10.0) // Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, - // to nie ograniczać przyspieszenia do 0.5m/ss - AccDesired = 0.9; // przy małych prędkościach może być trudno utrzymać + if( ( vel < 10.0 ) + && ( AccDesired > 0.1 ) ) { + // Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, + // to nie ograniczać przyspieszenia do 0.5m/ss + // przy małych prędkościach może być trudno utrzymać + AccDesired = std::max( 0.9, AccDesired ); + } // małe przyspieszenie - // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu - // migocze + // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze if (AccDesired > -0.15) // hamowania lepeiej nie uśredniać AccDesired = fAccDesiredAv = 0.2 * AccDesired + @@ -4675,79 +4615,58 @@ bool TController::UpdateSituation(double dt) // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz if( vel < VelDesired - fVelMinus ) { // jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines - if( ( ActualProximityDist > fMaxProximityDist ? - true : - vel < VelNext ) ) { + if( ( ActualProximityDist > ( + mvOccupied->CategoryFlag & 2 ? + fMinProximityDist : // cars are allowed to move within min proximity distance + fMaxProximityDist ) ? // other vehicle types keep wider margin + true : + vel < VelNext ) ) { // to można przyspieszyć IncSpeed(); } } } - // if ((AbsAccS0) and - // (EngineType=ElectricSeriesMotor) - // and (RList[MainCtrlPos].R>0.0) and (not DelayCtrlFlag)) - // if (ImTrainType & - dt_EZT) // właściwie, to warunek powinien być na działający EP - { // Ra: to dobrze hamuje EP w EZT - if ((AccDesired <= fAccThreshold) ? // jeśli hamować - u góry ustawia się - // hamowanie na fAccThreshold - ((AbsAccS > AccDesired) || (mvOccupied->BrakeCtrlPos < 0)) : - false) // hamować bardziej, gdy aktualne opóźnienie hamowania - // mniejsze niż (AccDesired) + if( mvOccupied->TrainType & dt_EZT ) { + // właściwie, to warunek powinien być na działający EP + // Ra: to dobrze hamuje EP w EZT + if( ( AccDesired <= fAccThreshold ) // jeśli hamować - u góry ustawia się hamowanie na fAccThreshold + && ( ( AbsAccS > AccDesired ) + || ( mvOccupied->BrakeCtrlPos < 0 ) ) ) { + // hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired) IncBrake(); - else if (OrderList[OrderPos] != - Disconnect) // przy odłączaniu nie zwalniamy tu hamulca - if (AbsAccS < - AccDesired - - 0.05) // jeśli opóźnienie większe od wymaganego (z histerezą) - { // luzowanie, gdy za dużo - if (mvOccupied->BrakeCtrlPos >= 0) + } + else if( OrderList[ OrderPos ] != Disconnect ) { + // przy odłączaniu nie zwalniamy tu hamulca + if( AbsAccS < AccDesired - 0.05 ) { + // jeśli opóźnienie większe od wymaganego (z histerezą) luzowanie, gdy za dużo + if( mvOccupied->BrakeCtrlPos >= 0 ) { DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu + } } - else if (mvOccupied->Handle->TimeEP) - { - if (mvOccupied->Handle->GetPos(bh_EPR) - - mvOccupied->Handle->GetPos(bh_EPN) < - 0.1) - mvOccupied->SwitchEPBrake(0); - else - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPN)); - } - // else if (mvOccupied->BrakeCtrlPos<0) IncBrake(); //ustawienie - // jazdy (pozycja 0) - // else if (mvOccupied->BrakeCtrlPos>0) DecBrake(); - } - else - { // a stara wersja w miarę dobrze działa na składy wagonowe - // if (mvOccupied->Handle->Time) - // mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_MB)); - // //najwyzej sobie przestawi - if (((fAccGravity < -0.05) && (vel < 0)) || - ((AccDesired < fAccGravity - 0.1) && - (AbsAccS > - AccDesired + fBrake_a1[0]))) // u góry ustawia się hamowanie na fAccThreshold - // if not MinVelFlag) - if (fBrakeTime < 0 ? true : (AccDesired < fAccGravity - 0.3) || - (mvOccupied->BrakeCtrlPos <= 0)) - if( false == IncBrake() ) { - // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował - MinVelFlag = true; + else if( mvOccupied->Handle->TimeEP ) { + if( mvOccupied->Handle->GetPos( bh_EPR ) - + mvOccupied->Handle->GetPos( bh_EPN ) < + 0.1 ) { + mvOccupied->SwitchEPBrake( 0 ); } else { - MinVelFlag = false; + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPN ) ); + } + } + } // order != disconnect + } // type & dt_ezt + else { + // a stara wersja w miarę dobrze działa na składy wagonowe + if( ( ( fAccGravity < -0.05 ) && ( vel < 0.0 ) ) + || ( ( AccDesired < fAccGravity - 0.1 ) && ( AbsAccS > AccDesired + fBrake_a1[ 0 ] ) ) ) { + // u góry ustawia się hamowanie na fAccThreshold + if( ( fBrakeTime < 0.0 ) + || ( AccDesired < fAccGravity - 0.3 ) + || ( mvOccupied->BrakeCtrlPos <= 0 ) ) { + // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował + if( true == IncBrake() ) { fBrakeTime = 3.0 + 0.5 * ( ( @@ -4758,11 +4677,10 @@ bool TController::UpdateSituation(double dt) // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 } - if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - fBrake_a1[0]*0.51)) - // if ((AccDesired<0.0)&&(AbsAccSBrakeDelayFlag > bdelay_G ? - mvOccupied->BrakeDelay[ 0 ] : - mvOccupied->BrakeDelay[ 2 ] ) + mvOccupied->BrakeDelay[ 0 ] : + mvOccupied->BrakeDelay[ 2 ] ) / 3.0; fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 } + // stop-gap measure to ensure cars actually brake to stop even when above calculactions go awry + // instead of releasing the brakes and creeping into obstacle at 1-2 km/h + if( mvControlling->CategoryFlag == 2 ) { + if( ( VelDesired == 0.0 ) + && ( vel > VelDesired ) + && ( ActualProximityDist <= fMinProximityDist ) + && ( mvOccupied->LocalBrakePos == 0 ) ) { + IncBrake(); + } + } } // Mietek-end1 SpeedSet(); // ciągla regulacja prędkości @@ -4782,33 +4710,22 @@ bool TController::UpdateSituation(double dt) WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" + AnsiString(mvControlling->MainCtrlPos)); #endif - - /* //Ra: mamy teraz wskażnik na człon silnikowy, gorzej jak są dwa w - ukrotnieniu... - //zapobieganie poslizgowi w czlonie silnikowym; Ra: Couplers[1] powinno - być - if (Controlling->Couplers[0].Connected!=NULL) - if (TestFlag(Controlling->Couplers[0].CouplingFlag,ctrain_controll)) - if (Controlling->Couplers[0].Connected->SlippingWheels) - if (Controlling->ScndCtrlPos>0?!Controlling->DecScndCtrl(1):true) - { - if (!Controlling->DecMainCtrl(1)) - if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo) - mvOccupied->DecBrakeLevel(); - ++iDriverFailCount; - } - */ // zapobieganie poslizgowi u nas if (mvControlling->SlippingWheels) { if (!mvControlling->DecScndCtrl(2)) // bocznik na zero mvControlling->DecMainCtrl(1); +/* if (mvOccupied->BrakeCtrlPos == mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania //yB: ten warunek wyżej nie ma sensu mvOccupied->DecBrakeLevel(); // to cofnij hamulec + DecBrake(); // to cofnij hamulec else mvControlling->AntiSlippingButton(); +*/ + DecBrake(); // to cofnij hamulec + mvControlling->AntiSlippingButton(); ++iDriverFailCount; mvControlling->SlippingWheels = false; // flaga już wykorzystana } @@ -4819,10 +4736,6 @@ bool TController::UpdateSituation(double dt) SetDriverPsyche(); } } // if (AIControllFlag) - else - { // tu mozna dać komunikaty tekstowe albo słowne: przyspiesz, hamuj (lekko, - // średnio, mocno) - } } // kierunek różny od zera else { // tutaj, gdy pojazd jest wyłączony diff --git a/Driver.h b/Driver.h index b2efddcc..68d44633 100644 --- a/Driver.h +++ b/Driver.h @@ -144,7 +144,7 @@ class TSpeedPos public: void Clear(); - bool Update(vector3 *p, vector3 *dir, double &len); + bool Update(vector3 *p, vector3 *dir, double &len, TOrders const &Orders ); bool Set(TEvent *e, double d, TOrders order = Wait_for_orders); void Set(TTrack *t, double d, int f); std::string TableText(); @@ -195,8 +195,8 @@ class TController 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 public: + double fBrakeDist = 0.0; // przybliżona droga hamowania double BrakeAccFactor(); double fBrakeReaction = 1.0; //opóźnienie zadziałania hamulca - czas w s / (km/h) double fAccThreshold = 0.0; // próg opóźnienia dla zadziałania hamulca @@ -270,8 +270,6 @@ class TController OrderTop = 0; // rozkaz aktualny oraz wolne miejsce do wstawiania nowych std::ofstream LogFile; // zapis parametrow fizycznych std::ofstream AILogFile; // log AI - bool MaxVelFlag = false; - bool MinVelFlag = false; // Ra: to nie jest używane 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) diff --git a/DynObj.cpp b/DynObj.cpp index 2a39c768..67ce1097 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1126,128 +1126,96 @@ void TDynamicObject::ABuCheckMyTrack() } // Ra: w poniższej funkcji jest problem ze sprzęgami -TDynamicObject * TDynamicObject::ABuFindObject(TTrack *Track, int ScanDir, - BYTE &CouplFound, double &dist) +TDynamicObject * +TDynamicObject::ABuFindObject( int &Foundcoupler, double &Distance, TTrack *Track, int const Direction, int const Mycoupler ) { // Zwraca wskaźnik najbliższego obiektu znajdującego się // na torze w określonym kierunku, ale tylko wtedy, kiedy // obiekty mogą się zderzyć, tzn. nie mijają się. + // WE: + // Track - tor, na ktorym odbywa sie poszukiwanie, + // Direction - kierunek szukania na torze (+1:w stronę Point2, -1:w stronę Point1) + // Mycoupler - nr sprzegu obiektu szukajacego; + // WY: + // wskaznik do znalezionego obiektu. + // Foundcoupler - nr sprzegu znalezionego obiektu + // Distance - distance to found object - // WE: Track - tor, na ktorym odbywa sie poszukiwanie, - // MyPointer - wskaznik do obiektu szukajacego. //Ra: zamieniłem na "this" - // ScanDir - kierunek szukania na torze (+1:w stronę Point2, -1:w stronę - // Point1) - // MyScanDir - kierunek szukania obiektu szukajacego (na jego torze); Ra: - // nie potrzebne - // MyCouplFound - nr sprzegu obiektu szukajacego; Ra: nie potrzebne - - // WY: wskaznik do znalezionego obiektu. - // CouplFound - nr sprzegu znalezionego obiektu - if( false == Track->Dynamics.empty() ) - { // sens szukania na tym torze jest tylko, gdy są na nim pojazdy - double MyTranslation; // pozycja szukającego na torze - double MinDist = Track->Length(); // najmniejsza znaleziona odleglość - // (zaczynamy od długości toru) - double TestDist; // robocza odległość od kolejnych pojazdów na danym odcinku - TDynamicObject *collider = nullptr; - // if (Track->iNumDynamics>1) - // iMinDist+=0; //tymczasowo pułapka - if (MyTrack == Track) // gdy szukanie na tym samym torze - MyTranslation = RaTranslationGet(); // położenie wózka względem Point1 toru - else // gdy szukanie na innym torze - if (ScanDir > 0) - MyTranslation = 0; // szukanie w kierunku Point2 (od zera) - jesteśmy w Point1 - else - MyTranslation = MinDist; // szukanie w kierunku Point1 (do zera) - jesteśmy w Point2 - if (ScanDir >= 0) - { // jeśli szukanie w kierunku Point2 - for( auto dynamic : Track->Dynamics ) { - // pętla po pojazdach - if( dynamic == this ) { - // szukający się nie liczy - continue; - } - - TestDist = ( dynamic->RaTranslationGet() ) - MyTranslation; // odległogłość tamtego od szukającego - if( ( TestDist > 0 ) && ( TestDist <= MinDist ) ) { // gdy jest po właściwej stronie i bliżej - // niż jakiś wcześniejszy - CouplFound = ( dynamic->RaDirectionGet() > 0 ) ? 1 : 0; // to, bo (ScanDir>=0) - if( Track->iCategoryFlag & 254 ) { - // trajektoria innego typu niż tor kolejowy - // dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija - // Ra: mijanie samochodów wcale nie jest proste - // Przesuniecie wzgledne pojazdow. Wyznaczane, zeby sprawdzic, - // czy pojazdy faktycznie sie zderzaja (moga byc przesuniete - // w/m siebie tak, ze nie zachodza na siebie i wtedy sie mijaja). - double RelOffsetH; // wzajemna odległość poprzeczna - if( CouplFound ) { - // my na tym torze byśmy byli w kierunku Point2 - // dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć - RelOffsetH = ( MoverParameters->OffsetTrackH - dynamic->MoverParameters->OffsetTrackH ); - } - else { - // dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się - RelOffsetH = ( MoverParameters->OffsetTrackH + dynamic->MoverParameters->OffsetTrackH ); - } - if( RelOffsetH < 0 ) { - RelOffsetH = -RelOffsetH; - } - if( RelOffsetH + RelOffsetH > MoverParameters->Dim.W + dynamic->MoverParameters->Dim.W ) { - // odległość większa od połowy sumy szerokości - kolizji nie będzie - continue; - } - // jeśli zahaczenie jest niewielkie, a jest miejsce na poboczu, to - // zjechać na pobocze - } - collider = dynamic; // potencjalna kolizja - MinDist = TestDist; // odleglość pomiędzy aktywnymi osiami pojazdów - } - - } - } - else //(ScanDir<0) - { - for( auto dynamic : Track->Dynamics ) { - - if( dynamic == this ) { continue; } - - TestDist = MyTranslation - ( dynamic->RaTranslationGet() ); //???-przesunięcie wózka względem Point1 toru - if( ( TestDist > 0 ) && ( TestDist < MinDist ) ) { - CouplFound = ( dynamic->RaDirectionGet() > 0 ) ? 0 : 1; // odwrotnie, bo (ScanDir<0) - if( Track->iCategoryFlag & 254 ) // trajektoria innego typu niż tor kolejowy - { // dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija - // Ra: mijanie samochodów wcale nie jest proste - // Przesunięcie względne pojazdów. Wyznaczane, żeby sprawdzić, - // czy pojazdy faktycznie się zderzają (mogą być przesunięte - // w/m siebie tak, że nie zachodzą na siebie i wtedy sie mijają). - double RelOffsetH; // wzajemna odległość poprzeczna - if( CouplFound ) { - // my na tym torze byśmy byli w kierunku Point1 - // dla CouplFound=1 są zwroty zgodne - istotna różnica przesunięć - RelOffsetH = ( MoverParameters->OffsetTrackH - dynamic->MoverParameters->OffsetTrackH ); - } - else { - // dla CouplFound=0 są zwroty przeciwne - przesunięcia sumują się - RelOffsetH = ( MoverParameters->OffsetTrackH + dynamic->MoverParameters->OffsetTrackH ); - } - if( RelOffsetH < 0 ) { - RelOffsetH = -RelOffsetH; - } - if( RelOffsetH + RelOffsetH > MoverParameters->Dim.W + dynamic->MoverParameters->Dim.W ) { - // odległość większa od połowy sumy szerokości - kolizji nie będzie - continue; - } - } - collider = dynamic; // potencjalna kolizja - MinDist = TestDist; // odleglość pomiędzy aktywnymi osiami pojazdów - } - } - } - dist += MinDist; // doliczenie odległości przeszkody albo długości odcinka do przeskanowanej odległości - return collider; + if( true == Track->Dynamics.empty() ) { + // sens szukania na tym torze jest tylko, gdy są na nim pojazdy + Distance += Track->Length(); // doliczenie długości odcinka do przeskanowanej odległości + return nullptr; // nie ma pojazdów na torze, to jest NULL } - dist += Track->Length(); // doliczenie długości odcinka do przeskanowanej - // odległości - return nullptr; // nie ma pojazdów na torze, to jest NULL + + double distance = Track->Length(); // najmniejsza znaleziona odleglość (zaczynamy od długości toru) + double myposition; // pozycja szukającego na torze + TDynamicObject *foundobject = nullptr; + if( MyTrack == Track ) { + // gdy szukanie na tym samym torze + myposition = RaTranslationGet(); // położenie wózka względem Point1 toru + } + else { + // gdy szukanie na innym torze + if( Direction > 0 ) { + // szukanie w kierunku Point2 (od zera) - jesteśmy w Point1 + myposition = 0; + } + else { + // szukanie w kierunku Point1 (do zera) - jesteśmy w Point2 + myposition = distance; + } + } + + double objectposition; // robocza odległość od kolejnych pojazdów na danym odcinku + for( auto dynamic : Track->Dynamics ) { + + if( dynamic == this ) { continue; } // szukający się nie liczy + + if( Direction > 0 ) { + // jeśli szukanie w kierunku Point2 + objectposition = ( dynamic->RaTranslationGet() ) - myposition; // odległogłość tamtego od szukającego + if( ( objectposition > 0 ) + && ( objectposition < distance ) ) { + // gdy jest po właściwej stronie i bliżej niż jakiś wcześniejszy + Foundcoupler = ( dynamic->RaDirectionGet() > 0 ) ? 1 : 0; // to, bo (ScanDir>=0) + } + else { continue; } + } + else { + objectposition = myposition - ( dynamic->RaTranslationGet() ); //???-przesunięcie wózka względem Point1 toru + if( ( objectposition > 0 ) + && ( objectposition < distance ) ) { + Foundcoupler = ( dynamic->RaDirectionGet() > 0 ) ? 0 : 1; // odwrotnie, bo (ScanDir<0) + } + else { continue; } + } + + if( Track->iCategoryFlag & 254 ) { + // trajektoria innego typu niż tor kolejowy + // dla torów nie ma sensu tego sprawdzać, rzadko co jedzie po jednej szynie i się mija + // Ra: mijanie samochodów wcale nie jest proste + // Przesuniecie wzgledne pojazdow. Wyznaczane, zeby sprawdzic, + // czy pojazdy faktycznie sie zderzaja (moga byc przesuniete + // w/m siebie tak, ze nie zachodza na siebie i wtedy sie mijaja). + double relativeoffset; // wzajemna odległość poprzeczna + if( Foundcoupler != Mycoupler ) { + // facing the same direction + relativeoffset = std::abs( MoverParameters->OffsetTrackH - dynamic->MoverParameters->OffsetTrackH ); + } + else { + relativeoffset = std::abs( MoverParameters->OffsetTrackH + dynamic->MoverParameters->OffsetTrackH ); + } + if( relativeoffset + relativeoffset > MoverParameters->Dim.W + dynamic->MoverParameters->Dim.W ) { + // odległość większa od połowy sumy szerokości - kolizji nie będzie + continue; + } + // jeśli zahaczenie jest niewielkie, a jest miejsce na poboczu, to zjechać na pobocze + } + foundobject = dynamic; // potencjalna kolizja + distance = objectposition; // odleglość pomiędzy aktywnymi osiami pojazdów + } + + Distance += distance; // doliczenie odległości przeszkody albo długości odcinka do przeskanowanej odległości + return foundobject; } int TDynamicObject::DettachStatus(int dir) @@ -1294,9 +1262,9 @@ void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) { if (PrevConnected) // pojazd od strony sprzęgu 0 { - if (MoverParameters->Couplers[0].CoupleDist > - MinDist) // sprzęgi wirtualne zawsze przekraczają - { + if (MoverParameters->Couplers[0].CoupleDist > MinDist) { + // sprzęgi wirtualne zawsze przekraczają + if ((PrevConnectedNo ? PrevConnected->NextConnected : PrevConnected->PrevConnected) == this) { // Ra: nie rozłączamy znalezionego, jeżeli nie do nas @@ -1314,10 +1282,11 @@ void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) PrevConnected->NextConnected = NULL; } } + // za to zawsze odłączamy siebie PrevConnected = NULL; PrevConnectedNo = 2; // sprzęg 0 nie podłączony - MoverParameters->Couplers[0].Connected = NULL; + MoverParameters->Couplers[0].Connected = nullptr; } } } @@ -1325,9 +1294,9 @@ void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) { if (NextConnected) // pojazd od strony sprzęgu 1 { - if (MoverParameters->Couplers[1].CoupleDist > - MinDist) // sprzęgi wirtualne zawsze przekraczają - { + if (MoverParameters->Couplers[1].CoupleDist > MinDist) { + // sprzęgi wirtualne zawsze przekraczają + if ((NextConnectedNo ? NextConnected->NextConnected : NextConnected->PrevConnected) == this) { // Ra: nie rozłączamy znalezionego, jeżeli nie do nas @@ -1345,180 +1314,147 @@ void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) NextConnected->NextConnected = NULL; } } + NextConnected = NULL; NextConnectedNo = 2; // sprzęg 1 nie podłączony - MoverParameters->Couplers[1].Connected = NULL; + MoverParameters->Couplers[1].Connected = nullptr; } } } } -void TDynamicObject::ABuScanObjects(int ScanDir, double ScanDist) +void TDynamicObject::ABuScanObjects( int Direction, double Distance ) { // skanowanie toru w poszukiwaniu kolidujących pojazdów // ScanDir - określa kierunek poszukiwania zależnie od zwrotu prędkości // pojazdu // ScanDir=1 - od strony Coupler0, ScanDir=-1 - od strony Coupler1 - int MyScanDir = ScanDir; // zapamiętanie kierunku poszukiwań na torze - // początkowym, względem sprzęgów - TTrackFollower *FirstAxle = (MyScanDir > 0 ? &Axle0 : &Axle1); // można by to trzymać w trainset - TTrack *Track = FirstAxle->GetTrack(); // tor na którym "stoi" skrajny wózek + int initialdirection = Direction; // zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów + TTrackFollower *firstaxle = (initialdirection > 0 ? &Axle0 : &Axle1); // można by to trzymać w trainset + TTrack *track = firstaxle->GetTrack(); // tor na którym "stoi" skrajny wózek // (może być inny niż tor pojazdu) - if (FirstAxle->GetDirection() < 0) // czy oś jest ustawiona w stronę Point1? - ScanDir = -ScanDir; // jeśli tak, to kierunek szukania będzie przeciwny + if( firstaxle->GetDirection() < 0 ) { + // czy oś jest ustawiona w stronę Point1? + Direction = -Direction; // jeśli tak, to kierunek szukania będzie przeciwny + } // (teraz względem // toru) - BYTE MyCouplFound; // numer sprzęgu do podłączenia w obiekcie szukajacym - MyCouplFound = (MyScanDir < 0) ? 1 : 0; - BYTE CouplFound; // numer sprzęgu w znalezionym obiekcie (znaleziony wypełni) - TDynamicObject *FoundedObj; // znaleziony obiekt - double ActDist = 0; // przeskanowana odleglość; odległość do zawalidrogi - FoundedObj = ABuFindObject(Track, ScanDir, CouplFound, - ActDist); // zaczynamy szukać na tym samym torze + int const mycoupler = ( initialdirection < 0 ? 1 : 0 ); // numer sprzęgu do podłączenia w obiekcie szukajacym + int foundcoupler { -1 }; // numer sprzęgu w znalezionym obiekcie (znaleziony wypełni) + double distance = 0; // przeskanowana odleglość; odległość do zawalidrogi + TDynamicObject *foundobject = ABuFindObject( foundcoupler, distance, track, Direction, mycoupler ); // zaczynamy szukać na tym samym torze - /* - if (FoundedObj) //jak coś znajdzie, to śledzimy - {//powtórzenie wyszukiwania tylko do zastawiania pułepek podczas testów - if (ABuGetDirection()<0) ScanDir=ScanDir; //ustalenie kierunku względem toru - FoundedObj=ABuFindObject(Track,this,ScanDir,CouplFound); - } - */ - - if (DebugModeFlag) - if (FoundedObj) // kod służący do logowania błędów - if (CouplFound == 0) - { - if (FoundedObj->PrevConnected) - if (FoundedObj->PrevConnected != this) // odświeżenie tego samego się nie liczy - WriteLog("0! Coupler warning on " + asName + ":" + - to_string(MyCouplFound) + " - " + FoundedObj->asName + - ":0 connected to " + FoundedObj->PrevConnected->asName + ":" + - to_string(FoundedObj->PrevConnectedNo)); - } - else - { - if (FoundedObj->NextConnected) - if (FoundedObj->NextConnected != this) // odświeżenie tego samego się nie liczy - WriteLog("0! Coupler warning on " + asName + ":" + - to_string(MyCouplFound) + " - " + FoundedObj->asName + - ":1 connected to " + FoundedObj->NextConnected->asName + ":" + - to_string(FoundedObj->NextConnectedNo)); - } - - if (FoundedObj == NULL) // jeśli nie ma na tym samym, szukamy po okolicy - { // szukanie najblizszego toru z jakims obiektem + if( foundobject == nullptr ) { + // jeśli nie ma na tym samym, szukamy po okolicy szukanie najblizszego toru z jakims obiektem // praktycznie przeklejone z TraceRoute()... - // double CurrDist=0; //aktualna dlugosc toru - if (ScanDir >= 0) // uwzględniamy kawalek przeanalizowanego wcześniej toru - ActDist = Track->Length() - FirstAxle->GetTranslation(); // odległość osi od Point2 toru + if (Direction >= 0) // uwzględniamy kawalek przeanalizowanego wcześniej toru + distance = track->Length() - firstaxle->GetTranslation(); // odległość osi od Point2 toru else - ActDist = FirstAxle->GetTranslation(); // odległość osi od Point1 toru - while (ActDist < ScanDist) - { - // ActDist+=CurrDist; //odległość już przeanalizowana - if (ScanDir > 0) // w kierunku Point2 toru - { - if (Track ? Track->iNextDirection : - false) // jeśli następny tor jest podpięty od Point2 - ScanDir = -ScanDir; // to zmieniamy kierunek szukania na tym torze - Track = Track->CurrentNext(); // potem dopiero zmieniamy wskaźnik + distance = firstaxle->GetTranslation(); // odległość osi od Point1 toru + + while (distance < Distance) { + if (Direction > 0) { + // w kierunku Point2 toru + if( track ? + track->iNextDirection : + false ) { + // jeśli następny tor jest podpięty od Point2 + Direction = -Direction; // to zmieniamy kierunek szukania na tym torze + } + track = track->CurrentNext(); // potem dopiero zmieniamy wskaźnik } - else // w kierunku Point1 - { - if (Track ? !Track->iPrevDirection : - true) // jeśli poprzedni tor nie jest podpięty od Point2 - ScanDir = -ScanDir; // to zmieniamy kierunek szukania na tym torze - Track = Track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik + else { + // w kierunku Point1 + if( track ? + !track->iPrevDirection : + true ) { + // jeśli poprzedni tor nie jest podpięty od Point2 + Direction = -Direction; // to zmieniamy kierunek szukania na tym torze + } + track = track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik } - if (Track) - { // jesli jest kolejny odcinek toru - // CurrDist=Track->Length(); //doliczenie tego toru do przejrzanego - // dystandu - FoundedObj = ABuFindObject(Track, ScanDir, CouplFound, - ActDist); // przejrzenie pojazdów tego toru - if (FoundedObj) - { - // ActDist=ScanDist; //wyjście z pętli poszukiwania + if (track) { + // jesli jest kolejny odcinek toru + foundobject = ABuFindObject(foundcoupler, distance, track, Direction, mycoupler); // przejrzenie pojazdów tego toru + if (foundobject) { break; } } - else // jeśli toru nie ma, to wychodzimy - { - ActDist = ScanDist + 1.0; // koniec przeglądania torów + else { + // jeśli toru nie ma, to wychodzimy + distance = Distance + 1.0; // koniec przeglądania torów break; } } } // Koniec szukania najbliższego toru z jakimś obiektem. + // teraz odczepianie i jeśli coś się znalazło, doczepianie. - if (MyScanDir > 0 ? PrevConnected : NextConnected) - if ((MyScanDir > 0 ? PrevConnected : NextConnected) != FoundedObj) - CouplersDettach(1.0, MyScanDir); // odłączamy, jeśli dalej niż metr - // i łączenie sprzęgiem wirtualnym - if (FoundedObj) - { // siebie można bezpiecznie podłączyć jednostronnie do - // znalezionego - MoverParameters->Attach(MyCouplFound, CouplFound, FoundedObj->MoverParameters, - ctrain_virtual); - // MoverParameters->Couplers[MyCouplFound].Render=false; //wirtualnego nie - // renderujemy - if (MyCouplFound == 0) - { - PrevConnected = FoundedObj; // pojazd od strony sprzęgu 0 - PrevConnectedNo = CouplFound; + auto connectedobject = ( + initialdirection > 0 ? + PrevConnected : + NextConnected ); + if( ( connectedobject != nullptr ) + && ( connectedobject != foundobject ) ) { + // odłączamy, jeśli dalej niż metr i łączenie sprzęgiem wirtualnym + CouplersDettach( 1.0, initialdirection ); + } + + if (foundobject) { + // siebie można bezpiecznie podłączyć jednostronnie do znalezionego + MoverParameters->Attach( mycoupler, foundcoupler, foundobject->MoverParameters, coupling::faux ); + // MoverParameters->Couplers[MyCouplFound].Render=false; //wirtualnego nie renderujemy + if( mycoupler == TMoverParameters::side::front ) { + PrevConnected = foundobject; // pojazd od strony sprzęgu 0 + PrevConnectedNo = foundcoupler; } - else - { - NextConnected = FoundedObj; // pojazd od strony sprzęgu 1 - NextConnectedNo = CouplFound; + else { + NextConnected = foundobject; // pojazd od strony sprzęgu 1 + NextConnectedNo = foundcoupler; } - if (FoundedObj->MoverParameters->Couplers[CouplFound].CouplingFlag == ctrain_virtual) - { // Ra: wpinamy się wirtualnym tylko jeśli znaleziony - // ma wirtualny sprzęg - FoundedObj->MoverParameters->Attach(CouplFound, MyCouplFound, this->MoverParameters, - ctrain_virtual); - if (CouplFound == 0) // jeśli widoczny sprzęg 0 znalezionego - { - if (DebugModeFlag) - if (FoundedObj->PrevConnected) - if (FoundedObj->PrevConnected != this) - WriteLog("1! Coupler warning on " + asName + ":" + - to_string(MyCouplFound) + " - " + FoundedObj->asName + - ":0 connected to " + FoundedObj->PrevConnected->asName + ":" + - to_string(FoundedObj->PrevConnectedNo)); - FoundedObj->PrevConnected = this; - FoundedObj->PrevConnectedNo = MyCouplFound; + + if( foundobject->MoverParameters->Couplers[ foundcoupler ].CouplingFlag == coupling::faux ) { + // Ra: wpinamy się wirtualnym tylko jeśli znaleziony ma wirtualny sprzęg + foundobject->MoverParameters->Attach( foundcoupler, mycoupler, this->MoverParameters, coupling::faux ); + + if( foundcoupler == TMoverParameters::side::front ) { + // jeśli widoczny sprzęg 0 znalezionego + if( ( DebugModeFlag ) + && ( foundobject->PrevConnected ) + && ( foundobject->PrevConnected != this ) ) { + WriteLog( "ScanObjects(): formed virtual link between \"" + asName + "\" (coupler " + to_string( mycoupler ) + ") and \"" + foundobject->asName + "\" (coupler " + to_string( foundcoupler ) + ")" ); + } + foundobject->PrevConnected = this; + foundobject->PrevConnectedNo = mycoupler; } - else // jeśli widoczny sprzęg 1 znalezionego - { - if (DebugModeFlag) - if (FoundedObj->NextConnected) - if (FoundedObj->NextConnected != this) - WriteLog("1! Coupler warning on " + asName + ":" + - to_string(MyCouplFound) + " - " + FoundedObj->asName + - ":1 connected to " + FoundedObj->NextConnected->asName + ":" + - to_string(FoundedObj->NextConnectedNo)); - FoundedObj->NextConnected = this; - FoundedObj->NextConnectedNo = MyCouplFound; + else { + // jeśli widoczny sprzęg 1 znalezionego + if( ( DebugModeFlag ) + && ( foundobject->NextConnected ) + && ( foundobject->NextConnected != this ) ) { + WriteLog( "ScanObjects(): formed virtual link between \"" + asName + "\" (coupler " + to_string( mycoupler ) + ") and \"" + foundobject->asName + "\" (coupler " + to_string( foundcoupler ) + ")" ); + } + foundobject->NextConnected = this; + foundobject->NextConnectedNo = mycoupler; } } - // Ra: jeśli dwa samochody się mijają na odcinku przed zawrotką, to - // odległość między nimi - // nie może być liczona w linii prostej! - fTrackBlock = MoverParameters->Couplers[MyCouplFound] - .CoupleDist; // odległość do najbliższego pojazdu w linii prostej - if (Track->iCategoryFlag > 1) // jeśli samochód - if (ActDist > MoverParameters->Dim.L + - FoundedObj->MoverParameters->Dim - .L) // przeskanowana odległość większa od długości pojazdów + + // odległość do najbliższego pojazdu w linii prostej + // Ra: jeśli dwa samochody się mijają na odcinku przed zawrotką, to odległość między nimi nie może być liczona w linii prostej! + fTrackBlock = MoverParameters->Couplers[mycoupler].CoupleDist; + if( track->iCategoryFlag & 254 ) { + // jeśli samochód + if( distance > MoverParameters->Dim.L + foundobject->MoverParameters->Dim.L ) { + // przeskanowana odległość większa od długości pojazdów // else if (ActDistasName); + fTrackBlock = distance; // ta odległość jest wiecej warta + } + } } - else // nic nie znalezione, to nie ma przeszkód + else { + // nic nie znalezione, to nie ma przeszkód fTrackBlock = 10000.0; + } } //----------ABu: koniec skanowania pojazdow @@ -1540,7 +1476,6 @@ TDynamicObject::TDynamicObject() bBrakeAcc = false; NextConnected = PrevConnected = NULL; NextConnectedNo = PrevConnectedNo = 2; // ABu: Numery sprzegow. 2=nie podłączony - CouplCounter = 50; // będzie sprawdzać na początku asName = ""; bEnabled = true; MyTrack = NULL; @@ -1880,14 +1815,20 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" if (MoverParameters->CategoryFlag & 2) // jeśli samochód { // ustawianie samochodow na poboczu albo na środku drogi - if (Track->fTrackWidth < 3.5) // jeśli droga wąska + if( Track->fTrackWidth < 3.5 ) // jeśli droga wąska MoverParameters->OffsetTrackH = 0.0; // to stawiamy na środku, niezależnie od stanu // ruchu - else if (driveractive) // od 3.5m do 8.0m jedzie po środku pasa, dla + else if( driveractive ) {// od 3.5m do 8.0m jedzie po środku pasa, dla // szerszych w odległości // 1.5m - MoverParameters->OffsetTrackH = - Track->fTrackWidth <= 8.0 ? -Track->fTrackWidth * 0.25 : -1.5; + auto const lanefreespace = 0.5 * Track->fTrackWidth - MoverParameters->Dim.W; + MoverParameters->OffsetTrackH = ( + lanefreespace > 1.5 ? + -0.5 * MoverParameters->Dim.W - 0.75 : // wide road, keep near centre with safe margin + ( lanefreespace > 0.1 ? + -0.25 * Track->fTrackWidth : // narrow fit, stay on the middle + -0.5 * MoverParameters->Dim.W - 0.075 ) ); // too narrow, just keep some minimal clearance + } else // jak stoi, to kołem na poboczu i pobieramy szerokość razem z // poboczem, ale nie z // chodnikiem @@ -3471,45 +3412,6 @@ bool TDynamicObject::Update(double dt, double dt1) toggle_lights(); } - // ABu-160303 sledzenie toru przed obiektem: ******************************* - // Z obserwacji: v>0 -> Coupler 0; v<0 ->coupler1 (Ra: prędkość jest związana - // z pojazdem) - // Rozroznienie jest tutaj, zeby niepotrzebnie nie skakac do funkcji. Nie jest - // uzaleznione - // od obecnosci AI, zeby uwzglednic np. jadace bez lokomotywy wagony. - // Ra: można by przenieść na poziom obiektu reprezentującego skład, aby nie - // sprawdzać środkowych - if (CouplCounter > 25) // licznik, aby nie robić za każdym razem - { // poszukiwanie czegoś do zderzenia się - fTrackBlock = 10000.0; // na razie nie ma przeszkód (na wypadek nie - // uruchomienia skanowania) - // jeśli nie ma zwrotnicy po drodze, to tylko przeliczyć odległość? - if (MoverParameters->V > 0.03) //[m/s] jeśli jedzie do przodu (w kierunku Coupler 0) - { - if (MoverParameters->Couplers[0].CouplingFlag == - ctrain_virtual) // brak pojazdu podpiętego? - { - ABuScanObjects(1, fScanDist); // szukanie czegoś do podłączenia - // WriteLog(asName+" - block 0: "+AnsiString(fTrackBlock)); - } - } - else if (MoverParameters->V < -0.03) //[m/s] jeśli jedzie do tyłu (w kierunku Coupler 1) - if (MoverParameters->Couplers[1].CouplingFlag == - ctrain_virtual) // brak pojazdu podpiętego? - { - ABuScanObjects(-1, fScanDist); - // WriteLog(asName+" - block 1: "+AnsiString(fTrackBlock)); - } - CouplCounter = Random(20); // ponowne sprawdzenie po losowym czasie - } - if (MoverParameters->Vel > 0.1) //[km/h] - ++CouplCounter; // jazda sprzyja poszukiwaniu połączenia - else - { - CouplCounter = 25; // a bezruch nie, ale trzeba zaktualizować odległość, bo - // zawalidroga może - // sobie pojechać - } if (MoverParameters->DerailReason > 0) { switch (MoverParameters->DerailReason) @@ -5137,7 +5039,6 @@ void TDynamicObject::RaLightsSet(int head, int rear) int TDynamicObject::DirectionSet(int d) { // ustawienie kierunku w składzie (wykonuje AI) iDirection = d > 0 ? 1 : 0; // d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny; - CouplCounter = 20; //żeby normalnie skanować kolizje, to musi ruszyć z miejsca if (MyTrack) { // podczas wczytywania wstawiane jest AI, ale może jeszcze nie // być toru diff --git a/DynObj.h b/DynObj.h index c14cdfd7..8095c7f3 100644 --- a/DynObj.h +++ b/DynObj.h @@ -354,15 +354,13 @@ public: // modele składowe pojazdu // TTrackFollower Axle2; //dwie osie z czterech (te są protected) // TTrackFollower Axle3; //Ra: wyłączyłem, bo kąty są liczone w Segment.cpp int iNumAxles; // ilość osi - int CouplCounter; std::string asModel; public: void ABuScanObjects(int ScanDir, double ScanDist); protected: - TDynamicObject * ABuFindObject(TTrack *Track, int ScanDir, BYTE &CouplFound, - double &dist); + TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack *Track, int const Direction, int const Mycoupler ); void ABuCheckMyTrack(); public: diff --git a/Globals.cpp b/Globals.cpp index 80b4fa98..6bc61dc2 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -86,7 +86,8 @@ float Global::BaseDrawRange { 2500.f }; opengl_light Global::DayLight; int Global::DynamicLightCount { 3 }; bool Global::ScaleSpecularValues { true }; -bool Global::RenderShadows { false }; +bool Global::BasicRenderer { false }; +bool Global::RenderShadows { true }; Global::shadowtune_t Global::shadowtune = { 2048, 250.f, 250.f, 500.f }; bool Global::bRollFix = true; // czy wykonać przeliczanie przechyłki bool Global::bJoinEvents = false; // czy grupować eventy o tych samych nazwach @@ -545,6 +546,13 @@ void Global::ConfigParse(cParser &Parser) Parser.getTokens(); Parser >> Global::ScaleSpecularValues; } + else if( token == "gfxrenderer" ) { + // shadow render toggle + std::string gfxrenderer; + Parser.getTokens(); + Parser >> gfxrenderer; + Global::BasicRenderer = ( gfxrenderer == "simple" ); + } else if( token == "shadows" ) { // shadow render toggle Parser.getTokens(); @@ -1304,7 +1312,7 @@ double Global::Min0RSpeed(double vel1, double vel2) { vel2 = std::numeric_limits::max(); } - return Min0R(vel1, vel2); + return std::min(vel1, vel2); }; double Global::CutValueToRange(double min, double value, double max) diff --git a/Globals.h b/Globals.h index 376a45a0..73f52cb2 100644 --- a/Globals.h +++ b/Globals.h @@ -228,6 +228,7 @@ class Global static opengl_light DayLight; static int DynamicLightCount; static bool ScaleSpecularValues; + static bool BasicRenderer; static bool RenderShadows; static struct shadowtune_t { unsigned int map_size; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 714d7c2b..1a1a0cfa 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -2623,7 +2623,7 @@ bool TMoverParameters::DecBrakeLevelOld(void) bool TMoverParameters::IncLocalBrakeLevel(int CtrlSpeed) { bool IBL; - if ((LocalBrakePos < LocalBrakePosNo) /*and (BrakeCtrlPos<1)*/) + if ((LocalBrakePos < LocalBrakePosNo) /*and (BrakeCtrlPos<1)*/) { while ((LocalBrakePos < LocalBrakePosNo) && (CtrlSpeed > 0)) { @@ -4009,17 +4009,17 @@ double TMoverParameters::CouplerForce(int CouplerN, double dt) // blablabla // ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami - //***if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then + //if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then if ((Couplers[CouplerN].CouplingFlag == ctrain_virtual) && (Couplers[CouplerN].CoupleDist > 0)) { CF = 0; // kontrola zderzania sie - OK ScanCounter++; if ((newdist > MaxDist) || ((ScanCounter > MaxCount) && (newdist > MinDist))) - //***if (tempdist>MaxDist) or ((ScanCounter>MaxCount)and(tempdist>MinDist)) then + //if (tempdist>MaxDist) or ((ScanCounter>MaxCount)and(tempdist>MinDist)) then { // zerwij kontrolnie wirtualny sprzeg // Connected.Couplers[CNext].Connected:=nil; //Ra: ten podłączony niekoniecznie jest // wirtualny - Couplers[CouplerN].Connected = NULL; +// Couplers[CouplerN].Connected = NULL; ScanCounter = static_cast(Random(500.0)); // Q: TODO: cy dobrze przetlumaczone? // WriteLog(FloatToStr(ScanCounter)); } diff --git a/Model3d.cpp b/Model3d.cpp index e6149df5..1eea864a 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -1137,23 +1137,6 @@ TSubModel::convert( TGroundNode &Groundnode ) const { } } -// NOTE: leftover from static distance factor adjustment. -// TODO: get rid of it, once we have the dynamic adjustment code in place -void TSubModel::AdjustDist() -{ // aktualizacja odległości faz LoD, zależna od - // rozdzielczości pionowej oraz multisamplingu - if (fSquareMaxDist > 0.0) - fSquareMaxDist *= Global::fDistanceFactor; - if (fSquareMinDist > 0.0) - fSquareMinDist /= Global::fDistanceFactor; - // if (fNearAttenStart>0.0) fNearAttenStart*=Global::fDistanceFactor; - // if (fNearAttenEnd>0.0) fNearAttenEnd*=Global::fDistanceFactor; - if (Child) - Child->AdjustDist(); - if (Next) - Next->AdjustDist(); -}; - void TSubModel::ColorsSet( glm::vec3 const &Ambient, glm::vec3 const &Diffuse, glm::vec3 const &Specular ) { // ustawienie kolorów dla modelu terenu f4Ambient = glm::vec4( Ambient, 1.0f ); diff --git a/Model3d.h b/Model3d.h index 0861a6f1..a1072228 100644 --- a/Model3d.h +++ b/Model3d.h @@ -207,7 +207,6 @@ public: return m_material; } void ParentMatrix(float4x4 *m); float MaxY( float4x4 const &m ); - void AdjustDist(); void deserialize(std::istream&); void serialize(std::ostream&, diff --git a/World.cpp b/World.cpp index 94ee4e06..4d4451da 100644 --- a/World.cpp +++ b/World.cpp @@ -1434,13 +1434,19 @@ TWorld::Update_UI() { uitextline1 += "; C0:" + ( tmp->PrevConnected ? - tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) : - "none" ); + tmp->PrevConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 0 ].CouplingFlag ) + ( + tmp->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ? + " (" + to_string( tmp->MoverParameters->Couplers[ 0 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); uitextline1 += " C1:" + ( tmp->NextConnected ? - tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) : - "none" ); + tmp->NextConnected->GetName() + ":" + to_string( tmp->MoverParameters->Couplers[ 1 ].CouplingFlag ) + ( + tmp->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ? + " (" + to_string( tmp->MoverParameters->Couplers[ 1 ].CoupleDist, 1 ) + " m)" : + "" ) : + "none" ); // equipment flags uitextline2 = ( tmp->MoverParameters->Battery ? "B" : "." ); @@ -1546,9 +1552,10 @@ TWorld::Update_UI() { uitextline4 += "Driver: Vd=" + to_string( tmp->Mechanik->VelDesired, 0 ) + " Ad=" + to_string( tmp->Mechanik->AccDesired, 2 ) - + " Ah=" + to_string(tmp->Mechanik->fAccThreshold, 2) - + "@" + to_string(tmp->Mechanik->fBrake_a0[0], 2) - + "+" + to_string(tmp->Mechanik->fBrake_a1[0], 2) + + " Ah=" + to_string( tmp->Mechanik->fAccThreshold, 2 ) + + "@" + to_string( tmp->Mechanik->fBrake_a0[0], 2 ) + + "+" + to_string( tmp->Mechanik->fBrake_a1[0], 2 ) + + " Bd=" + to_string( tmp->Mechanik->fBrakeDist, 0 ) + " Pd=" + to_string( tmp->Mechanik->ActualProximityDist, 0 ) + " Vn=" + to_string( tmp->Mechanik->VelNext, 0 ) + " VSl=" + to_string( tmp->Mechanik->VelSignalLast, 0 ) diff --git a/renderer.cpp b/renderer.cpp index cb7bdb61..e741a261 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -99,7 +99,10 @@ opengl_renderer::Init( GLFWwindow *Window ) { glEnable( GL_CULL_FACE ); // Cull back-facing triangles glShadeModel( GL_SMOOTH ); // Enable Smooth Shading - m_geometry.units().texture = std::vector{ m_normaltextureunit, m_diffusetextureunit }; + m_geometry.units().texture = ( + Global::BasicRenderer ? + std::vector{ m_diffusetextureunit } : + std::vector{ m_normaltextureunit, m_diffusetextureunit } ); m_textures.assign_units( m_helpertextureunit, m_shadowtextureunit, m_normaltextureunit, m_diffusetextureunit ); // TODO: add reflections unit UILayer.set_unit( m_diffusetextureunit ); Active_Texture( m_diffusetextureunit ); @@ -253,7 +256,8 @@ opengl_renderer::Init( GLFWwindow *Window ) { ::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target for now } // environment cube map resources - if( true == m_framebuffersupport ) { + if( ( false == Global::BasicRenderer ) + && ( true == m_framebuffersupport ) ) { // texture: ::glGenTextures( 1, &m_environmentcubetexture ); ::glBindTexture( GL_TEXTURE_CUBE_MAP, m_environmentcubetexture ); @@ -1004,6 +1008,7 @@ void opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ) { // helper texture unit. if( m_helpertextureunit >= 0 ) { + Active_Texture( m_helpertextureunit ); if( ( true == Reflections ) || ( ( true == Global::RenderShadows ) @@ -1039,14 +1044,16 @@ opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool cons } } // normal/reflection texture unit - if( true == Reflections ) { + if( m_normaltextureunit >= 0 ) { + if( true == Reflections ) { - Active_Texture( m_normaltextureunit ); - ::glEnable( GL_TEXTURE_2D ); - } - else { - Active_Texture( m_normaltextureunit ); - ::glDisable( GL_TEXTURE_2D ); + Active_Texture( m_normaltextureunit ); + ::glEnable( GL_TEXTURE_2D ); + } + else { + Active_Texture( m_normaltextureunit ); + ::glDisable( GL_TEXTURE_2D ); + } } // diffuse texture unit. // NOTE: toggle actually disables diffuse texture mapping, unlike setup counterpart @@ -1282,7 +1289,9 @@ void opengl_renderer::Bind_Material( material_handle const Material ) { auto const &material = m_materials.material( Material ); - m_textures.bind( textureunit::normals, material.texture2 ); + if( false == Global::BasicRenderer ) { + m_textures.bind( textureunit::normals, material.texture2 ); + } m_textures.bind( textureunit::diffuse, material.texture1 ); } @@ -2041,8 +2050,8 @@ void opengl_renderer::Render( TSubModel *Submodel ) { if( ( Submodel->iVisible ) - && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / Global::fDistanceFactor ) ) - && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ) { + && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / std::max( 1.f, Global::fDistanceFactor ) ) ) + && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * std::max( 1.f, Global::fDistanceFactor ) ) ) ) { if( Submodel->iFlags & 0xC000 ) { ::glPushMatrix(); @@ -2702,8 +2711,8 @@ void opengl_renderer::Render_Alpha( TSubModel *Submodel ) { // renderowanie przezroczystych przez DL if( ( Submodel->iVisible ) - && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / Global::fDistanceFactor ) ) - && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * Global::fDistanceFactor ) ) ) { + && ( TSubModel::fSquareDist >= ( Submodel->fSquareMinDist / std::max( 1.f, Global::fDistanceFactor ) ) ) + && ( TSubModel::fSquareDist <= ( Submodel->fSquareMaxDist * std::max( 1.f, Global::fDistanceFactor ) ) ) ) { if( Submodel->iFlags & 0xC000 ) { ::glPushMatrix(); @@ -3187,17 +3196,29 @@ opengl_renderer::Init_caps() { Global::DynamicLightCount = std::min( Global::DynamicLightCount, maxlights - 1 ); WriteLog( "Dynamic light amount capped at " + std::to_string( Global::DynamicLightCount ) + " (" + std::to_string(maxlights) + " lights total supported by the gfx card)" ); } - { + // select renderer mode + if( true == Global::BasicRenderer ) { + WriteLog( "Basic renderer selected, shadow and reflection mapping will be disabled" ); + Global::RenderShadows = false; + m_diffusetextureunit = GL_TEXTURE0; + m_helpertextureunit = -1; + m_shadowtextureunit = -1; + m_normaltextureunit = -1; + } + else { GLint maxtextureunits; ::glGetIntegerv( GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits ); if( maxtextureunits < 4 ) { WriteLog( "Less than 4 texture units, shadow and reflection mapping will be disabled" ); + Global::BasicRenderer = true; Global::RenderShadows = false; m_diffusetextureunit = GL_TEXTURE0; - m_shadowtextureunit = -1; m_helpertextureunit = -1; + m_shadowtextureunit = -1; + m_normaltextureunit = -1; } } + if( Global::iMultisampling ) { WriteLog( "Using multisampling x" + std::to_string( 1 << Global::iMultisampling ) ); } diff --git a/version.h b/version.h index f3543435..3221e61c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 815 +#define VERSION_MINOR 820 #define VERSION_REVISION 0