From 5e52467746622ed4d77efe831b6646be1d493ff0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 11 Aug 2018 01:42:22 +0200 Subject: [PATCH] car route scanning accuracy improvement, AI coasting logic tweaks, AI car braking fix --- Driver.cpp | 66 ++++++++++++++++++++++++++++++--------------------- DynObj.cpp | 69 ++++++++++++++++++++++-------------------------------- DynObj.h | 12 ++++++++++ 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 7eb533e4..6a80d78c 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -475,12 +475,11 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1) fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze - double odl_czola_od_wozka = (pVehicle->AxlePositionGet() - pVehicle->RearPosition()).Length(); if( fLastDir < 0.0 ) { // jeśli w kierunku Point2 toru fTrackLength = pTrack->Length() - fTrackLength; // przeskanowana zostanie odległość do Point2 } - fTrackLength -= odl_czola_od_wozka; + fTrackLength -= pVehicle->tracing_offset(); fCurrentDistance = -fLength - fTrackLength; // aktualna odległość ma być ujemna gdyż jesteśmy na końcu składu fLastVel = -1.0; // pTrack->VelocityGet(); // aktualna prędkość // changed to -1 to recognize speed limit, if any sSpeedTable.clear(); @@ -1878,10 +1877,16 @@ void TController::AutoRewident() } // 4. Przeliczanie siły hamowania d = pVehicles[0]; // pojazd na czele składu + // HACK: calculated brake thresholds for cars are so high they prevent the AI from effectively braking + // thus we artificially reduce them until a better solution for the problem is found + auto const braketablescale { ( + d->MoverParameters->CategoryFlag == 2 ? + 0.6 : + 1.0 ) }; while (d) { for( int i = 0; i < BrakeAccTableSize; ++i ) { - fBrake_a0[ i + 1 ] += d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); - fBrake_a1[ i + 1 ] += d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); + fBrake_a0[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) ); + fBrake_a1[ i + 1 ] += braketablescale * d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) ); } d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } @@ -4550,7 +4555,6 @@ TController::UpdateSituation(double dt) { 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 @@ -4598,8 +4602,8 @@ TController::UpdateSituation(double dt) { // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); - switch (comm) - { // ustawienie VelSignal - trochę proteza = do przemyślenia + switch (comm) { + // ustawienie VelSignal - trochę proteza = do przemyślenia case TCommandType::cm_Ready: // W4 zezwolił na jazdę // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę TableCheck( routescanrange); @@ -4636,6 +4640,11 @@ TController::UpdateSituation(double dt) { break; } + if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) { + // if ordered to change direction, try to stop + SetVelocity( 0, 0, stopDir ); + } + if( VelNext == 0.0 ) { if( !( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) { // jedzie w Shunt albo Connect, albo Wait_for_orders @@ -4909,7 +4918,7 @@ TController::UpdateSituation(double dt) { if( VelNext == 0.0 ) { if( mvOccupied->CategoryFlag & 1 ) { // trains - if( ( OrderCurrentGet() & Shunt ) + if( ( OrderCurrentGet() & ( Shunt | Connect ) ) && ( pVehicles[0]->fTrackBlock < 50.0 ) ) { // crude detection of edge case, if approaching another vehicle coast slowly until min distance // this should allow to bunch up trainsets more on sidings @@ -4929,25 +4938,28 @@ TController::UpdateSituation(double dt) { } } else { - // przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia) - auto const slowdowndistance { ( - ( OrderCurrentGet() & Connect ) == 0 ? - 100.0 : - 25.0 ) }; - if( ( std::max( slowdowndistance, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { - // don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good - // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever - auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); - AccDesired = std::min( - AccDesired, - ( VelNext * VelNext - vel * vel ) - / ( 25.92 - * std::max( - ActualProximityDist - brakingpointoffset, - std::min( - ActualProximityDist, - brakingpointoffset ) ) - + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje + // outside of max safe range + if( vel > min_speed( 10.0, VelDesired ) ) { + // allow to coast at reasonably low speed + auto const slowdowndistance { ( + ( OrderCurrentGet() & Connect ) == 0 ? + 100.0 : + 25.0 ) }; + if( ( std::max( slowdowndistance, fMaxProximityDist ) + fBrakeDist * braking_distance_multiplier( VelNext ) ) >= ( ActualProximityDist - fMaxProximityDist ) ) { + // don't slow down prematurely; as long as we have room to come to a full stop at a safe distance, we're good + // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever + auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); + AccDesired = std::min( + AccDesired, + ( VelNext * VelNext - vel * vel ) + / ( 25.92 + * std::max( + ActualProximityDist - brakingpointoffset, + std::min( + ActualProximityDist, + brakingpointoffset ) ) + + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje + } } } AccDesired = std::min( AccDesired, AccPreferred ); diff --git a/DynObj.cpp b/DynObj.cpp index ce9c6424..c019cd46 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2216,45 +2216,26 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // iNumAxles=(MoverParameters->NAxles>3 ? 4 : 2 ); iNumAxles = 2; // McZapkie-090402: odleglosc miedzy czopami skretu lub osiami - fAxleDist = Max0R(MoverParameters->BDist, MoverParameters->ADist); - if (fAxleDist < 0.2f) - fAxleDist = 0.2f; //żeby się dało wektory policzyć - if (fAxleDist > MoverParameters->Dim.L - 0.2) // nie mogą być za daleko - fAxleDist = MoverParameters->Dim.L - 0.2; // bo będzie "walenie w mur" + fAxleDist = clamp( + std::max( MoverParameters->BDist, MoverParameters->ADist ), + 0.2, //żeby się dało wektory policzyć + MoverParameters->Dim.L - 0.2 ); // nie mogą być za daleko bo będzie "walenie w mur" double fAxleDistHalf = fAxleDist * 0.5; - // WriteLog("Dynamic "+Type_Name+" of length "+MoverParameters->Dim.L+" at - // "+AnsiString(fDist)); - // if (Cab) //jeśli ma obsadę - zgodność wstecz, jeśli tor startowy ma Event0 - // if (Track->Event0) //jeśli tor ma Event0 - // if (fDist>=0.0) //jeśli jeśli w starych sceneriach początek składu byłby - // wysunięty na ten - // tor - // if (fDist<=0.5*MoverParameters->Dim.L+0.2) //ale nie jest wysunięty - // fDist+=0.5*MoverParameters->Dim.L+0.2; //wysunąć go na ten tor // przesuwanie pojazdu tak, aby jego początek był we wskazanym miejcu - fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół długości pojazdu, bo - // ustawiamy jego środek (zliczanie na - // minus) + fDist -= 0.5 * MoverParameters->Dim.L; // dodajemy pół długości pojazdu, bo ustawiamy jego środek (zliczanie na minus) switch (iNumAxles) { // Ra: pojazdy wstawiane są na tor początkowy, a potem przesuwane case 2: // ustawianie osi na torze Axle0.Init(Track, this, iDirection ? 1 : -1); Axle0.Move((iDirection ? fDist : -fDist) + fAxleDistHalf, false); Axle1.Init(Track, this, iDirection ? 1 : -1); - Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, - false); // false, żeby nie generować eventów - // Axle2.Init(Track,this,iDirection?1:-1); - // Axle2.Move((iDirection?fDist:-fDist)-fAxleDistHalft+0.01),false); - // Axle3.Init(Track,this,iDirection?1:-1); - // Axle3.Move((iDirection?fDist:-fDist)+fAxleDistHalf-0.01),false); + Axle1.Move((iDirection ? fDist : -fDist) - fAxleDistHalf, false); // false, żeby nie generować eventów break; case 4: Axle0.Init(Track, this, iDirection ? 1 : -1); - Axle0.Move((iDirection ? fDist : -fDist) + (fAxleDistHalf + MoverParameters->ADist * 0.5), - false); + Axle0.Move((iDirection ? fDist : -fDist) + (fAxleDistHalf + MoverParameters->ADist * 0.5), false); Axle1.Init(Track, this, iDirection ? 1 : -1); - Axle1.Move((iDirection ? fDist : -fDist) - (fAxleDistHalf + MoverParameters->ADist * 0.5), - false); + Axle1.Move((iDirection ? fDist : -fDist) - (fAxleDistHalf + MoverParameters->ADist * 0.5), false); // Axle2.Init(Track,this,iDirection?1:-1); // Axle2.Move((iDirection?fDist:-fDist)-(fAxleDistHalf-MoverParameters->ADist*0.5),false); // Axle3.Init(Track,this,iDirection?1:-1); @@ -2392,8 +2373,7 @@ void TDynamicObject::Move(double fDistance) // fAdjustment=0.0; vFront = Normalize(vFront); // kierunek ustawienia pojazdu (wektor jednostkowy) vLeft = Normalize(CrossProduct(vWorldUp, vFront)); // wektor poziomy w lewo, - // normalizacja potrzebna z powodu - // pochylenia (vFront) + // normalizacja potrzebna z powodu pochylenia (vFront) vUp = CrossProduct(vFront, vLeft); // wektor w górę, będzie jednostkowy modelRot.z = atan2(-vFront.x, vFront.z); // kąt obrotu pojazdu [rad]; z ABuBogies() double a = ((Axle1.GetRoll() + Axle0.GetRoll())); // suma przechyłek @@ -2409,17 +2389,13 @@ void TDynamicObject::Move(double fDistance) vLeft = Normalize(CrossProduct(vUp, vFront)); // wektor w lewo // vUp=CrossProduct(vFront,vLeft); //wektor w górę } - mMatrix.Identity(); // to też można by od razu policzyć, ale potrzebne jest - // do wyświetlania - mMatrix.BasisChange(vLeft, vUp, vFront); // przesuwanie jest jednak rzadziej niż - // renderowanie - mMatrix = Inverse(mMatrix); // wyliczenie macierzy dla pojazdu (potrzebna - // tylko do wyświetlania?) + mMatrix.Identity(); // to też można by od razu policzyć, ale potrzebne jest do wyświetlania + mMatrix.BasisChange(vLeft, vUp, vFront); // przesuwanie jest jednak rzadziej niż renderowanie + mMatrix = Inverse(mMatrix); // wyliczenie macierzy dla pojazdu (potrzebna tylko do wyświetlania?) // if (MoverParameters->CategoryFlag&2) { // przesunięcia są używane po wyrzuceniu pociągu z toru vPosition.x += MoverParameters->OffsetTrackH * vLeft.x; // dodanie przesunięcia w bok - vPosition.z += - MoverParameters->OffsetTrackH * vLeft.z; // vLeft jest wektorem poprzecznym + vPosition.z += MoverParameters->OffsetTrackH * vLeft.z; // vLeft jest wektorem poprzecznym // if () na przechyłce będzie dodatkowo zmiana wysokości samochodu vPosition.y += MoverParameters->OffsetTrackV; // te offsety są liczone przez moverparam } @@ -2429,10 +2405,10 @@ void TDynamicObject::Move(double fDistance) // MoverParameters->Loc.Z= vPosition.y; // obliczanie pozycji sprzęgów do liczenia zderzeń auto dir = (0.5 * MoverParameters->Dim.L) * vFront; // wektor sprzęgu - vCoulpler[0] = vPosition + dir; // współrzędne sprzęgu na początku - vCoulpler[1] = vPosition - dir; // współrzędne sprzęgu na końcu - MoverParameters->vCoulpler[0] = vCoulpler[0]; // tymczasowo kopiowane na inny poziom - MoverParameters->vCoulpler[1] = vCoulpler[1]; + vCoulpler[side::front] = vPosition + dir; // współrzędne sprzęgu na początku + vCoulpler[side::rear] = vPosition - dir; // współrzędne sprzęgu na końcu + MoverParameters->vCoulpler[side::front] = vCoulpler[side::front]; // tymczasowo kopiowane na inny poziom + MoverParameters->vCoulpler[side::rear] = vCoulpler[side::rear]; // bCameraNear= // if (bCameraNear) //jeśli istotne są szczegóły (blisko kamery) { // przeliczenie cienia @@ -4503,6 +4479,17 @@ void TDynamicObject::RenderSounds() { } } +// calculates distance between event-starting axle and front of the vehicle +double +TDynamicObject::tracing_offset() const { + + auto const axletoend{ ( GetLength() - fAxleDist ) * 0.5 }; + return ( + iAxleFirst ? + axletoend : + axletoend + iDirection * fAxleDist ); +} + // McZapkie-250202 // wczytywanie pliku z danymi multimedialnymi (dzwieki) void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, std::string ReplacableSkin ) { diff --git a/DynObj.h b/DynObj.h index 8d0f5de6..0bd80c0e 100644 --- a/DynObj.h +++ b/DynObj.h @@ -539,6 +539,16 @@ private: return iAxleFirst ? Axle1.pPosition : Axle0.pPosition; }; +/* + // TODO: check if scanning takes into account direction when selecting axle + // if it does, replace the version above + // if it doesn't, fix it so it does + inline Math3D::vector3 AxlePositionGet() { + return ( + iDirection ? + ( iAxleFirst ? Axle1.pPosition : Axle0.pPosition ) : + ( iAxleFirst ? Axle0.pPosition : Axle1.pPosition ) ); } +*/ inline Math3D::vector3 VectorFront() const { return vFront; }; inline Math3D::vector3 VectorUp() const { @@ -555,6 +565,8 @@ private: return MoverParameters->Dim.L; }; inline double GetWidth() const { return MoverParameters->Dim.W; }; + // calculates distance between event-starting axle and front of the vehicle + double tracing_offset() const; inline TTrack * GetTrack() { return (iAxleFirst ? Axle1.GetTrack() :