From 8f02ae26c4058561edb9a99d01fe8462ea46b381 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 1 May 2021 23:04:25 +0200 Subject: [PATCH] backward scan ai logic tweak, heating control ai logic tweak, autogenerated power station recognition and filtering, pantograph tank pressure exposed to uart interface, editor mode camera initialization fix --- Driver.cpp | 309 +++++++++++++++++++++++---------------------- Driver.h | 2 +- Globals.cpp | 30 +++-- Traction.cpp | 1 + TractionPower.h | 1 + Train.cpp | 1 + Train.h | 1 + driveruipanels.cpp | 5 +- editormode.cpp | 20 ++- uart.cpp | 9 +- uart.h | 2 + 11 files changed, 214 insertions(+), 167 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index be287014..2ed0019c 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2502,10 +2502,14 @@ bool TController::CheckVehicles(TOrders user) { // HACK: to account for su-45/46 shortcomings diesel-powered engines only activate heating in cold conditions // TODO: take instead into account presence of converters in attached cars, once said presence is possible to specify - auto const isheatingneeded{ ( - IsCargoTrain ? false : - has_diesel_engine() ? ( Global.AirTemperature < 10 ) : - true ) }; + auto const ispassengertrain { ( IsPassengerTrain ) && ( iVehicles - ControlledEnginesCount > 0 ) }; + auto const isheatingcouplingactive { pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::heating ) }; + auto const isheatingneeded { + (is_emu() || is_dmu() ? true : +// false == isheatingcouplingactive ? false : + (OrderCurrentGet() & (Obey_train | Bank)) == 0 ? false : + ispassengertrain ? (has_diesel_engine() ? (Global.AirTemperature < 10) : true) : + false)}; if( mvControlling->HeatingAllow != isheatingneeded ) { cue_action( isheatingneeded ? @@ -5317,161 +5321,164 @@ TCommandType TController::BackwardScan( double const Range ) } // szukamy od pierwszej osi w wybranym kierunku double scandir = startdir * pVehicles[0]->RaDirectionGet(); - if (scandir != 0.0) { - // skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne) - // Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia - double scandist = Range; // zmodyfikuje na rzeczywiście przeskanowane - basic_event *e = NULL; // event potencjalnie od semafora - // opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru wg drugiej osi w kierunku ruchu - TTrack *scantrack = BackwardTraceRoute(scandist, scandir, pVehicles[end::front], e); - auto const dir = startdir * pVehicles[end::front]->VectorFront(); // wektor w kierunku jazdy/szukania - if( !scantrack ) { - // jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić - return TCommandType::cm_Unknown; + + if( scandir == 0.0 ) { return TCommandType::cm_Unknown; } + + // skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne) + // Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia + double scandist = Range; // zmodyfikuje na rzeczywiście przeskanowane + basic_event *e = nullptr; // event potencjalnie od semafora + // opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru wg + // drugiej osi w kierunku ruchu + auto const *scantrack{BackwardTraceRoute(scandist, scandir, pVehicles[end::front], e)}; + auto const dir{startdir * + pVehicles[end::front]->VectorFront()}; // wektor w kierunku jazdy/szukania + + // jeśli wstecz wykryto koniec toru to raczej nic się nie da w takiej sytuacji zrobić + if (e == nullptr) + { + return TCommandType::cm_Unknown; + } + if (typeid(*e) != typeid(getvalues_event)) + { + return TCommandType::cm_Unknown; + } + + // jeśli jest jakiś sygnał na widoku + double scanvel; // prędkość ustawiona semaforem +#if LOGBACKSCAN + std::string edir{"Backward scan by " + pVehicle->asName + " - " + + ((scandir > 0) ? "Event2 " : "Event1 ")}; + edir += "(" + (e->name()) + ")"; +#endif + { + // najpierw sprawdzamy, czy semafor czy inny znak został przejechany + auto const sl{e->input_location()}; // położenie komórki pamięci + auto const pos{pVehicles[end::rear]->RearPosition()}; // pozycja tyłu + auto const sem{sl - pos}; // wektor do komórki pamięci od końca składu + if (dir.x * sem.x + dir.z * sem.z < 0) + { + // jeśli został minięty + // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu +#if LOGBACKSCAN + WriteLog(edir + " - ignored as not passed yet"); +#endif + return TCommandType::cm_Unknown; // nic } - else { - // a jeśli są dalej tory - double vmechmax; // prędkość ustawiona semaforem - if( e != nullptr ) { - // jeśli jest jakiś sygnał na widoku + scanvel = e->input_value(1); // prędkość przy tym semaforze + // przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu + scandist = sem.Length() - 2; // 2m luzu przy manewrach wystarczy + if (scandist < 0) + { + // ujemnych nie ma po co wysyłać + scandist = 0; + } + } + + auto move{false}; // czy AI w trybie manewerowym ma dociągnąć pod S1 + if (e->input_command() == TCommandType::cm_SetVelocity) + { + if ((scanvel == 0.0) ? (OrderCurrentGet() & (Shunt | Loose_shunt | Connect)) : + (OrderCurrentGet() & Connect)) + { // przy podczepianiu ignorować wyjazd? + move = true; // AI w trybie manewerowym ma dociągnąć pod S1 + } + else + { + if ((scandist > fMinProximityDist) && + ((mvOccupied->Vel > EU07_AI_NOMOVEMENT) && + ((OrderCurrentGet() & (Shunt | Loose_shunt)) == 0))) + { + // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości + // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył #if LOGBACKSCAN - std::string edir { - "Backward scan by " - + pVehicle->asName + " - " - + ( ( scandir > 0 ) ? - "Event2 " : - "Event1 " ) }; + // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist) + + // AnsiString(scanvel)); + WriteLog(edir); #endif - // najpierw sprawdzamy, czy semafor czy inny znak został przejechany - auto pos = pVehicles[1]->RearPosition(); // pozycja tyłu - if( typeid( *e ) == typeid( getvalues_event ) ) - { // przesłać info o zbliżającym się semaforze + // SetProximityVelocity(scandist,scanvel,&sl); + return (scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown); + } + else + { + // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać + // if ((MoverParameters->Vel==0.0)||(scanvel==0.0)) //jeśli stoi lub ma stanąć/stać + // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie + // ruszać stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam + // PutCommand("SetVelocity",scanvel,e->Params[9].asMemCell->Value2(),&sl,stopSem); #if LOGBACKSCAN - edir += "(" + ( e->name() ) + ")"; + WriteLog(edir + " - [SetVelocity] [" + to_string(scanvel, 2) + "] [" + + to_string(e->input_value(2), 2) + "]"); #endif - auto sl = e->input_location(); // położenie komórki pamięci - auto sem = sl - pos; // wektor do komórki pamięci od końca składu - if (dir.x * sem.x + dir.z * sem.z < 0) { - // jeśli został minięty - // iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu + return (scanvel > 0 ? TCommandType::cm_SetVelocity : TCommandType::cm_Unknown); + } + } + } + // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe + if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Loose_shunt | Connect) : + true) // w Wait_for_orders też widzi tarcze + { + if (move || e->input_command() == TCommandType::cm_ShuntVelocity) + { // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 +/* + if ((scandist > fMinProximityDist) && + ((mvOccupied->Vel > EU07_AI_NOMOVEMENT) || (scanvel == 0.0))) + { + // jeśli tarcza jest daleko, to: + //- jesli pojazd jedzie, to informujemy o zmianie prędkości + //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą tarczę + if (mvOccupied->Vel > EU07_AI_NOMOVEMENT) // tylko jeśli jedzie + { // Mechanik->PutCommand("SetProximityVelocity",scandist,scanvel,sl); #if LOGBACKSCAN - WriteLog(edir + " - ignored as not passed yet"); + // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" + // "+AnsiString(scanvel)); + WriteLog(edir); #endif - return TCommandType::cm_Unknown; // nic - } - vmechmax = e->input_value(1); // prędkość przy tym semaforze - // przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu - scandist = sem.Length() - 2; // 2m luzu przy manewrach wystarczy - if( scandist < 0 ) { - // ujemnych nie ma po co wysyłać - scandist = 0; - } - bool move = false; // czy AI w trybie manewerowym ma dociągnąć pod S1 - if( e->input_command() == TCommandType::cm_SetVelocity ) { - if( ( vmechmax == 0.0 ) ? - ( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) : - ( OrderCurrentGet() & Connect ) ) { // przy podczepianiu ignorować wyjazd? - move = true; // AI w trybie manewerowym ma dociągnąć pod S1 - } - else { - if( ( scandist > fMinProximityDist ) - && ( ( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) - && ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) == 0 ) ) ) { - // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości - // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył + // SetProximityVelocity(scandist,scanvel,&sl); + // jeśli jedzie na W5 albo koniec toru, to można zmienić kierunek + return (iDrivigFlags & moveTrackEnd) ? TCommandType::cm_ChangeDirection : + TCommandType::cm_Unknown; + // TBD: request direction change also if VelNext in current direction is 0, + // while signal behind requests movement? + } + } + else + { + // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo ma stać pod + // tarczą stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam if + // ((MoverParameters->Vel==0.0)||(scanvel==0.0)) //jeśli jedzie lub ma stanąć/stać + { // nie dostanie komendy jeśli jedzie i ma jechać + // PutCommand("ShuntVelocity",scanvel,e->Params[9].asMemCell->Value2(),&sl,stopSem); #if LOGBACKSCAN - // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist) + AnsiString(vmechmax)); - WriteLog(edir); + WriteLog(edir + " - [ShuntVelocity] [" + to_string(scanvel, 2) + "] [" + + to_string(e->input_value(2), 2) + "]"); #endif - // SetProximityVelocity(scandist,vmechmax,&sl); - return ( - vmechmax > 0 ? - TCommandType::cm_SetVelocity : - TCommandType::cm_Unknown ); - } - else { - // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać - // if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma stanąć/stać - // semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie ruszać - // stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - // PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); + return (scanvel > 0 ? TCommandType::cm_ShuntVelocity : + TCommandType::cm_Unknown); + } + } + // NOTE: dead code due to returns in branching above + if ((scanvel != 0.0) && (scandist < 100.0)) + { + // jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od razu ją + // ignorujemy, aby móc szukać kolejnej eSignSkip=e; //wtedy uznajemy ignorowaną przy + // poszukiwaniu nowej #if LOGBACKSCAN - WriteLog( - edir + " - [SetVelocity] [" - + to_string( vmechmax, 2 ) + "] [" - + to_string( e->input_value( 2 ), 2 ) + "]" ); + WriteLog(edir + " - will be ignored due to Ms2"); #endif - return ( - vmechmax > 0 ? - TCommandType::cm_SetVelocity : - TCommandType::cm_Unknown ); - } - } - } - if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Loose_shunt | Connect) : - true) // w Wait_for_orders też widzi tarcze - { // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe - if (move ? true : e->input_command() == TCommandType::cm_ShuntVelocity) - { // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 - if ((scandist > fMinProximityDist) && - (mvOccupied->Vel > EU07_AI_NOMOVEMENT) || (vmechmax == 0.0) ) - { // jeśli tarcza jest daleko, to: - //- jesli pojazd jedzie, to informujemy o zmianie prędkości - //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą - // tarczę - if (mvOccupied->Vel > EU07_AI_NOMOVEMENT) // tylko jeśli jedzie - { // Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); -#if LOGBACKSCAN - // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" - // "+AnsiString(vmechmax)); - WriteLog(edir); -#endif - // SetProximityVelocity(scandist,vmechmax,&sl); - return (iDrivigFlags & moveTrackEnd) ? - TCommandType::cm_ChangeDirection : - TCommandType::cm_Unknown; // jeśli jedzie na W5 albo koniec toru, - // to można zmienić kierunek - } - } - else { - // ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo ma stać pod tarczą - // stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam - // if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie lub ma stanąć/stać - { // nie dostanie komendy jeśli jedzie i ma jechać - // PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem); -#if LOGBACKSCAN - WriteLog( - edir + " - [ShuntVelocity] [" - + to_string( vmechmax, 2 ) + "] [" - + to_string( e->input_value( 2 ), 2 ) + "]" ); -#endif - return ( - vmechmax > 0 ? - TCommandType::cm_ShuntVelocity : - TCommandType::cm_Unknown ); - } - } - if ((vmechmax != 0.0) && (scandist < 100.0)) { - // jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od razu ją ignorujemy, aby móc szukać kolejnej - // eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej -#if LOGBACKSCAN - WriteLog(edir + " - will be ignored due to Ms2"); -#endif - return ( - vmechmax > 0 ? - TCommandType::cm_ShuntVelocity : - TCommandType::cm_Unknown ); - } - } // if (move?... - } // if (OrderCurrentGet()==Shunt) - if (e->m_passive) // jeśli skanowany - if (e->is_command()) // a podłączona komórka ma komendę - return TCommandType::cm_Command; // to też się obrócić - } // if (e->Type==tp_GetValues) - } // if (e) - } // if (scantrack) - } // if (scandir!=0.0) - return TCommandType::cm_Unknown; // nic + return (scanvel > 0 ? TCommandType::cm_ShuntVelocity : TCommandType::cm_Unknown); + } +*/ + return ((VelNext > 0) ? + TCommandType::cm_Unknown : // no need to bother if we can continue in current direction + (scanvel == 0) ? + TCommandType::cm_Unknown : // no need to bother with a stop signal + TCommandType::cm_ShuntVelocity); // otherwise report a relevant shunt signal behind + } // if (move?... + } // if (OrderCurrentGet()==Shunt) + + return (((e->m_passive) && (e->is_command())) ? TCommandType::cm_Command : + TCommandType::cm_Unknown); }; std::string TController::NextStop() const @@ -7991,13 +7998,13 @@ TController::check_route_behind( double const Range ) { || ( TestFlag( iDrivigFlags, moveConnect ) ) ) }; if( couplinginprogress ) { return; } - auto const comm { BackwardScan( Range ) }; - if( comm != TCommandType::cm_Unknown ) { + auto const commandbehind { BackwardScan( Range ) }; + if( commandbehind != TCommandType::cm_Unknown ) { // jeśli w drugą można jechać // należy sprawdzać odległość od znalezionego sygnalizatora, // aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za sygnalizator // i dopiero wtedy zmienić kierunek jazdy, oczekując podania prędkości >0.5 - if( comm == TCommandType::cm_Command ) { + if( commandbehind == TCommandType::cm_Command ) { // jeśli komenda Shunt to ją odbierz bez przemieszczania się (np. odczep wagony po dopchnięciu do końca toru) iDrivigFlags |= moveStopHere; } diff --git a/Driver.h b/Driver.h index cba21eec..28b88a4d 100644 --- a/Driver.h +++ b/Driver.h @@ -407,7 +407,7 @@ private: double IdleTime{}; // keeps track of time spent at a stop double fStopTime = 0.0; // czas postoju przed dalszą jazdą (np. na przystanku) float ExchangeTime{ 0.0 }; // time needed to finish current load exchange - double fShuntVelocity = 25.0; // prędkość manewrowania, zależy m.in. od składu + double fShuntVelocity = 40.0; // prędkość manewrowania, zależy m.in. od składu int iDrivigFlags = // flagi bitowe ruchu moveStopPoint | // podjedź do W4 możliwie blisko moveStopHere | // nie podjeżdżaj do semafora, jeśli droga nie jest wolna diff --git a/Globals.cpp b/Globals.cpp index ca780f4f..d62fab48 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -695,17 +695,24 @@ global_settings::ConfigParse(cParser &Parser) { { uart_conf.enable = true; Parser.getTokens(3, false); - Parser >> uart_conf.port >> uart_conf.baud >> uart_conf.updatetime; + Parser + >> uart_conf.port + >> uart_conf.baud + >> uart_conf.updatetime; } else if (token == "uarttune") { Parser.getTokens(16); - Parser >> uart_conf.mainbrakemin >> uart_conf.mainbrakemax >> uart_conf.localbrakemin >> - uart_conf.localbrakemax >> uart_conf.tankmax >> uart_conf.tankuart >> - uart_conf.pipemax >> uart_conf.pipeuart >> uart_conf.brakemax >> - uart_conf.brakeuart >> uart_conf.hvmax >> uart_conf.hvuart >> - uart_conf.currentmax >> uart_conf.currentuart >> uart_conf.lvmax >> - uart_conf.lvuart; + Parser + >> uart_conf.mainbrakemin >> uart_conf.mainbrakemax + >> uart_conf.localbrakemin >> uart_conf.localbrakemax + >> uart_conf.tankmax >> uart_conf.tankuart + >> uart_conf.pipemax >> uart_conf.pipeuart + >> uart_conf.brakemax >> uart_conf.brakeuart + >> uart_conf.pantographmax >> uart_conf.pantographuart + >> uart_conf.hvmax >> uart_conf.hvuart + >> uart_conf.currentmax >> uart_conf.currentuart + >> uart_conf.lvmax >> uart_conf.lvuart; } else if (token == "uarttachoscale") { @@ -715,8 +722,11 @@ global_settings::ConfigParse(cParser &Parser) { else if (token == "uartfeature") { Parser.getTokens(4); - Parser >> uart_conf.mainenable >> uart_conf.scndenable >> uart_conf.trainenable >> - uart_conf.localenable; + Parser + >> uart_conf.mainenable + >> uart_conf.scndenable + >> uart_conf.trainenable + >> uart_conf.localenable; } else if (token == "uartdebug") { @@ -1177,6 +1187,8 @@ global_settings::export_as_text( std::ostream &Output ) const { << uart_conf.pipeuart << " " << uart_conf.brakemax << " " << uart_conf.brakeuart << " " + << uart_conf.pantographmax << " " + << uart_conf.pipemax << " " << uart_conf.hvmax << " " << uart_conf.hvuart << " " << uart_conf.currentmax << " " diff --git a/Traction.cpp b/Traction.cpp index 14be7909..e28767c9 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -767,6 +767,7 @@ traction_table::InitTraction() { scene::node_data nodedata; nodedata.name = traction->asPowerSupplyName; powersource = new TTractionPowerSource( nodedata ); + powersource->IsAutogenerated = true; powersource->Init( traction->NominalVoltage, traction->MaxCurrent ); simulation::Powergrid.insert( powersource ); } diff --git a/TractionPower.h b/TractionPower.h index d96f401d..3bdeacf1 100644 --- a/TractionPower.h +++ b/TractionPower.h @@ -33,6 +33,7 @@ public: // members TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji bool bSection = false; // czy jest sekcją + bool IsAutogenerated { false }; // indicates autogenerated source for individual traction piece private: // methods diff --git a/Train.cpp b/Train.cpp index 1fd2b13c..b808d850 100644 --- a/Train.cpp +++ b/Train.cpp @@ -799,6 +799,7 @@ TTrain::get_state() const { static_cast( mvOccupied->Compressor ), static_cast( mvOccupied->PipePress ), static_cast( mvOccupied->BrakePress ), + static_cast( mvPantographUnit->PantPress ), fHVoltage, { fHCurrent[ ( mvControlled->TrainType & dt_EZT ) ? 0 : 1 ], fHCurrent[ 2 ], fHCurrent[ 3 ] }, ggLVoltage.GetValue(), diff --git a/Train.h b/Train.h index 2202fb1f..3fe5e4b2 100644 --- a/Train.h +++ b/Train.h @@ -104,6 +104,7 @@ class TTrain { float reservoir_pressure; float pipe_pressure; float brake_pressure; + float pantograph_pressure; float hv_voltage; std::array hv_current; float lv_voltage; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 0ee313a3..771053fa 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -938,8 +938,8 @@ debug_panel::update_section_vehicle( std::vector &Output ) { } } } + Output.emplace_back( textline, Global.UITextColor ); } - Output.emplace_back( textline, Global.UITextColor ); } std::string @@ -1293,7 +1293,8 @@ debug_panel::update_section_powergrid( std::vector &Output ) { for( auto const *powerstation : simulation::Powergrid.sequence() ) { - if( true == powerstation->bSection ) { continue; } + if( true == powerstation->IsAutogenerated ) { continue; } + if( true == powerstation->bSection ) { continue; } auto const name { ( powerstation->m_name.empty() ? diff --git a/editormode.cpp b/editormode.cpp index 71631eca..9143c47c 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -106,7 +106,25 @@ editor_mode::enter() { m_statebackup = { Global.pCamera, FreeFlyModeFlag, Global.ControlPicking }; Camera = Global.pCamera; - FreeFlyModeFlag = true; + // NOTE: camera placement is effectively a copy of drivermode DistantView( true ) + // TBD, TODO: refactor into a common vehicle method? + if( false == FreeFlyModeFlag ) { + + auto const *vehicle { Camera.m_owner }; + auto const cab { + ( vehicle->MoverParameters->CabOccupied == 0 ? + 1 : + vehicle->MoverParameters->CabOccupied ) }; + auto const left { vehicle->VectorLeft() * cab }; + Camera.Pos = + Math3D::vector3( Camera.Pos.x, vehicle->GetPosition().y, Camera.Pos.z ) + + left * vehicle->GetWidth() + + Math3D::vector3( 1.25 * left.x, 1.6, 1.25 * left.z ); + Camera.m_owner = nullptr; + Camera.LookAt = vehicle->GetPosition(); + Camera.RaLook(); // jednorazowe przestawienie kamery + FreeFlyModeFlag = true; + } Global.ControlPicking = true; EditorModeFlag = true; diff --git a/uart.cpp b/uart.cpp index 9be1e202..d2900aef 100644 --- a/uart.cpp +++ b/uart.cpp @@ -336,7 +336,8 @@ void uart_input::poll() uint16_t tank_press = (uint16_t)std::min(conf.tankuart, trainstate.reservoir_pressure * 0.1f / conf.tankmax * conf.tankuart); uint16_t pipe_press = (uint16_t)std::min(conf.pipeuart, trainstate.pipe_pressure * 0.1f / conf.pipemax * conf.pipeuart); uint16_t brake_press = (uint16_t)std::min(conf.brakeuart, trainstate.brake_pressure * 0.1f / conf.brakemax * conf.brakeuart); - uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, trainstate.hv_voltage / conf.hvmax * conf.hvuart); + uint16_t pantograph_press = (uint16_t)std::min(conf.pantographuart, trainstate.pantograph_pressure * 0.1f / conf.pantographmax * conf.pantographuart ); + uint16_t hv_voltage = (uint16_t)std::min(conf.hvuart, trainstate.hv_voltage / conf.hvmax * conf.hvuart); uint16_t current1 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[0] / conf.currentmax * conf.currentuart); uint16_t current2 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[1] / conf.currentmax * conf.currentuart); uint16_t current3 = (uint16_t)std::min(conf.currentuart, trainstate.hv_current[2] / conf.currentmax * conf.currentuart); @@ -409,8 +410,10 @@ void uart_input::poll() SPLIT_INT16(lv_voltage), //byte 33 (uint8_t)trainstate.radio_channel, - //byte 34-48 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + //byte 34-35 + SPLIT_INT16(pantograph_press), + //byte 36-48 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (conf.debug) diff --git a/uart.h b/uart.h index 3d864740..649c29ec 100644 --- a/uart.h +++ b/uart.h @@ -23,6 +23,8 @@ public: float pipeuart = 65535.0f; float brakemax = 10.0f; float brakeuart = 65535.0f; + float pantographmax = 10.0f; + float pantographuart = 65535.0f; float hvmax = 100000.0f; float hvuart = 65535.0f; float currentmax = 10000.0f;