From 6947107f3cbffc016a73274f9d006dfa66e76868 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 15 Feb 2019 16:07:02 +0100 Subject: [PATCH 1/7] door operation permit preset cab control, door control system enhancements, minor bug fixes --- Driver.cpp | 7 ++- DynObj.cpp | 20 +++---- McZapkie/MOVER.h | 23 +++++++- McZapkie/Mover.cpp | 128 +++++++++++++++++++++++++++------------- Train.cpp | 48 +++++++++++++-- Train.h | 5 +- command.cpp | 2 + command.h | 2 + driverkeyboardinput.cpp | 9 ++- drivermouseinput.cpp | 3 + station.cpp | 2 +- translation.cpp | 35 ++++++----- translation.h | 1 + 13 files changed, 203 insertions(+), 82 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index b9297f8c..76fc776b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3172,7 +3172,7 @@ void TController::SpeedSet() // Ra 2014-06: "automatyczna" skrzynia biegów... if (!mvControlling->MotorParam[mvControlling->ScndCtrlPos].AutoSwitch) // gdy biegi ręczne if ((mvControlling->ShuntMode ? mvControlling->AnPos : 1.0) * mvControlling->Vel > - 0.6 * mvControlling->MotorParam[mvControlling->ScndCtrlPos].mfi) + 0.75 * mvControlling->MotorParam[mvControlling->ScndCtrlPos].mfi) // if (mvControlling->enrot>0.95*mvControlling->dizel_nMmax) //youBy: jeśli obroty > // 0,95 nmax, wrzuć wyższy bieg - Ra: to nie działa { // jak prędkość większa niż 0.6 maksymalnej na danym biegu, wrzucić wyższy @@ -3223,7 +3223,7 @@ void TController::Doors( bool const Open, int const Side ) { auto const lewe = ( pVehicle->DirectionGet() > 0 ) ? 1 : 2; auto const prawe = 3 - lewe; - if( ( pVehicle->MoverParameters->Doors.open_permit == false ) + if( ( true == pVehicle->MoverParameters->Doors.permit_needed ) && ( true == AIControllFlag ) ) { // grant door control permission if it's not automatic // TBD: stricter requirements? @@ -3247,7 +3247,8 @@ void TController::Doors( bool const Open, int const Side ) { } else { // zamykanie - if( ( true == pVehicle->MoverParameters->Doors.open_permit ) && ( false == doors_open() ) ) { + if( ( false == pVehicle->MoverParameters->Doors.permit_needed ) + && ( false == doors_open() ) ) { // the doors are already closed and we don't have to revoke control permit, we can skip all hard work iDrivigFlags &= ~moveDoorOpened; } diff --git a/DynObj.cpp b/DynObj.cpp index 05d61771..37bb522e 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2287,18 +2287,19 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" int TDynamicObject::init_sections( TModel3d const *Model, std::string const &Nameprefix ) { - std::string sectionname; auto sectioncount = 0; auto sectionindex = 0; TSubModel *sectionsubmodel { nullptr }; do { - sectionname = - Nameprefix + ( - sectionindex < 10 ? - "0" + std::to_string( sectionindex ) : - std::to_string( sectionindex ) ); - sectionsubmodel = Model->GetFromName( sectionname ); + // section names for index < 10 match either prefix0X or prefixX + // section names above 10 match prefixX + auto const sectionindexname { std::to_string( sectionindex ) }; + sectionsubmodel = Model->GetFromName( Nameprefix + sectionindexname ); + if( ( sectionsubmodel == nullptr ) + && ( sectionindex < 10 ) ) { + sectionsubmodel = Model->GetFromName( Nameprefix + "0" + sectionindexname ); + } if( sectionsubmodel != nullptr ) { Sections.push_back( { sectionsubmodel, @@ -2771,10 +2772,7 @@ TDynamicObject::update_load_sections() { for( auto §ion : Sections ) { - section.load = ( - mdLoad != nullptr ? - mdLoad->GetFromName( section.compartment->pName ) : - nullptr ); + section.load = GetSubmodelFromName( mdLoad, section.compartment->pName ); if( ( section.load != nullptr ) && ( section.load->count_children() > 0 ) ) { diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index eac33dc5..697757ab 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -638,6 +638,20 @@ class TMoverParameters private: // types + // communication cable, exchanging control signals with adjacent vehicle + struct jumper_cable { + // types + using flag_pair = std::pair; + // members + // booleans + // std::array flags {}; + // boolean pairs, exchanged data is swapped when connected to a matching end (front to front or back to back) + // TBD, TODO: convert to regular bool array for efficiency once it's working? + std::array flag_pairs {}; + // integers + // std::array values {}; + }; + // basic approximation of a generic device // TBD: inheritance or composition? struct basic_device { @@ -722,9 +736,13 @@ private: bool has_autowarning { false }; float auto_duration { -1.f }; // automatic door closure delay period float auto_velocity { -1.f }; // automatic door closure velocity threshold + bool auto_include_remote { false }; // automatic door closure applies also to remote control + bool permit_needed { false }; + std::vector permit_presets; // permit presets selectable with preset switch // ld inputs bool lock_enabled { true }; - bool open_permit { true }; + // internal data + int permit_preset { -1 }; // curent position of preset selection switch // vehicle parts std::array instances; // door on the right and left side of the vehicle // ld outputs @@ -1472,7 +1490,8 @@ public: /* funckje dla wagonow*/ bool AssignLoad( std::string const &Name, float const Amount = 0.f ); bool LoadingDone(double LSpeed, std::string const &Loadname); - bool PermitDoors( side const Door, range_t const Notify = range_t::consist ); + bool PermitDoors( side const Door, bool const State = true, range_t const Notify = range_t::consist ); + bool ChangeDoorPermitPreset( int const Change, range_t const Notify = range_t::consist ); bool OperateDoors( side const Door, bool const State, range_t const Notify = range_t::consist ); bool LockDoors( bool const State, range_t const Notify = range_t::consist ); bool signal_departure( bool const State, range_t const Notify = range_t::consist ); // toggles departure warning diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 6a5f15a7..b6535ce0 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -4595,8 +4595,13 @@ double TMoverParameters::TractionForce( double dt ) { case TEngineType::ElectricSeriesMotor: { // update the state of voltage relays auto const voltage { std::max( GetTrainsetVoltage(), std::abs( RunningTraction.TractionVoltage ) ) }; - NoVoltRelay = ( voltage >= EnginePowerSource.CollectorParameters.MinV ); - OvervoltageRelay = ( voltage <= EnginePowerSource.CollectorParameters.MaxV ) || ( false == EnginePowerSource.CollectorParameters.OVP ); + NoVoltRelay = + ( EnginePowerSource.SourceType != TPowerSource::CurrentCollector ) + || ( voltage >= EnginePowerSource.CollectorParameters.MinV ); + OvervoltageRelay = + ( EnginePowerSource.SourceType != TPowerSource::CurrentCollector ) + || ( voltage <= EnginePowerSource.CollectorParameters.MaxV ) + || ( false == EnginePowerSource.CollectorParameters.OVP ); // wywalanie szybkiego z powodu niewłaściwego napięcia EventFlag |= ( ( true == Mains ) && ( ( false == NoVoltRelay ) || ( false == OvervoltageRelay ) ) @@ -5582,10 +5587,10 @@ bool TMoverParameters::AutoRelayCheck(void) // sprawdzenie wszystkich warunkow (AutoRelayFlag, AutoSwitch, Im= 4 ); } -bool TMoverParameters::PermitDoors( side const Door, range_t const Notify ) { +bool TMoverParameters::ChangeDoorPermitPreset( int const Change, range_t const Notify ) { + + auto const initialstate { Doors.permit_preset }; + + if( false == Doors.permit_presets.empty() ) { + + Doors.permit_preset = clamp( Doors.permit_preset + Change, 0, Doors.permit_presets.size() - 1 ); + auto const doors { Doors.permit_presets[ Doors.permit_preset ] }; + auto const permitleft = doors & 1; + auto const permitright = doors & 2; + + PermitDoors( ( CabNo > 0 ? side::left : side::right ), permitleft, Notify ); + PermitDoors( ( CabNo > 0 ? side::right : side::left ), permitright, Notify ); + } + + return ( Doors.permit_preset != initialstate ); +} + +bool TMoverParameters::PermitDoors( side const Door, bool const State, range_t const Notify ) { bool const initialstate { Doors.instances[Door].open_permit }; - if( ( true == Battery ) - && ( false == Doors.is_locked ) ) { + if( ( false == Doors.permit_presets.empty() ) // HACK: for cases where preset switch is used before battery + || ( ( true == Battery ) + && ( false == Doors.is_locked ) ) ) { - Doors.instances[ Door ].open_permit = true; + Doors.instances[ Door ].open_permit = State; } if( Notify != range_t::local ) { SendCtrlToNext( "DoorPermit", - ( Door == ( CabNo > 0 ? side::left : side::right ) ? // 1=lewe, 2=prawe (swap if reversed) + ( State ? 1 : -1 ) // positive: grant, negative: revoke + * ( Door == ( CabNo > 0 ? side::left : side::right ) ? // 1=lewe, 2=prawe (swap if reversed) 1 : 2 ), CabNo, @@ -6872,8 +6897,12 @@ TMoverParameters::update_doors( double const Deltatime ) { && ( Vel >= 10.0 ); for( auto &door : Doors.instances ) { - - door.open_permit = door.open_permit && ( false == door.remote_close ) && ( false == Doors.is_locked ); + // revoke permit if... + door.open_permit = + ( true == door.open_permit ) // ...we already have one... + && ( ( false == Doors.permit_presets.empty() ) // ...there's no permit preset switch... + || ( ( false == Doors.is_locked ) // ...and the door lock is engaged... + && ( false == door.remote_close ) ) );// ...or about to be closed door.is_open = ( door.position >= Doors.range ) @@ -6882,35 +6911,41 @@ TMoverParameters::update_doors( double const Deltatime ) { ( door.position <= 0.f ) && ( door.step_position <= 0.f ); - door.local_open = door.local_open && ( false == door.is_open ) && ( Doors.open_permit || door.open_permit ); - door.remote_open = door.remote_open && ( false == door.is_open ) && ( Doors.open_permit || door.open_permit ); - door.local_close = door.local_close && ( false == door.is_closed ); + door.local_open = door.local_open && ( false == door.is_open ) && ( ( false == Doors.permit_needed ) || door.open_permit ); + door.remote_open = door.remote_open && ( false == door.is_open ) && ( ( false == Doors.permit_needed ) || door.open_permit ); + door.local_close = door.local_close && ( false == door.is_closed ); door.remote_close = door.remote_close && ( false == door.is_closed ); auto const openrequest { ( localopencontrol && door.local_open ) || ( remoteopencontrol && door.remote_open ) }; + auto const autocloserequest { ( ( Doors.auto_velocity != -1.f ) && ( Vel > Doors.auto_velocity ) ) - || ( ( Doors.auto_duration != -1.f ) && ( door.auto_timer <= 0.f ) ) }; + || ( ( door.auto_timer != -1.f ) && ( door.auto_timer <= 0.f ) ) + || ( ( Doors.permit_needed ) && ( false == door.open_permit ) ) }; auto const closerequest { - ( remoteclosecontrol && door.remote_close ) - || ( localclosecontrol && door.local_close ) - || ( autocloserequest && door.local_close ) }; + ( door.remote_close && remoteclosecontrol ) + || ( door.local_close && localclosecontrol ) + || ( autocloserequest && door.is_open ) }; door.is_opening = ( false == door.is_open ) + && ( true == Battery ) && ( false == closerequest ) - && ( door.is_opening || openrequest ); + && ( ( true == door.is_opening ) + || ( ( true == openrequest ) + && ( false == Doors.is_locked ) ) ); door.is_closing = ( false == door.is_closed ) + && ( true == Battery ) && ( false == openrequest ) && ( door.is_closing || closerequest ); if( true == door.is_opening ) { door.auto_timer = ( - ( remoteopencontrol && door.remote_open ) ? - -1.f : - Doors.auto_duration ); + ( localopencontrol && door.local_open ) ? Doors.auto_duration : + ( remoteopencontrol && door.remote_open && Doors.auto_include_remote ) ? Doors.auto_duration : + -1.f ); } // doors @@ -6994,7 +7029,7 @@ TMoverParameters::update_doors( double const Deltatime ) { } } } - +/* // the door are closed if their timer goes below 0, or if the vehicle is moving faster than defined threshold std::array const doorids { side::right, side::left }; for( auto const doorid : doorids ) { @@ -7007,6 +7042,7 @@ TMoverParameters::update_doors( double const Deltatime ) { } } } +*/ } // ************************************************************************************************* @@ -8123,11 +8159,23 @@ void TMoverParameters::LoadFIZ_Doors( std::string const &line ) { // automatic closing conditions extract_value( Doors.auto_duration, "DoorStayOpen", line, "" ); extract_value( Doors.auto_velocity, "DoorAutoCloseVel", line, "" ); - // operation permit override + extract_value( Doors.auto_include_remote, "DoorAutoCloseRemote", line, "" ); + // operation permit + extract_value( Doors.permit_needed, "DoorNeedPermit", line, "" ); { - bool doorneedpermit { false }; - extract_value( doorneedpermit, "DoorNeedPermit", line, "" ); - Doors.open_permit = ( false == doorneedpermit ); + auto permitpresets = Split( extract_value( "DoorPermitList", line ), '|' ); + for( auto const &permit : permitpresets ) { + Doors.permit_presets.emplace_back( std::stoi( permit ) ); + } + if( false == Doors.permit_presets.empty() ) { + // HACK: legacy position indices start from 1, so we deduct 1 to arrive at proper index into the array + extract_value( Doors.permit_preset, "DoorPermitListDefault", line, "1" ); + Doors.permit_preset = + std::min( + Doors.permit_presets.size(), + Doors.permit_preset ) + - 1; + } } extract_value( Doors.open_rate, "OpenSpeed", line, "" ); @@ -8935,7 +8983,8 @@ TPowerSource TMoverParameters::LoadFIZ_SourceDecode( std::string const &Source ) std::map powersources{ { "Transducer", TPowerSource::Transducer }, { "Generator", TPowerSource::Generator }, - { "Accu", TPowerSource::Accumulator }, + { "Accu", TPowerSource::Accumulator }, // legacy compatibility leftover. TODO: check if we can get rid of it + { "Accumulator", TPowerSource::Accumulator }, { "CurrentCollector", TPowerSource::CurrentCollector }, { "PowerCable", TPowerSource::PowerCable }, { "Heater", TPowerSource::Heater }, @@ -9250,10 +9299,12 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) BrakeDelayFlag = bdelay_G; if ((TestFlag(BrakeDelays, bdelay_R)) && !(TestFlag(BrakeDelays, bdelay_G))) BrakeDelayFlag = bdelay_R; - +/* +// disabled, as test mode is used in specific situations and not really a default if (BrakeOpModes & bom_PS) BrakeOpModeFlag = bom_PS; else +*/ BrakeOpModeFlag = bom_PN; // yB: jesli pojazdy nie maja zadeklarowanych czasow, to wsadz z przepisow +-16,(6)% @@ -9632,19 +9683,16 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else if (Command == "DoorPermit") { - if( ( true == Battery ) - && ( false == Doors.is_locked ) ) { + auto const left { CValue2 > 0 ? 1 : 2 }; + auto const right { 3 - left }; - auto const left { CValue2 > 0 ? 1 : 2 }; - auto const right { 3 - left }; - - if( static_cast( CValue1 ) & right ) { - Doors.instances[ side::right ].open_permit = true; - } - if( static_cast( CValue1 ) & left ) { - Doors.instances[ side::left ].open_permit = true; - } + if( std::abs( static_cast( CValue1 ) ) & right ) { + Doors.instances[ side::right ].open_permit = (CValue1 > 0); } + if( std::abs( static_cast( CValue1 ) ) & left ) { + Doors.instances[ side::left ].open_permit = (CValue1 > 0); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "DoorOpen") /*NBMX*/ diff --git a/Train.cpp b/Train.cpp index 56c594c3..1aab4f76 100644 --- a/Train.cpp +++ b/Train.cpp @@ -325,6 +325,8 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::doortoggleright, &TTrain::OnCommand_doortoggleright }, { user_command::doorpermitleft, &TTrain::OnCommand_doorpermitleft }, { user_command::doorpermitright, &TTrain::OnCommand_doorpermitright }, + { user_command::doorpermitpresetactivatenext, &TTrain::OnCommand_doorpermitpresetactivatenext }, + { user_command::doorpermitpresetactivateprevious, &TTrain::OnCommand_doorpermitpresetactivateprevious }, { user_command::dooropenleft, &TTrain::OnCommand_dooropenleft }, { user_command::dooropenright, &TTrain::OnCommand_dooropenright }, { user_command::doorcloseleft, &TTrain::OnCommand_doorcloseleft }, @@ -4237,6 +4239,27 @@ void TTrain::OnCommand_doorpermitright( TTrain *Train, command_data const &Comma } } +void TTrain::OnCommand_doorpermitpresetactivatenext( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + Train->mvOccupied->ChangeDoorPermitPreset( 1 ); + // visual feedback + Train->ggDoorPermitPresetButton.UpdateValue( Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch ); + } +} + +void TTrain::OnCommand_doorpermitpresetactivateprevious( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + + Train->mvOccupied->ChangeDoorPermitPreset( -1 ); + // visual feedback + Train->ggDoorPermitPresetButton.UpdateValue( Train->mvOccupied->Doors.permit_preset, Train->dsbSwitch ); + } +} + + void TTrain::OnCommand_dooropenleft( TTrain *Train, command_data const &Command ) { auto const remoteopencontrol { @@ -5839,6 +5862,7 @@ bool TTrain::Update( double const Deltatime ) // NBMX wrzesien 2003 - drzwi ggDoorLeftPermitButton.Update(); ggDoorRightPermitButton.Update(); + ggDoorPermitPresetButton.Update(); ggDoorLeftButton.Update(); ggDoorRightButton.Update(); ggDoorLeftOnButton.Update(); @@ -5869,11 +5893,12 @@ bool TTrain::Update( double const Deltatime ) InstrumentLightType == 1 ? mvControlled->Mains : InstrumentLightType == 2 ? mvControlled->ConverterFlag : InstrumentLightType == 3 ? mvControlled->Battery || mvControlled->ConverterFlag : + InstrumentLightType == 4 ? mvControlled->Battery || mvControlled->ConverterFlag : false ) }; - if( InstrumentLightType == 3 ) { - // TODO: link the light state with the state of the master key - InstrumentLightActive = true; - } + InstrumentLightActive = ( + InstrumentLightType == 3 ? true : // TODO: link the light state with the state of the master key + InstrumentLightType == 4 ? ( mvOccupied->iLights[end::front] != 0 ) || ( mvOccupied->iLights[end::rear] != 0 ) : + InstrumentLightActive ); btInstrumentLight.Turn( InstrumentLightActive && lightpower ); btDashboardLight.Turn( DashboardLightActive && lightpower ); btTimetableLight.Turn( TimetableLightActive && lightpower ); @@ -6245,7 +6270,10 @@ TTrain::update_sounds( double const Deltatime ) { || TestFlag( mvOccupied->SecuritySystem.Status, s_SHPalarm ) ) { if( false == dsbBuzzer.is_playing() ) { - dsbBuzzer.play( sound_flags::looping ); + dsbBuzzer + .pitch( dsbBuzzer.m_frequencyoffset + dsbBuzzer.m_frequencyfactor ) + .gain( dsbBuzzer.m_amplitudeoffset + dsbBuzzer.m_amplitudefactor ) + .play( sound_flags::looping ); Console::BitsSet( 1 << 14 ); // ustawienie bitu 16 na PoKeys } } @@ -6270,9 +6298,10 @@ TTrain::update_sounds( double const Deltatime ) { auto const frequency { ( true == dsbHasler.is_combined() ? fTachoVelocity * 0.01 : - 1.0 ) }; + dsbHasler.m_frequencyoffset + dsbHasler.m_frequencyfactor ) }; dsbHasler .pitch( frequency ) + .gain( dsbHasler.m_amplitudeoffset + dsbHasler.m_amplitudefactor ) .play( sound_flags::exclusive | sound_flags::looping ); } else if( fTachoCount < 1.f ) { @@ -7116,6 +7145,7 @@ void TTrain::clear_cab_controls() ggRadioTest.Clear(); ggDoorLeftPermitButton.Clear(); ggDoorRightPermitButton.Clear(); + ggDoorPermitPresetButton.Clear(); ggDoorLeftButton.Clear(); ggDoorRightButton.Clear(); ggDoorLeftOnButton.Clear(); @@ -7429,6 +7459,7 @@ void TTrain::set_cab_controls( int const Cab ) { 0.f ) ); // doors // NOTE: for the time being permit switches are presumed to be impulse switches + ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset ); ggDoorLeftButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].is_closed ? 0.f : 1.f ); ggDoorRightButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].is_closed ? 0.f : 1.f ); // door lock @@ -7676,6 +7707,10 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co btInstrumentLight.Load( Parser, DynamicObject ); InstrumentLightType = 3; } + else if( Label == "i-instrumentlight_l:" ) { + btInstrumentLight.Load( Parser, DynamicObject ); + InstrumentLightType = 4; + } else if (Label == "i-doors:") { int i = Parser.getToken() - 1; @@ -7725,6 +7760,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "stlinoff_bt:", ggStLinOffButton }, { "doorleftpermit_sw:", ggDoorLeftPermitButton }, { "doorrightpermit_sw:", ggDoorRightPermitButton }, + { "doorpermitpreset_sw:", ggDoorPermitPresetButton }, { "door_left_sw:", ggDoorLeftButton }, { "door_right_sw:", ggDoorRightButton }, { "doorlefton_sw:", ggDoorLeftOnButton }, diff --git a/Train.h b/Train.h index 57038300..7ebaff11 100644 --- a/Train.h +++ b/Train.h @@ -315,6 +315,8 @@ class TTrain static void OnCommand_doortoggleright( TTrain *Train, command_data const &Command ); static void OnCommand_doorpermitleft( TTrain *Train, command_data const &Command ); static void OnCommand_doorpermitright( TTrain *Train, command_data const &Command ); + static void OnCommand_doorpermitpresetactivatenext( TTrain *Train, command_data const &Command ); + static void OnCommand_doorpermitpresetactivateprevious( TTrain *Train, command_data const &Command ); static void OnCommand_dooropenleft( TTrain *Train, command_data const &Command ); static void OnCommand_dooropenright( TTrain *Train, command_data const &Command ); static void OnCommand_doorcloseleft( TTrain *Train, command_data const &Command ); @@ -445,6 +447,7 @@ public: // reszta może by?publiczna // NBMX wrzesien 2003 - obsluga drzwi TGauge ggDoorLeftPermitButton; TGauge ggDoorRightPermitButton; + TGauge ggDoorPermitPresetButton; TGauge ggDoorLeftButton; TGauge ggDoorRightButton; TGauge ggDoorLeftOnButton; @@ -517,7 +520,7 @@ public: // reszta może by?publiczna TButton btInstrumentLight; TButton btDashboardLight; TButton btTimetableLight; - int InstrumentLightType{ 0 }; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw., 3-rozrzad + int InstrumentLightType{ 0 }; // ABu 030405 - swiecenie uzaleznione od: 0-nic, 1-obw.gl, 2-przetw., 3-rozrzad, 4-external lights bool InstrumentLightActive{ false }; bool DashboardLightActive{ false }; bool TimetableLightActive{ false }; diff --git a/command.cpp b/command.cpp index f1f38536..fda03c21 100644 --- a/command.cpp +++ b/command.cpp @@ -144,6 +144,8 @@ commanddescription_sequence Commands_descriptions = { { "doortoggleright", command_target::vehicle }, { "doorpermitleft", command_target::vehicle }, { "doorpermitright", command_target::vehicle }, + { "doorpermitpresetactivatenext", command_target::vehicle }, + { "doorpermitpresetactivateprevious", command_target::vehicle }, { "dooropenleft", command_target::vehicle }, { "dooropenright", command_target::vehicle }, { "dooropenall", command_target::vehicle }, diff --git a/command.h b/command.h index a3d025d9..f5875aa5 100644 --- a/command.h +++ b/command.h @@ -137,6 +137,8 @@ enum class user_command { doortoggleright, doorpermitleft, doorpermitright, + doorpermitpresetactivatenext, + doorpermitpresetactivateprevious, dooropenleft, dooropenright, dooropenall, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index ae8aab93..7da92746 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -144,8 +144,13 @@ driverkeyboard_input::default_bindings() { { user_command::carcouplingdisconnect, GLFW_KEY_DELETE }, { user_command::doortoggleleft, GLFW_KEY_COMMA }, { user_command::doortoggleright, GLFW_KEY_PERIOD }, + { user_command::doorpermitleft, GLFW_KEY_COMMA | keymodifier::shift }, + { user_command::doorpermitright, GLFW_KEY_PERIOD | keymodifier::shift }, + { user_command::doorpermitpresetactivatenext, GLFW_KEY_PERIOD | keymodifier::shift | keymodifier::control }, + { user_command::doorpermitpresetactivateprevious, GLFW_KEY_COMMA | keymodifier::shift | keymodifier::control }, // dooropenleft, // dooropenright, + { user_command::dooropenall, GLFW_KEY_SLASH | keymodifier::shift }, // doorcloseleft, // doorcloseright, { user_command::doorcloseall, GLFW_KEY_SLASH | keymodifier::control }, @@ -202,8 +207,8 @@ driverkeyboard_input::default_bindings() { { user_command::instrumentlighttoggle, GLFW_KEY_SEMICOLON }, // instrumentlightenable, // instrumentlightdisable, - // dashboardlighttoggle, - // timetablelighttoggle, + { user_command::dashboardlighttoggle, GLFW_KEY_SEMICOLON | keymodifier::shift }, + { user_command::timetablelighttoggle, GLFW_KEY_APOSTROPHE | keymodifier::shift }, { user_command::generictoggle0, GLFW_KEY_0 }, { user_command::generictoggle1, GLFW_KEY_1 }, { user_command::generictoggle2, GLFW_KEY_2 }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index a5b1d8c2..d0ff7b5b 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -557,6 +557,9 @@ drivermouse_input::default_bindings() { { "doorrightpermit_sw:", { user_command::doorpermitright, user_command::none } }, + { "doorpermitpreset_sw:", { + user_command::doorpermitpresetactivatenext, + user_command::doorpermitpresetactivateprevious } }, { "door_left_sw:", { user_command::doortoggleleft, user_command::none } }, diff --git a/station.cpp b/station.cpp index 5fba4379..a8d8887d 100644 --- a/station.cpp +++ b/station.cpp @@ -59,7 +59,7 @@ basic_station::update_load( TDynamicObject *First, Mtable::TTrainParameters &Sch firststop ? 0 : std::min( parameters.LoadAmount, - Random( parameters.MaxLoad * 0.10 * stationsizemodifier ) ) ); + Random( parameters.MaxLoad * 0.15f * stationsizemodifier ) ) ); auto loadcount = static_cast( laststop ? 0 : diff --git a/translation.cpp b/translation.cpp index 3b0373aa..1b1c85f5 100644 --- a/translation.cpp +++ b/translation.cpp @@ -97,16 +97,17 @@ init() { "motor overload relay reset", "converter overload relay reset", "motor connectors", + "left door (permit)", + "right door (permit)", + "door (permit)", "left door", "right door", - "left door", - "right door", - "left door", - "right door", - "left door", - "right door", - "all doors", - "all doors", + "left door (open)", + "right door (open)", + "left door (close)", + "right door (close)", + "all doors (open)", + "all doors (close)", "departure signal", "upper headlight", "left headlight", @@ -238,16 +239,17 @@ init() { "przekaznik nadmiarowy silnikow trakcyjnych", "przekaznik nadmiarowy przetwornicy", "styczniki liniowe", + "drzwi lewe (zezwol)", + "drzwi prawe (zezwol)", + "drzwi (zezwol)", "drzwi lewe", "drzwi prawe", - "drzwi lewe", - "drzwi prawe", - "drzwi lewe", - "drzwi prawe", - "drzwi lewe", - "drzwi prawe", - "drzwi", - "drzwi", + "drzwi lewe (otworz)", + "drzwi prawe (otworz)", + "drzwi lewe (zamknij)", + "drzwi prawe (zamknij)", + "drzwi (otworz)", + "drzwi (zamknij)", "sygnal odjazdu", "reflektor gorny", "reflektor lewy", @@ -353,6 +355,7 @@ init() { "stlinoff_bt:", "doorleftpermit_sw:", "doorrightpermit_sw:", + "doorpermitpreset_sw:", "door_left_sw:", "door_right_sw:", "doorlefton_sw:", diff --git a/translation.h b/translation.h index 7435c93d..6ca599b8 100644 --- a/translation.h +++ b/translation.h @@ -88,6 +88,7 @@ enum string { cab_stlinoff_bt, cab_doorleftpermit_sw, cab_doorrightpermit_sw, + cab_doorpermitpreset_sw, cab_door_left_sw, cab_door_right_sw, cab_doorlefton_sw, From c40b54fd9311d5af3696256402dc016b1bcf50c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Mon, 11 Feb 2019 20:53:09 +0100 Subject: [PATCH 2/7] Added parameters of train (mass and length) for driver timetable panel --- driveruipanels.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/driveruipanels.cpp b/driveruipanels.cpp index e30f921b..e4f221f0 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -220,7 +220,17 @@ timetable_panel::update() { } else { auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; - // header + + text_lines.emplace_back("Brutto rozkl. " + to_string(table->LocLoad), Global.UITextColor); + auto fMass = owner->fMass / 1000; + if (owner->mvControlling->TrainType & (dt_DMU + dt_EZT) == 0) + { + //odejmij lokomotywy czynne, a przynajmniej aktualną + } + text_lines.emplace_back("Brutto rzecz. " + to_string(fMass,0), Global.UITextColor); + text_lines.emplace_back("Dl.poc. rzecz. " + to_string(owner->fLength,0), Global.UITextColor); + + // header text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); TMTableLine const *tableline; From bc7df7fa5910a95ae6bec49fbceae228a322f6b3 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 15 Feb 2019 20:03:32 +0100 Subject: [PATCH 3/7] build 190215. timetable consist data tweaks --- Driver.cpp | 4 ++-- driveruipanels.cpp | 38 ++++++++++++++++++++++++++++---------- translation.cpp | 2 ++ translation.h | 1 + version.h | 2 +- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 76fc776b..942a33e3 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1030,9 +1030,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN + ": at " + std::to_string(simulation::Time.data().wHour) + ":" + std::to_string(simulation::Time.data().wMinute) + " next " + asNextStop); // informacja #endif - // update brake settings and ai braking tables + // update consist weight, brake settings and ai braking tables // NOTE: this calculation is expected to run after completing loading/unloading - AutoRewident(); // nastawianie hamulca do jazdy pociągowej + CheckVehicles(); // nastawianie hamulca do jazdy pociągowej if( static_cast( std::floor( std::abs( sSpeedTable[ i ].evEvent->input_value( 1 ) ) ) ) % 2 ) { // nie podjeżdżać do semafora, jeśli droga nie jest wolna diff --git a/driveruipanels.cpp b/driveruipanels.cpp index e4f221f0..a4f9ca01 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -207,29 +207,47 @@ timetable_panel::update() { auto textline = " -> " + nextstation; text_lines.emplace_back( textline, Global.UITextColor ); + text_lines.emplace_back( "", Global.UITextColor ); } } if( is_expanded ) { - text_lines.emplace_back( "", Global.UITextColor ); + if( vehicle->MoverParameters->CategoryFlag == 1 ) { + // consist data + auto consistmass { owner->fMass }; + auto consistlength { owner->fLength }; + if( ( owner->mvControlling->TrainType != dt_DMU ) + && ( owner->mvControlling->TrainType != dt_EZT ) + && ( owner->pVehicles[end::front] != owner->pVehicles[end::rear] ) ) { + //odejmij lokomotywy czynne, a przynajmniej aktualną + consistmass -= owner->pVehicle->MoverParameters->TotalMass; + // subtract potential other half of a two-part vehicle + auto const *previous { owner->pVehicle->PrevC( coupling::permanent ) }; + if( previous != nullptr ) { consistmass -= previous->MoverParameters->TotalMass; } + auto const *next { owner->pVehicle->NextC( coupling::permanent ) }; + if( next != nullptr ) { consistmass -= next->MoverParameters->TotalMass; } +// consistlength -= owner->pVehicle->MoverParameters->Dim.L; + } + std::snprintf( + m_buffer.data(), m_buffer.size(), + locale::strings[ locale::string::driver_timetable_consistdata ].c_str(), + static_cast( table->LocLoad ), + static_cast( consistmass / 1000 ), + static_cast( consistlength ) ); + + text_lines.emplace_back( m_buffer.data(), Global.UITextColor ); + text_lines.emplace_back( "", Global.UITextColor ); + } if( 0 == table->StationCount ) { // only bother if there's stations to list text_lines.emplace_back( locale::strings[ locale::string::driver_timetable_notimetable ], Global.UITextColor ); } else { + auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; - text_lines.emplace_back("Brutto rozkl. " + to_string(table->LocLoad), Global.UITextColor); - auto fMass = owner->fMass / 1000; - if (owner->mvControlling->TrainType & (dt_DMU + dt_EZT) == 0) - { - //odejmij lokomotywy czynne, a przynajmniej aktualną - } - text_lines.emplace_back("Brutto rzecz. " + to_string(fMass,0), Global.UITextColor); - text_lines.emplace_back("Dl.poc. rzecz. " + to_string(owner->fLength,0), Global.UITextColor); - // header text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); diff --git a/translation.cpp b/translation.cpp index 1b1c85f5..09811e91 100644 --- a/translation.cpp +++ b/translation.cpp @@ -41,6 +41,7 @@ init() { "Timetable", "Time: %d:%02d:%02d", "(no timetable)", + "Consist weight: %d t (specified) %d t (actual)\nConsist length: %d m", "Transcripts", @@ -183,6 +184,7 @@ init() { "Rozklad jazdy", "Godzina: %d:%02d:%02d", "(brak rozkladu)", + "Brutto: %d t (rozkladowe) %d t (rzeczywiste)\nDlugosc pociagu: %d m", "Transkrypcje", diff --git a/translation.h b/translation.h index 6ca599b8..aa0ab028 100644 --- a/translation.h +++ b/translation.h @@ -30,6 +30,7 @@ enum string { driver_timetable_header, driver_timetable_time, driver_timetable_notimetable, + driver_timetable_consistdata, driver_transcripts_header, diff --git a/version.h b/version.h index e985f355..35fb08b2 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 129 +#define VERSION_MINOR 215 #define VERSION_REVISION 0 From bc60b5ac62f4fecbd7c00956eb9a5118e09f4da0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 19 Feb 2019 14:48:35 +0100 Subject: [PATCH 4/7] potential vbo render path crash fix, minor bug fixes --- Event.cpp | 13 ++++++++++--- Event.h | 6 ++++-- TrkFoll.cpp | 27 +++++++++++---------------- openglgeometrybank.cpp | 1 + 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/Event.cpp b/Event.cpp index c97b35f9..12593cdf 100644 --- a/Event.cpp +++ b/Event.cpp @@ -886,9 +886,14 @@ whois_event::run_() { auto *targetcell { static_cast( std::get( target ) ) }; if( targetcell == nullptr ) { continue; } // event effect code + // +24: vehicle type, consist brake level, obstacle distance + // +16: load type, load amount, max load amount + // +8: destination, direction, engine power + // +0: train name, station count, stop on next station if( m_input.flags & flags::load ) { + // +16 or +24 // jeśli pytanie o ładunek - if( m_input.flags & flags::mode_add ) { + if( m_input.flags & flags::mode_alt ) { // jeśli typ pojazdu // TODO: define and recognize individual request types auto const owner { ( @@ -912,7 +917,7 @@ whois_event::run_() { WriteLog( "Type: WhoIs (" + to_string( m_input.flags ) + ") - " - + "[name: " + m_activator->MoverParameters->TypeName + "], " + + "[type: " + m_activator->MoverParameters->TypeName + "], " + "[consist brake level: " + to_string( consistbrakelevel, 2 ) + "], " + "[obstacle distance: " + to_string( collisiondistance, 2 ) + " m]" ); } @@ -931,7 +936,8 @@ whois_event::run_() { + "[max load: " + to_string( m_activator->MoverParameters->MaxLoad, 2 ) + "]" ); } } - else if( m_input.flags & flags::mode_add ) { // jeśli miejsce docelowe pojazdu + // +8 + else if( m_input.flags & flags::mode_alt ) { // jeśli miejsce docelowe pojazdu targetcell->UpdateValues( m_activator->asDestination, // adres docelowy m_activator->DirectionGet(), // kierunek pojazdu względem czoła składu (1=zgodny,-1=przeciwny) @@ -944,6 +950,7 @@ whois_event::run_() { + "[direction: " + to_string( m_activator->DirectionGet() ) + "], " + "[engine power: " + to_string( m_activator->MoverParameters->Power, 2 ) + "]" ); } + // +0 else if( m_activator->Mechanik ) { if( m_activator->Mechanik->Primary() ) { // tylko jeśli ktoś tam siedzi - nie powinno dotyczyć pasażera! targetcell->UpdateValues( diff --git a/Event.h b/Event.h index 6a63ccef..59f82d75 100644 --- a/Event.h +++ b/Event.h @@ -25,8 +25,10 @@ public: value_1 = 1 << 1, value_2 = 1 << 2, // update values - load = 1 << 3, - mode_add = 1 << 4, + mode_add = 1 << 3, + // whois + mode_alt = 1 << 3, + load = 1 << 4, // condition values track_busy = 1 << 3, track_free = 1 << 4, diff --git a/TrkFoll.cpp b/TrkFoll.cpp index d7a8f3ee..77e4e2e3 100644 --- a/TrkFoll.cpp +++ b/TrkFoll.cpp @@ -96,10 +96,6 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) // bPrimary=true - jest pierwszą osią w pojeździe, czyli generuje eventy i przepisuje pojazd // Ra: zwraca false, jeśli pojazd ma być usunięty auto const ismoving { ( std::abs( fDistance ) > 0.01 ) && ( Owner->GetVelocity() > 0.01 ) }; - int const eventfilter { ( - ( ( true == ismoving ) && ( Owner->ctOwner != nullptr ) ) ? - Owner->ctOwner->Direction() * ( Owner->ctOwner->Vehicle()->DirectionGet() == Owner->DirectionGet() ? 1 : -1 ) * ( fDirection > 0 ? 1 : -1 ) : - 0 ) }; fDistance *= fDirection; // dystans mnożnony przez kierunek double s; // roboczy dystans double dir; // zapamiętany kierunek do sprawdzenia, czy się zmienił @@ -110,6 +106,13 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) // TODO: refactor following block as track method if( pCurrentTrack->m_events ) { // sumaryczna informacja o eventach // omijamy cały ten blok, gdy tor nie ma on żadnych eventów (większość nie ma) + int const eventfilter { ( + false == ismoving ? 0 : // only moving vehicles activate events type 1/2 + false == bPrimary ? 0 : // only primary axle activates events type 1/2 + Owner->ctOwner == nullptr ? + ( fDistance > 0 ? 1 : -1 ) : // loose vehicle has no means to determine 'intended' direction so the filter does effectively nothing in such case + ( fDirection > 0 ? 1 : -1 ) * Owner->ctOwner->Direction() * ( Owner->ctOwner->Vehicle()->DirectionGet() == Owner->DirectionGet() ? 1 : -1 ) ) }; + if( false == ismoving ) { //McZapkie-140602: wyzwalanie zdarzenia gdy pojazd stoi if( ( Owner->Mechanik != nullptr ) @@ -127,16 +130,12 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) && ( Owner->Mechanik->Primary() ) ) { // tylko dla jednego członu // McZapkie-280503: wyzwalanie event tylko dla pojazdow z obsada - if( true == bPrimary ) { - pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner ); - } + pCurrentTrack->QueueEvents( pCurrentTrack->m_events1, Owner ); } } if( SetFlag( iEventallFlag, -1 ) ) { // McZapkie-280503: wyzwalanie eventall dla wszystkich pojazdow - if( true == bPrimary ) { - pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner ); - } + pCurrentTrack->QueueEvents( pCurrentTrack->m_events1all, Owner ); } } else if( ( fDistance > 0 ) && ( eventfilter > 0 ) ) { @@ -146,16 +145,12 @@ bool TTrackFollower::Move(double fDistance, bool bPrimary) if( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->Primary() ) ) { // tylko dla jednego członu - if( true == bPrimary ) { - pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner ); - } + pCurrentTrack->QueueEvents( pCurrentTrack->m_events2, Owner ); } } if( SetFlag( iEventallFlag, -2 ) ) { // sprawdza i zeruje na przyszłość, true jeśli zmieni z 2 na 0 - if( true == bPrimary ) { - pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner ); - } + pCurrentTrack->QueueEvents( pCurrentTrack->m_events2all, Owner ); } } } diff --git a/openglgeometrybank.cpp b/openglgeometrybank.cpp index 358fe7b1..56bae61e 100644 --- a/openglgeometrybank.cpp +++ b/openglgeometrybank.cpp @@ -174,6 +174,7 @@ opengl_vbogeometrybank::draw_( gfx::geometry_handle const &Geometry, gfx::stream // try to set up the buffer we need ::glGenBuffers( 1, &m_buffer ); bind_buffer(); + if( m_buffer == 0 ) { return; } // if we didn't get a buffer we'll try again during the next draw call // NOTE: we're using static_draw since it's generally true for all we have implemented at the moment // TODO: allow to specify usage hint at the object creation, and pass it here ::glBufferData( From b72e237ab11bb096fe2bf8a24bbe02de1a97a2b8 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 23 Feb 2019 15:26:59 +0100 Subject: [PATCH 5/7] refactoring: obstacle detection system component separation, partial leverage of new structure --- Driver.cpp | 374 +++++++++----------- Driver.h | 1 + DynObj.cpp | 848 +++++++++++++++------------------------------ DynObj.h | 33 +- McZapkie/MOVER.h | 51 +-- McZapkie/Mover.cpp | 707 ++++++++++++++++--------------------- Train.cpp | 63 ++-- driveruipanels.cpp | 17 +- 8 files changed, 824 insertions(+), 1270 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 942a33e3..2f7a191b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1173,7 +1173,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN if( mvOccupied->Vel < 2.0 ) { // stanąć nie musi, ale zwolnić przynajmniej if( ( sSpeedTable[ i ].fDist < fMaxProximityDist ) - && ( TrackBlock() > 1000.0 ) ) { + && ( Obstacle.distance > 1000 ) ) { // jest w maksymalnym zasięgu to można go pominąć (wziąć drugą prędkosć) // as long as there isn't any obstacle in arbitrary view range eSignSkip = sSpeedTable[ i ].evEvent; @@ -1259,7 +1259,7 @@ 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 ) ) { + && ( sSpeedTable[ i ].fDist > Obstacle.distance - 20 ) ) { // jak sygnał jest dalej niż zawalidroga v = 0.0; // to może być podany dla tamtego: jechać tak, jakby tam stop był } @@ -2061,7 +2061,7 @@ bool TController::CheckVehicles(TOrders user) && ( p->MoverParameters->BrakeSubsystem != TBrakeSubSystem::ss_LSt ) ) { iDrivigFlags &= ~( moveOerlikons ); } - p = p->Neightbour(dir); // pojazd podłączony od wskazanej strony + p = p->Neighbour(dir); // pojazd podłączony od wskazanej strony } if (main) iDrivigFlags |= movePrimary; // nie znaleziono innego, można się porządzić @@ -2408,11 +2408,11 @@ bool TController::PrepareEngine() if( !iDirection ) { // jeśli nie ma ustalonego kierunku if( ( mvControlling->PantFrontVolt != 0.0 ) || ( mvControlling->PantRearVolt != 0.0 ) || voltfront || voltrear ) { - if( mvOccupied->Couplers[ 1 ].CouplingFlag == coupling::faux ) { + if( mvOccupied->Couplers[ end::rear ].Connected == nullptr ) { // jeśli z tyłu nie ma nic iDirection = -1; // jazda w kierunku sprzęgu 1 } - if( mvOccupied->Couplers[ 0 ].CouplingFlag == coupling::faux ) { + if( mvOccupied->Couplers[ end::front ].Connected == nullptr ) { // jeśli z przodu nie ma nic iDirection = 1; // jazda w kierunku sprzęgu 0 } @@ -2618,12 +2618,12 @@ bool TController::IncBrake() || ( mvOccupied->TrainType == dt_ET42 ) ) { // NOTE: we're doing simplified checks full of presuptions here. // they'll break if someone does strange thing like turning around the second unit - if( ( mvOccupied->Couplers[ 1 ].CouplingFlag & coupling::permanent ) - && ( mvOccupied->Couplers[ 1 ].Connected->Couplers[ 1 ].CouplingFlag > 0 ) ) { + if( ( mvOccupied->Couplers[ end::rear ].CouplingFlag & coupling::permanent ) + && ( mvOccupied->Couplers[ end::rear ].Connected->Couplers[ end::rear ].Connected != nullptr ) ) { standalone = false; } - if( ( mvOccupied->Couplers[ 0 ].CouplingFlag & coupling::permanent ) - && ( mvOccupied->Couplers[ 0 ].Connected->Couplers[ 0 ].CouplingFlag > 0 ) ) { + if( ( mvOccupied->Couplers[ end::front ].CouplingFlag & coupling::permanent ) + && ( mvOccupied->Couplers[ end::front ].Connected->Couplers[ end::front ].Connected != nullptr ) ) { standalone = false; } } @@ -2637,16 +2637,16 @@ bool TController::IncBrake() ( ( mvOccupied->Couplers[ 0 ].CouplingFlag == 0 ) && ( mvOccupied->Couplers[ 1 ].CouplingFlag == 0 ) ); */ - if( pVehicles[ 0 ] != pVehicles[ 1 ] ) { + if( pVehicles[ end::front ] != pVehicles[ end::rear ] ) { // more detailed version, will use manual braking also for coupled sets of controlled vehicles - auto *vehicle = pVehicles[ 0 ]; // start from first + auto *vehicle = pVehicles[ end::front ]; // start from first while( ( true == standalone ) && ( vehicle != nullptr ) ) { // NOTE: we could simplify this by doing only check of the rear coupler, but this can be quite tricky in itself // TODO: add easier ways to access front/rear coupler taking into account vehicle's direction standalone = - ( ( ( vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag == 0 ) || ( vehicle->MoverParameters->Couplers[ 0 ].CouplingFlag & coupling::control ) ) - && ( ( vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag == 0 ) || ( vehicle->MoverParameters->Couplers[ 1 ].CouplingFlag & coupling::control ) ) ); + ( ( ( vehicle->MoverParameters->Couplers[ end::front ].Connected == nullptr ) || ( vehicle->MoverParameters->Couplers[ end::front ].CouplingFlag & coupling::control ) ) + && ( ( vehicle->MoverParameters->Couplers[ end::rear ].Connected == nullptr ) || ( vehicle->MoverParameters->Couplers[ end::rear ].CouplingFlag & coupling::control ) ) ); vehicle = vehicle->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } } @@ -3625,22 +3625,21 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N } WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie } - else // if (NewValue2==0.0) //zerowy sprzęg - if (NewValue1 >= 0.0) // jeśli ilość wagonów inna niż wszystkie - { // będzie odczepianie, ale jeśli wagony są z przodu, to trzeba najpierw zmienić kierunek - if ((mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 1 : 0].CouplingFlag == - 0) ? // z tyłu nic - (mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 0 : 1].CouplingFlag > 0) : - false) // a z przodu skład - { - iDirectionOrder = -iDirection; // zmiana na ciągnięcie - OrderNext(Change_direction); // najpierw zmień kierunek (zastąpi Disconnect) - OrderPush(Disconnect); // a odczep już po zmianie kierunku + else { // if (NewValue2==0.0) //zerowy sprzęg + if( NewValue1 >= 0.0 ) { + // jeśli ilość wagonów inna niż wszystkie będzie odczepianie, + // ale jeśli wagony są z przodu, to trzeba najpierw zmienić kierunek + if( ( mvOccupied->Couplers[ mvOccupied->DirAbsolute > 0 ? end::rear : end::front ].Connected == nullptr ) // z tyłu nic + && ( mvOccupied->Couplers[ mvOccupied->DirAbsolute > 0 ? end::front : end::rear ].Connected != nullptr ) ) { // a z przodu skład + iDirectionOrder = -iDirection; // zmiana na ciągnięcie + OrderNext( Change_direction ); // najpierw zmień kierunek (zastąpi Disconnect) + OrderPush( Disconnect ); // a odczep już po zmianie kierunku + } + else if( mvOccupied->Couplers[ mvOccupied->DirAbsolute > 0 ? end::rear : end::front ].Connected != nullptr ) { // z tyłu coś + OrderNext( Disconnect ); // jak ciągnie, to tylko odczep (NewValue1) wagonów + } + WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie } - else if (mvOccupied->Couplers[mvOccupied->DirAbsolute > 0 ? 1 : 0].CouplingFlag > - 0) // z tyłu coś - OrderNext(Disconnect); // jak ciągnie, to tylko odczep (NewValue1) wagonów - WaitingTime = 0.0; // nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie } if (NewValue1 == -1.0) { @@ -4181,55 +4180,45 @@ TController::UpdateSituation(double dt) { // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji // - rzadziej). - // check for potential colliders + // check for potential collisions { - auto rearvehicle = ( - pVehicles[ 0 ] == pVehicles[ 1 ] ? - pVehicles[ 0 ] : - pVehicles[ 1 ] ); + // HACK: vehicle order in the consist is based on intended travel direction + // if our actual travel direction doesn't match that, we should be scanning from the other end of the consist + auto *frontvehicle { pVehicles[ ( mvOccupied->V * iDirection >= 0 ? end::front : end::rear ) ] }; + + int routescandirection; // for moving vehicle determine heading from velocity; for standing fall back on the set direction - if( ( std::abs( mvOccupied->V ) < 0.1 ? // ignore potential micro-stutters in oposite direction during "almost stop" + if( ( std::abs( frontvehicle->MoverParameters->V ) > 0.1 ? // ignore potential micro-stutters in oposite direction during "almost stop" + frontvehicle->MoverParameters->V > 0.0 : + ( pVehicle->DirectionGet() == frontvehicle->DirectionGet() ? iDirection > 0 : - mvOccupied->V > 0.0 ) ) { + iDirection < 0 ) ) ) { // towards coupler 0 - if( ( mvOccupied->V * iDirection < 0.0 ) - || ( ( rearvehicle->NextConnected != nullptr ) - && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 1 : 0 ) ].CouplingFlag == coupling::faux ) ) ) { - // scan behind if we're moving backward, or if we had something connected there and are moving away - rearvehicle->ABuScanObjects( ( - pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? - -1 : - 1 ), - fMaxProximityDist ); - } - pVehicles[ 0 ]->ABuScanObjects( ( - pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? - 1 : - -1 ), - routescanrange ); + routescandirection = end::front; } else { // towards coupler 1 - if( ( mvOccupied->V * iDirection < 0.0 ) - || ( ( rearvehicle->PrevConnected != nullptr ) - && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 0 : 1 ) ].CouplingFlag == coupling::faux ) ) ) { - // scan behind if we're moving backward, or if we had something connected there and are moving away - rearvehicle->ABuScanObjects( ( - pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? - 1 : - -1 ), - fMaxProximityDist ); + routescandirection = end::rear; + } + + Obstacle = neighbour_data(); + auto const lookup { frontvehicle->find_vehicle( routescandirection, routescanrange ) }; + + if( std::get( lookup ) == true ) { + + Obstacle.vehicle = std::get( lookup ); + Obstacle.vehicle_end = std::get( lookup ); + Obstacle.distance = std::get( lookup ); + + if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 25 : 75 ) ) { + // at short distances (re)calculate range between couplers directly + Obstacle.distance = TMoverParameters::CouplerDist( frontvehicle->MoverParameters, Obstacle.vehicle->MoverParameters ); } - pVehicles[ 0 ]->ABuScanObjects( ( - pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? - -1 : - 1 ), - routescanrange ); + } + else { + Obstacle.distance = 10000; // legacy value. TBD, TODO: use standard -1 instead? } } - - - // tu bedzie logika sterowania if (AIControllFlag) { @@ -4291,37 +4280,17 @@ TController::UpdateSituation(double dt) { if (AIControllFlag) { // to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić // sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec - 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 - { // sprzęg 0 - próba podczepienia - if( pVehicles[ 0 ]->MoverParameters->Couplers[ 0 ].Connected ) { - // jeśli jest coś wykryte (a chyba jest, nie?) - if( pVehicles[ 0 ]->MoverParameters->Attach( - 0, 2, pVehicles[ 0 ]->MoverParameters->Couplers[ 0 ].Connected, - iCoupler ) ) { - // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - } - // udało się? (mogło częściowo) - ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag == iCoupler); - } - else // if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 - { // sprzęg 1 - próba podczepienia - if( pVehicles[ 0 ]->MoverParameters->Couplers[ 1 ].Connected ) { - // jeśli jest coś wykryte (a chyba jest, nie?) - if( pVehicles[ 0 ]->MoverParameters->Attach( - 1, 2, pVehicles[ 0 ]->MoverParameters->Couplers[ 1 ].Connected, - iCoupler ) ) { - // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - } - // udało się? (mogło częściowo) - ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag == iCoupler); - } - if (ok) - { // jeżeli został podłączony + auto *vehicle { pVehicles[ end::front ] }; + auto *vehicleparameters { vehicle->MoverParameters }; + int const end { ( vehicle->DirectionGet() > 0 ? end::front : end::rear ) }; + auto const &neighbour { vehicleparameters->Neighbours[ end ] }; + // próba podczepienia + vehicleparameters->Attach( + end, neighbour.vehicle_end, + neighbour.vehicle->MoverParameters, + iCoupler ); + if( vehicleparameters->Couplers[ end ].CouplingFlag == iCoupler ) { + // jeżeli został podłączony iCoupler = 0; // dalsza jazda manewrowa już bez łączenia iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie @@ -4337,7 +4306,7 @@ TController::UpdateSituation(double dt) { fMaxProximityDist = 5.0; //[m] w takim przedziale odległości powinien stanąć 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 - if( pVehicles[ 0 ]->fTrackBlock <= 20.0 ) { + if( Obstacle.distance <= 20.0 ) { // przy zderzeniu fTrackBlock nie jest miarodajne // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock iDrivigFlags |= moveConnect; @@ -4477,8 +4446,8 @@ TController::UpdateSituation(double dt) { && ( false == TestFlag( iDrivigFlags, movePress ) ) && ( iCoupler == 0 ) // && ( mvOccupied->Vel > 0.0 ) - && ( pVehicle->MoverParameters->Couplers[ end::front ].CouplingFlag == coupling::faux ) - && ( pVehicle->MoverParameters->Couplers[ end::rear ].CouplingFlag == coupling::faux ) ) { + && ( pVehicle->MoverParameters->Couplers[ end::front ].Connected == nullptr ) + && ( pVehicle->MoverParameters->Couplers[ end::rear ].Connected == nullptr ) ) { SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie // WriteLog("Zatrzymanie w celu odczepienia"); AccPreferred = std::min( 0.0, AccPreferred ); @@ -4516,7 +4485,7 @@ TController::UpdateSituation(double dt) { else { // samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję if (eStopReason == stopBlock) - if (pVehicles[0]->fTrackBlock > fDriverDist) + if (Obstacle.distance > fDriverDist) if (AIControllFlag) { PrepareEngine(); // zmieni ustawiony kierunek @@ -4668,7 +4637,8 @@ TController::UpdateSituation(double dt) { n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone } } while (n--); - if( p ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) { + if( ( p == nullptr ) + || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { // no target, or already just virtual coupling WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); iVehicleCount = -2; // odczepiono, co było do odczepienia @@ -4759,9 +4729,9 @@ TController::UpdateSituation(double dt) { // w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia // Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by // było porównać z odległością od sygnalizatora z przodu - if( ( OrderList[ OrderPos ] & Connect ) ? - ( pVehicles[ 0 ]->fTrackBlock > 2000 || pVehicles[ 0 ]->fTrackBlock > FirstSemaphorDist ) : - true ) { + if( ( ( OrderList[ OrderPos ] & Connect ) == 0 ) + || ( Obstacle.distance > std::min( 2000.0, FirstSemaphorDist ) ) ) { + if( ( comm = BackwardScan() ) != TCommandType::cm_Unknown ) { // jeśli w drugą można jechać // należy sprawdzać odległość od znalezionego sygnalizatora, @@ -4786,121 +4756,99 @@ TController::UpdateSituation(double dt) { VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną // Ra: jazda na widoczność -/* - // 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ść - 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 == coupling::faux ) ) { - // mamy coś z przodu podłączone sprzęgiem wirtualnym - // wyliczanie optymalnego przyspieszenia do jazdy na widoczność -/* - ActualProximityDist = std::min( + if( Obstacle.distance < 5000 ) { + // mamy coś z przodu + // prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!) + auto const k { Obstacle.vehicle->MoverParameters->Vel }; + if( k - vel < 5 ) { + // porównanie modułów prędkości [km/h] + // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej + ActualProximityDist = std::min( ActualProximityDist, - vehicle->fTrackBlock - ( - mvOccupied->CategoryFlag & 2 ? - fMinProximityDist : // cars can bunch up tighter - fMaxProximityDist ) ); // other vehicle types less so -*/ - // prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!) - double k = coupler->Connected->Vel; - if( k - vel < 5 ) { - // porównanie modułów prędkości [km/h] - // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej - ActualProximityDist = std::min( - ActualProximityDist, - vehicle->fTrackBlock ); + Obstacle.distance ); - if( ActualProximityDist <= ( - ( mvOccupied->CategoryFlag & 2 ) ? - 100.0 : // cars - 250.0 ) ) { // others - // regardless of driving mode at close distance take precaution measures: - // match the other vehicle's speed or slow down if the other vehicle is stopped - VelDesired = - min_speed( - VelDesired, - std::max( - k, - ( mvOccupied->CategoryFlag & 2 ) ? - 40.0 : // cars - 20.0 ) ); // others - if( vel > VelDesired + fVelPlus ) { - // if going too fast force some prompt braking - AccPreferred = std::min( -0.65, AccPreferred ); - } + if( ActualProximityDist <= ( + ( mvOccupied->CategoryFlag & 2 ) ? + 100.0 : // cars + 250.0 ) ) { // others + // regardless of driving mode at close distance take precaution measures: + // match the other vehicle's speed or slow down if the other vehicle is stopped + VelDesired = + min_speed( + VelDesired, + std::max( + k, + ( mvOccupied->CategoryFlag & 2 ) ? + 40.0 : // cars + 20.0 ) ); // others + if( vel > VelDesired + fVelPlus ) { + // if going too fast force some prompt braking + AccPreferred = std::min( -0.65, AccPreferred ); } + } - double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości - if( distance < 0.0 ) { - // jeśli odległość jest zbyt mała - 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.35, AccPreferred ); // nie hamuj - VelDesired = - min_speed( - VelDesired, - ( vehicle->fTrackBlock > 150.0 ? - 20.0: - 4.0 ) ); - VelNext = 2.0; // i pakuj się na tamtego - } - else { - // a normalnie to hamować - VelNext = 0.0; - if( vehicle->fTrackBlock <= fMinProximityDist ) { - VelDesired = 0.0; - } - - if( ( mvOccupied->CategoryFlag & 1 ) - && ( OrderCurrentGet() & Obey_train ) ) { - // trains which move normally should try to stop at safe margin - ActualProximityDist -= fDriverDist; - } - } - } - 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 = min_speed( 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; - } - } - } - ReactionTime = ( - mvOccupied->Vel > 0.01 ? - 0.1 : // orientuj się, bo jest goraco - 2.0 ); // we're already standing still, so take it easy - } - else { + double const distance = Obstacle.distance - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości + if( distance < 0.0 ) { + // jeśli odległość jest zbyt mała + 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 ) { - // if there's something nearby in the connect mode don't speed up too much + // jeśli spinanie, to jechać dalej + AccPreferred = std::min( 0.35, AccPreferred ); // nie hamuj VelDesired = min_speed( VelDesired, - ( vehicle->fTrackBlock > 100.0 ? - 20.0 : + ( Obstacle.distance > 150 ? + 20.0: 4.0 ) ); + VelNext = 2.0; // i pakuj się na tamtego } + else { + // a normalnie to hamować + VelNext = 0.0; + if( Obstacle.distance <= fMinProximityDist ) { + VelDesired = 0.0; + } + + if( ( mvOccupied->CategoryFlag & 1 ) + && ( OrderCurrentGet() & Obey_train ) ) { + // trains which move normally should try to stop at safe margin + ActualProximityDist -= fDriverDist; + } + } + } + else { + // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość + if( Obstacle.distance < ( + ( 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 = min_speed( std::round( k ) - 5.0, VelDesired ); + if( Obstacle.distance <= ( + ( mvOccupied->CategoryFlag & 2 ) ? + fMaxProximityDist : // cars + 2.0 * fMaxProximityDist ) ) { //others + // try to force speed change if obstacle is really close + VelDesired = VelNext; + } + } + } + ReactionTime = ( + mvOccupied->Vel > 0.01 ? + 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 = + min_speed( + VelDesired, + ( Obstacle.distance > 100 ? + 20.0 : + 4.0 ) ); } } } @@ -5060,7 +5008,7 @@ TController::UpdateSituation(double dt) { if( mvOccupied->CategoryFlag & 1 ) { // trains if( ( OrderCurrentGet() & ( Shunt | Connect ) ) - && ( pVehicles[0]->fTrackBlock < 50.0 ) ) { + && ( Obstacle.distance < 50 ) ) { // crude detection of edge case, if approaching another vehicle coast slowly until min distance // this should allow to bunch up trainsets more on sidings VelDesired = min_speed( 5.0, VelDesired ); @@ -6344,7 +6292,7 @@ bool TController::IsStop() const double TController::TrackBlock() const { - return pVehicles[ end::front ]->fTrackBlock; + return Obstacle.distance; } void TController::MoveTo(TDynamicObject *to) diff --git a/Driver.h b/Driver.h index 48bd4a15..88052fc0 100644 --- a/Driver.h +++ b/Driver.h @@ -376,6 +376,7 @@ private: std::size_t SemNextStopIndex{ std::size_t( -1 ) }; double dMoveLen = 0.0; // odległość przejechana od ostatniego sprawdzenia tabelki basic_event *eSignNext = nullptr; // sygnał zmieniający prędkość, do pokazania na [F2] + neighbour_data Obstacle; // nearest vehicle detected ahead on current route // timetable // methods diff --git a/DynObj.cpp b/DynObj.cpp index 37bb522e..870e9ee4 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -171,24 +171,24 @@ TDynamicObject * TDynamicObject::FirstFind(int &coupler_nr, int cf) return NULL; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & cf) != cf) return temp; // nic nie ma już dalej podłączone sprzęgiem cf - if (coupler_nr == 0) + if (coupler_nr == end::front) { // jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) // jeśli mamy coś z przodu + if (temp->PrevConnected()) // jeśli mamy coś z przodu { - if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + if (temp->PrevConnectedNo() == end::front) // jeśli pojazd od strony sprzęgu 0 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->PrevConnected; // ten jest od strony 0 + temp = temp->PrevConnected(); // ten jest od strony 0 } else return temp; // jeśli jednak z przodu nic nie ma } else { - if (temp->NextConnected) + if (temp->NextConnected()) { - if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + if (temp->NextConnectedNo() == end::rear) // jeśli pojazd od strony sprzęgu 1 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->NextConnected; // ten pojazd jest od strony 1 + temp = temp->NextConnected(); // ten pojazd jest od strony 1 } else return temp; // jeśli jednak z tyłu nic nie ma @@ -199,8 +199,7 @@ TDynamicObject * TDynamicObject::FirstFind(int &coupler_nr, int cf) //--------------------------------------------------------------------------- float TDynamicObject::GetEPP() -{ // szukanie skrajnego połączonego pojazdu w - // pociagu +{ // szukanie skrajnego połączonego pojazdu w pociagu // od strony sprzegu (coupler_nr) obiektu (start) TDynamicObject *temp = this; int coupler_nr = 0; @@ -213,26 +212,26 @@ float TDynamicObject::GetEPP() break; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów eq += temp->MoverParameters->PipePress * temp->MoverParameters->Dim.L; am += temp->MoverParameters->Dim.L; - if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & 2) != 2) + if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & coupling::brakehose) != coupling::brakehose) break; // nic nie ma już dalej podłączone if (coupler_nr == 0) { // jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) // jeśli mamy coś z przodu + if (temp->PrevConnected()) // jeśli mamy coś z przodu { - if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + if (temp->PrevConnectedNo() == end::front) // jeśli pojazd od strony sprzęgu 0 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->PrevConnected; // ten jest od strony 0 + temp = temp->PrevConnected(); // ten jest od strony 0 } else break; // jeśli jednak z przodu nic nie ma } else { - if (temp->NextConnected) + if (temp->NextConnected()) { - if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + if (temp->NextConnectedNo() == end::rear) // jeśli pojazd od strony sprzęgu 1 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->NextConnected; // ten pojazd jest od strony 1 + temp = temp->NextConnected(); // ten pojazd jest od strony 1 } else break; // jeśli jednak z tyłu nic nie ma @@ -247,26 +246,26 @@ float TDynamicObject::GetEPP() break; // Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów eq += temp->MoverParameters->PipePress * temp->MoverParameters->Dim.L; am += temp->MoverParameters->Dim.L; - if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & 2) != 2) + if ((temp->MoverParameters->Couplers[coupler_nr].CouplingFlag & coupling::brakehose) != coupling::brakehose) break; // nic nie ma już dalej podłączone if (coupler_nr == 0) { // jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnected) // jeśli mamy coś z przodu + if (temp->PrevConnected()) // jeśli mamy coś z przodu { - if (temp->PrevConnectedNo == 0) // jeśli pojazd od strony sprzęgu 0 jest odwrócony + if (temp->PrevConnectedNo() == end::front) // jeśli pojazd od strony sprzęgu 0 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->PrevConnected; // ten jest od strony 0 + temp = temp->PrevConnected(); // ten jest od strony 0 } else break; // jeśli jednak z przodu nic nie ma } else { - if (temp->NextConnected) + if (temp->NextConnected()) { - if (temp->NextConnectedNo == 1) // jeśli pojazd od strony sprzęgu 1 jest odwrócony + if (temp->NextConnectedNo() == end::rear) // jeśli pojazd od strony sprzęgu 1 jest odwrócony coupler_nr = 1 - coupler_nr; // to zmieniamy kierunek sprzęgu - temp = temp->NextConnected; // ten pojazd jest od strony 1 + temp = temp->NextConnected(); // ten pojazd jest od strony 1 } else break; // jeśli jednak z tyłu nic nie ma @@ -285,40 +284,6 @@ TDynamicObject * TDynamicObject::GetFirstDynamic(int cpl_type, int cf) return FirstFind(cpl_type, cf); // używa referencji }; -/* -TDynamicObject* TDynamicObject::GetFirstCabDynamic(int cpl_type) -{//ZiomalCl: szukanie skrajnego obiektu z kabiną - TDynamicObject* temp=this; - int coupler_nr=cpl_type; - for (int i=0;i<300;i++) //ograniczenie do 300 na wypadek zapętlenia składu - { - if (!temp) - return NULL; //Ra: zabezpieczenie przed ewentaulnymi błędami sprzęgów - if (temp->MoverParameters->CabNo!=0&&temp->MoverParameters->SandCapacity!=0) - return temp; //nic nie ma już dalej podłączone - if (temp->MoverParameters->Couplers[coupler_nr].CouplingFlag==0) - return NULL; - if (coupler_nr==0) - {//jeżeli szukamy od sprzęgu 0 - if (temp->PrevConnectedNo==0) //jeśli pojazd od strony sprzęgu 0 jest -odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - if (temp->PrevConnected) - temp=temp->PrevConnected; //ten jest od strony 0 - } - else - { - if (temp->NextConnectedNo==1) //jeśli pojazd od strony sprzęgu 1 jest -odwrócony - coupler_nr=1-coupler_nr; //to zmieniamy kierunek sprzęgu - if (temp->NextConnected) - temp=temp->NextConnected; //ten pojazd jest od strony 1 - } - } - return NULL; //to tylko po wyczerpaniu pętli -}; -*/ - void TDynamicObject::ABuSetModelShake( Math3D::vector3 mShake ) { modelShake = mShake; @@ -368,11 +333,11 @@ void TDynamicObject::SetPneumatic(bool front, bool red) tamten = 0; ten = GetPneumatic(front, red); // 1=lewy skos,2=prawy skos,3=dwa proste if (front) - if (PrevConnected) // pojazd od strony sprzęgu 0 - tamten = PrevConnected->GetPneumatic((PrevConnectedNo == 0 ? true : false), red); + if (PrevConnected()) // pojazd od strony sprzęgu 0 + tamten = PrevConnected()->GetPneumatic((PrevConnectedNo() == end::front ? true : false), red); if (!front) - if (NextConnected) // pojazd od strony sprzęgu 1 - tamten = NextConnected->GetPneumatic((NextConnectedNo == 0 ? true : false), red); + if (NextConnected()) // pojazd od strony sprzęgu 1 + tamten = NextConnected()->GetPneumatic((NextConnectedNo() == end::front ? true : false), red); if (ten == tamten) // jeśli układ jest symetryczny switch (ten) { @@ -383,7 +348,7 @@ void TDynamicObject::SetPneumatic(bool front, bool red) x = 3; break; // mamy prawy skos, dać prawe skosy case 3: // wszystkie cztery na prosto - if (MoverParameters->Couplers[front ? 0 : 1].Render) + if (MoverParameters->Couplers[front ? end::front : end::rear].Render) x = 1; else x = 4; @@ -697,15 +662,15 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // ABu-240105: Dodatkowy warunek: if (...).Render, zeby rysowal tylko // jeden // z polaczonych sprzegow - if ((TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_coupler)) && - (MoverParameters->Couplers[0].Render)) + if ((TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_coupler)) && + (MoverParameters->Couplers[end::front].Render)) { btCoupler1.Turn( true ); btnOn = true; } // else btCoupler1.TurnOff(); - if ((TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_coupler)) && - (MoverParameters->Couplers[1].Render)) + if ((TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_coupler)) && + (MoverParameters->Couplers[end::rear].Render)) { btCoupler2.Turn( true ); btnOn = true; @@ -723,7 +688,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) SetPneumatic(true, true); // ktore z nich nalezy SetPneumatic(false, true); // wyswietlic w tej klatce - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_pneumatic)) + if (TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_pneumatic)) { switch (cp1) { @@ -743,7 +708,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) btnOn = true; } - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_pneumatic)) + if (TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_pneumatic)) { switch (cp2) { @@ -764,7 +729,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) } // przewody zasilajace, j.w. (yB) - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_scndpneumatic)) + if (TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_scndpneumatic)) { switch (sp1) { @@ -784,7 +749,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) btnOn = true; } - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_scndpneumatic)) + if (TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_scndpneumatic)) { switch (sp2) { @@ -809,18 +774,18 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) { // przewody powietrzne j.w., ABu: decyzja czy rysowac tylko na podstawie // 'render' - if (TestFlag(MoverParameters->Couplers[0].CouplingFlag, ctrain_pneumatic)) + if (TestFlag(MoverParameters->Couplers[end::front].CouplingFlag, ctrain_pneumatic)) { - if (MoverParameters->Couplers[0].Render) + if (MoverParameters->Couplers[end::front].Render) btCPneumatic1.TurnOn(); else btCPneumatic1r.TurnOn(); btnOn = true; } - if (TestFlag(MoverParameters->Couplers[1].CouplingFlag, ctrain_pneumatic)) + if (TestFlag(MoverParameters->Couplers[end::rear].CouplingFlag, ctrain_pneumatic)) { - if (MoverParameters->Couplers[1].Render) + if (MoverParameters->Couplers[end::rear].Render) btCPneumatic2.TurnOn(); else btCPneumatic2r.TurnOn(); @@ -1214,7 +1179,7 @@ void TDynamicObject::ABuCheckMyTrack() // Ra: w poniższej funkcji jest problem ze sprzęgami TDynamicObject * -TDynamicObject::ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ) +TDynamicObject::ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ) const { // 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ę. @@ -1347,6 +1312,14 @@ int TDynamicObject::Dettach(int dir) if( MoverParameters->Couplers[ dir ].CouplingFlag ) { // odczepianie, o ile coś podłączone MoverParameters->Dettach( dir ); +/* + if( true == MoverParameters->Dettach( dir ) ) { + auto *othervehicle { dir ? NextConnected : PrevConnected }; + auto const othercoupler { dir ? NextConnectedNo() : PrevConnectedNo() }; + ( othercoupler ? othervehicle->NextConnected : othervehicle->PrevConnected ) = nullptr; + ( dir ? NextConnected : PrevConnected ) = nullptr; + }; +*/ } // sprzęg po rozłączaniu (czego się nie da odpiąć return MoverParameters->Couplers[dir].CouplingFlag; @@ -1355,16 +1328,23 @@ int TDynamicObject::Dettach(int dir) void TDynamicObject::couple( int const Side ) { - if( MoverParameters->Couplers[ Side ].Connected == nullptr ) { return; } + auto const &neighbour { MoverParameters->Neighbours[ Side ] }; - if( MoverParameters->Couplers[ Side ].CouplingFlag == coupling::faux ) { + if( neighbour.vehicle == nullptr ) { return; } + + auto const &coupler { MoverParameters->Couplers[ Side ] }; + auto *othervehicle { neighbour.vehicle }; + auto *othervehicleparams{ othervehicle->MoverParameters }; + auto const &othercoupler { othervehicleparams->Couplers[ Side ] }; + + if( coupler.CouplingFlag == coupling::faux ) { // najpierw hak - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::coupler ) == coupling::coupler ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, + Side, neighbour.vehicle_end, + othervehicleparams, coupling::coupler ) ) { // one coupling type per key press return; @@ -1376,20 +1356,15 @@ TDynamicObject::couple( int const Side ) { } if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::brakehose ) ) { // pneumatyka - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::brakehose ) == coupling::brakehose ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, - ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::brakehose ) ) ) { + Side, neighbour.vehicle_end, + othervehicleparams, + ( coupler.CouplingFlag | coupling::brakehose ) ) ) { SetPneumatic( Side != 0, true ); - if( Side == end::front ) { - PrevConnected->SetPneumatic( Side != 0, true ); - } - else { - NextConnected->SetPneumatic( Side != 0, true ); - } + othervehicle->SetPneumatic( Side != 0, true ); // one coupling type per key press return; } @@ -1397,20 +1372,15 @@ TDynamicObject::couple( int const Side ) { } if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::mainhose ) ) { // zasilajacy - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::mainhose ) == coupling::mainhose ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, - ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::mainhose ) ) ) { + Side, neighbour.vehicle_end, + othervehicleparams, + ( coupler.CouplingFlag | coupling::mainhose ) ) ) { SetPneumatic( Side != 0, false ); - if( Side == end::front ) { - PrevConnected->SetPneumatic( Side != 0, false ); - } - else { - NextConnected->SetPneumatic( Side != 0, false ); - } + othervehicle->SetPneumatic( Side != 0, false ); // one coupling type per key press return; } @@ -1418,13 +1388,13 @@ TDynamicObject::couple( int const Side ) { } if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::control ) ) { // ukrotnionko - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::control ) == coupling::control ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, - ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::control ) ) ) { + Side, neighbour.vehicle_end, + othervehicleparams, + ( coupler.CouplingFlag | coupling::control ) ) ) { // one coupling type per key press return; } @@ -1432,13 +1402,13 @@ TDynamicObject::couple( int const Side ) { } if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::gangway ) ) { // mostek - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::gangway ) == coupling::gangway ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, - ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::gangway ) ) ) { + Side, neighbour.vehicle_end, + othervehicleparams, + ( coupler.CouplingFlag | coupling::gangway ) ) ) { // one coupling type per key press return; } @@ -1446,13 +1416,13 @@ TDynamicObject::couple( int const Side ) { } if( false == TestFlag( MoverParameters->Couplers[ Side ].CouplingFlag, coupling::heating ) ) { // heating - if( ( MoverParameters->Couplers[ Side ].Connected->Couplers[ Side ].AllowedFlag - & MoverParameters->Couplers[ Side ].AllowedFlag + if( ( coupler.AllowedFlag + & othercoupler.AllowedFlag & coupling::heating ) == coupling::heating ) { if( MoverParameters->Attach( - Side, 2, - MoverParameters->Couplers[ Side ].Connected, - ( MoverParameters->Couplers[ Side ].CouplingFlag | coupling::heating ) ) ) { + Side, neighbour.vehicle_end, + othervehicleparams, + ( coupler.CouplingFlag | coupling::heating ) ) ) { // one coupling type per key press return; } @@ -1474,226 +1444,9 @@ TDynamicObject::uncouple( int const Side ) { return couplingflag; } -void TDynamicObject::CouplersDettach(double MinDist, int MyScanDir) { - // funkcja rozłączajaca podłączone sprzęgi, jeśli odległość przekracza (MinDist) - // MinDist - dystans minimalny, dla ktorego mozna rozłączać - if (MyScanDir > 0) { - // pojazd od strony sprzęgu 0 - if( ( PrevConnected != nullptr ) - && ( MoverParameters->Couplers[ end::front ].CoupleDist > MinDist ) ) { - // sprzęgi wirtualne zawsze przekraczają - if( ( PrevConnectedNo == end::front ? - PrevConnected->PrevConnected : - PrevConnected->NextConnected ) - == this ) { - // Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony - // (może jechać w innym kierunku) - PrevConnected->MoverParameters->Couplers[PrevConnectedNo].Connected = nullptr; - if( PrevConnectedNo == end::front ) { - // sprzęg 0 nie podłączony - PrevConnected->PrevConnectedNo = 2; - PrevConnected->PrevConnected = nullptr; - } - else if( PrevConnectedNo == end::rear ) { - // sprzęg 1 nie podłączony - PrevConnected->NextConnectedNo = 2; - PrevConnected->NextConnected = nullptr; - } - } - // za to zawsze odłączamy siebie - PrevConnected = nullptr; - PrevConnectedNo = 2; // sprzęg 0 nie podłączony - MoverParameters->Couplers[ end::front ].Connected = nullptr; - } - } - else { - // pojazd od strony sprzęgu 1 - if( ( NextConnected != nullptr ) - && ( MoverParameters->Couplers[ end::rear ].CoupleDist > MinDist ) ) { - // sprzęgi wirtualne zawsze przekraczają - if( ( NextConnectedNo == end::front ? - NextConnected->PrevConnected : - NextConnected->NextConnected ) - == this) { - // Ra: nie rozłączamy znalezionego, jeżeli nie do nas podłączony - // (może jechać w innym kierunku) - NextConnected->MoverParameters->Couplers[ NextConnectedNo ].Connected = nullptr; - if( NextConnectedNo == end::front ) { - // sprzęg 0 nie podłączony - NextConnected->PrevConnectedNo = 2; - NextConnected->PrevConnected = nullptr; - } - else if( NextConnectedNo == end::rear ) { - // sprzęg 1 nie podłączony - NextConnected->NextConnectedNo = 2; - NextConnected->NextConnected = nullptr; - } - } - // za to zawsze odłączamy siebie - NextConnected = nullptr; - NextConnectedNo = 2; // sprzęg 1 nie podłączony - MoverParameters->Couplers[1].Connected = nullptr; - } - } -} - -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 - auto const initialdirection = Direction; // zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów - - TTrack const *track = RaTrackGet(); - if( RaDirectionGet() < 0 ) { - // czy oś jest ustawiona w stronę Point1? - Direction = -Direction; - } - - // (teraz względem toru) - 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( foundobject == nullptr ) { - // jeśli nie ma na tym samym, szukamy po okolicy szukanie najblizszego toru z jakims obiektem - // praktycznie przeklejone z TraceRoute()... - if (Direction >= 0) // uwzględniamy kawalek przeanalizowanego wcześniej toru - distance = track->Length() - RaTranslationGet(); // odległość osi od Point2 toru - else - distance = RaTranslationGet(); // 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 - Direction = -Direction; // to zmieniamy kierunek szukania na tym torze - } - track = track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik - } - 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 - 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. - 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 == end::front ) { - PrevConnected = foundobject; // pojazd od strony sprzęgu 0 - PrevConnectedNo = foundcoupler; - } - else { - NextConnected = foundobject; // pojazd od strony sprzęgu 1 - NextConnectedNo = foundcoupler; - } - - if( foundobject->MoverParameters->Couplers[ foundcoupler ].CouplingFlag == coupling::faux ) { - // Ra: wpinamy się wirtualnym tylko jeśli znaleziony ma wirtualny sprzęg - if( ( foundcoupler == end::front ? - foundobject->PrevConnected : - foundobject->NextConnected ) - != this ) { - // but first break existing connection of the target, - // otherwise we risk leaving the target's connected vehicle with active one-side connection - foundobject->CouplersDettach( - 1.0, - ( foundcoupler == end::front ? - 1 : - -1 ) ); - } - foundobject->MoverParameters->Attach( foundcoupler, mycoupler, this->MoverParameters, coupling::faux ); - - if( foundcoupler == end::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 ) - && ( 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; - } - } - - // NOTE: the distance we get is approximated as it's measured between active axles, not vehicle ends - fTrackBlock = distance; - if( distance < 100.0 ) { - // at short distances start to calculate range between couplers directly - // odległość do najbliższego pojazdu w linii prostej - fTrackBlock = MoverParameters->Couplers[ mycoupler ].CoupleDist; - } - if( ( false == TestFlag( track->iCategoryFlag, 1 ) ) - && ( distance > 50.0 ) ) { - // 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! - // NOTE: the distance is approximated, and additionally less accurate for cars heading in opposite direction - fTrackBlock = distance - ( 0.5 * ( MoverParameters->Dim.L + foundobject->MoverParameters->Dim.L ) ); - } - } - else { - // nic nie znalezione, to nie ma przeszkód - fTrackBlock = 10000.0; - } - -#ifdef EU07_DEBUG_COLLISIONS - // debug collider scans - if( ( PrevConnected != nullptr ) - && ( PrevConnected == NextConnected ) ) { - ErrorLog( "Bad coupling: " + asName + " has the same vehicle detected attached to both couplers" ); - } -#endif -} -//----------ABu: koniec skanowania pojazdow - TDynamicObject::TDynamicObject() { modelShake = Math3D::vector3(0, 0, 0); - fTrackBlock = 10000.0; // brak przeszkody na drodze +// fTrackBlock = 10000.0; // brak przeszkody na drodze btnOn = false; vUp = vWorldUp; vFront = vWorldFront; @@ -1705,8 +1458,8 @@ TDynamicObject::TDynamicObject() { // McZapkie-270202 Controller = AIdriver; bDisplayCab = false; // 030303 - NextConnected = PrevConnected = NULL; - NextConnectedNo = PrevConnectedNo = 2; // ABu: Numery sprzegow. 2=nie podłączony +// NextConnected = PrevConnected = NULL; +// NextConnectedNo = PrevConnectedNo = 2; // ABu: Numery sprzegow. 2=nie podłączony bEnabled = true; MyTrack = NULL; // McZapkie-260202 @@ -2437,16 +2190,10 @@ void TDynamicObject::Move(double fDistance) // if () na przechyłce będzie dodatkowo zmiana wysokości samochodu vPosition.y += MoverParameters->OffsetTrackV; // te offsety są liczone przez moverparam } - // Ra: skopiowanie pozycji do fizyki, tam potrzebna do zrywania sprzęgów - // MoverParameters->Loc.X=-vPosition.x; //robi to {Fast}ComputeMovement() - // MoverParameters->Loc.Y= vPosition.z; - // 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[end::front] = vPosition + dir; // współrzędne sprzęgu na początku vCoulpler[end::rear] = vPosition - dir; // współrzędne sprzęgu na końcu - MoverParameters->vCoulpler[end::front] = vCoulpler[end::front]; // tymczasowo kopiowane na inny poziom - MoverParameters->vCoulpler[end::rear] = vCoulpler[end::rear]; // bCameraNear= // if (bCameraNear) //jeśli istotne są szczegóły (blisko kamery) { // przeliczenie cienia @@ -2518,74 +2265,19 @@ void TDynamicObject::Move(double fDistance) }; void TDynamicObject::AttachPrev(TDynamicObject *Object, int iType) -{ // Ra: doczepia Object na końcu - // składu (nazwa funkcji może być - // myląca) +{ // Ra: doczepia Object na końcu składu (nazwa funkcji może być myląca) // Ra: używane tylko przy wczytywaniu scenerii - /* - //Ra: po wstawieniu pojazdu do scenerii nie miał on ustawionej pozycji, teraz - już ma - TLocation loc; - loc.X=-vPosition.x; - loc.Y=vPosition.z; - loc.Z=vPosition.y; - MoverParameters->Loc=loc; //Ra: do obliczania sprzęgów, na starcie nie są - przesunięte - loc.X=-Object->vPosition.x; - loc.Y=Object->vPosition.z; - loc.Z=Object->vPosition.y; - Object->MoverParameters->Loc=loc; //ustawienie dodawanego pojazdu - */ - MoverParameters->Attach(iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true, false); - MoverParameters->Couplers[iDirection].Render = false; - Object->MoverParameters->Attach(Object->iDirection ^ 1, iDirection, MoverParameters, iType, true, false); - Object->MoverParameters->Couplers[Object->iDirection ^ 1].Render = true; // rysowanie sprzęgu w dołączanym - if (iDirection) - { //łączenie standardowe - NextConnected = Object; // normalnie doczepiamy go sobie do sprzęgu 1 - NextConnectedNo = Object->iDirection ^ 1; - } - else - { //łączenie odwrotne - PrevConnected = Object; // doczepiamy go sobie do sprzęgu 0, gdy stoimy odwrotnie - PrevConnectedNo = Object->iDirection ^ 1; - } - if (Object->iDirection) - { // dołączany jest normalnie ustawiany - Object->PrevConnected = this; // on ma nas z przodu - Object->PrevConnectedNo = iDirection; - } - else - { // dołączany jest odwrotnie ustawiany - Object->NextConnected = this; // on ma nas z tyłu - Object->NextConnectedNo = iDirection; - } -/* - // NOTE: this appears unnecessary and only messes things for the programmable lights function, which walks along - // whole trainset and expects each module to point to its own lights. Disabled, TBD, TODO: test for side-effects and delete if there's none - if (MoverParameters->TrainType & dt_EZT) // w przypadku łączenia członów, - // światła w rozrządczym zależą od stanu w silnikowym - if (MoverParameters->Couplers[iDirection].AllowedFlag & ctrain_depot) // gdy sprzęgi łączone warsztatowo (powiedzmy) - if ((MoverParameters->Power < 1.0) && (Object->MoverParameters->Power > 1.0)) // my nie mamy mocy, ale ten drugi ma - iLights = Object->MoverParameters->iLights; // to w tym z mocą będą światła załączane, a w tym bez tylko widoczne - else if ((MoverParameters->Power > 1.0) && - (Object->MoverParameters->Power < 1.0)) // my mamy moc, ale ten drugi nie ma - Object->iLights = MoverParameters->iLights; // to w tym z mocą będą światła załączane, a w tym bez tylko widoczne -*/ - return; - // SetPneumatic(1,1); //Ra: to i tak się nie wykonywało po return - // SetPneumatic(1,0); - // SetPneumatic(0,1); - // SetPneumatic(0,0); + MoverParameters->Attach( iDirection, Object->iDirection ^ 1, Object->MoverParameters, iType, true, false ); + update_neighbours(); } -bool TDynamicObject::UpdateForce(double dt, double dt1, bool FullVer) +bool TDynamicObject::UpdateForce(double dt) { if (!bEnabled) return false; if( dt > 0 ) { // wywalenie WS zależy od ustawienia kierunku - MoverParameters->ComputeTotalForce( dt, dt1, FullVer ); + MoverParameters->ComputeTotalForce( dt ); } return true; } @@ -6087,193 +5779,217 @@ void TDynamicObject::RaLightsSet(int head, int rear) int TDynamicObject::DirectionSet(int d) { // ustawienie kierunku w składzie (wykonuje AI) auto const lastdirection { iDirection }; - iDirection = d > 0 ? 1 : 0; // d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny; + iDirection = ( d > 0 ) ? 1 : 0; // d:1=zgodny,-1=przeciwny; iDirection:1=zgodny,0=przeciwny; if( iDirection != lastdirection ) { // direction was flipped, switch recorded servicable platform sides for potentially ongoing load exchange auto const left { ( lastdirection > 0 ) ? 1 : 2 }; auto const right { 3 - left }; m_exchange.platforms = - ( m_exchange.platforms & left ? right : 0 ) - + ( m_exchange.platforms & right ? left : 0 ); + ( ( m_exchange.platforms & left ) != 0 ? right : 0 ) + + ( ( m_exchange.platforms & right ) != 0 ? left : 0 ); } if (MyTrack) - { // podczas wczytywania wstawiane jest AI, ale może jeszcze nie - // być toru + { // podczas wczytywania wstawiane jest AI, ale może jeszcze nie być toru // AI ustawi kierunek ponownie po uruchomieniu silnika - if (iDirection) // jeśli w kierunku Coupler 0 - { - if (MoverParameters->Couplers[0].CouplingFlag == - ctrain_virtual) // brak pojazdu podpiętego? - ABuScanObjects(1, 300); // szukanie czegoś do podłączenia - } - else if (MoverParameters->Couplers[1].CouplingFlag == - ctrain_virtual) // brak pojazdu podpiętego? - ABuScanObjects(-1, 300); + update_neighbours(); } // informacja o położeniu następnego - return 1 - (iDirection ? NextConnectedNo : PrevConnectedNo); + return 1 - ( ( iDirection > 0 ) ? NextConnectedNo() : PrevConnectedNo() ); }; -TDynamicObject * TDynamicObject::PrevAny() -{ // wskaźnik na poprzedni, - // nawet wirtualny - return iDirection ? PrevConnected : NextConnected; -}; -TDynamicObject * TDynamicObject::Prev() -{ - if (MoverParameters->Couplers[iDirection ^ 1].CouplingFlag) - return iDirection ? PrevConnected : NextConnected; - return NULL; // gdy sprzęg wirtualny, to jakby nic nie było -}; -TDynamicObject * TDynamicObject::Next() -{ - if (MoverParameters->Couplers[iDirection].CouplingFlag) - return iDirection ? NextConnected : PrevConnected; - return NULL; // gdy sprzęg wirtualny, to jakby nic nie było -}; -TDynamicObject * TDynamicObject::PrevC(int C) -{ - if (MoverParameters->Couplers[iDirection ^ 1].CouplingFlag & C) - return iDirection ? PrevConnected : NextConnected; - return NULL; // gdy sprzęg wirtualny, to jakby nic nie było -}; -TDynamicObject * TDynamicObject::NextC(int C) -{ - if (MoverParameters->Couplers[iDirection].CouplingFlag & C) - return iDirection ? NextConnected : PrevConnected; - return NULL; // gdy sprzęg inny, to jakby nic nie było -}; -double TDynamicObject::NextDistance(double d) -{ // ustalenie odległości do - // następnego pojazdu, potrzebne - // do wstecznego skanowania - if (!MoverParameters->Couplers[iDirection].Connected) - return d; // jeśli nic nie ma, zwrócenie domyślnej wartości - if ((d <= 0.0) || (MoverParameters->Couplers[iDirection].CoupleDist < d)) - return MoverParameters->Couplers[iDirection].Dist; - else - return d; +// wskaźnik na poprzedni, nawet wirtualny +TDynamicObject * TDynamicObject::PrevAny() { + return MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle; +} +TDynamicObject * TDynamicObject::Prev() { + return ( MoverParameters->Couplers[ iDirection ^ 1 ].CouplingFlag != coupling::faux ? + MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle : + nullptr );// gdy sprzęg wirtualny, to jakby nic nie było +} +TDynamicObject * TDynamicObject::Next() { + return ( MoverParameters->Couplers[ iDirection ].CouplingFlag != coupling::faux ? + MoverParameters->Neighbours[ iDirection ].vehicle : + nullptr );// gdy sprzęg wirtualny, to jakby nic nie było +} +TDynamicObject * TDynamicObject::PrevC(int C) { + return ( ( MoverParameters->Couplers[ iDirection ^ 1 ].CouplingFlag & C ) == C ? + MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle : + nullptr ); // hide neighbour lacking specified connection type +} +TDynamicObject * TDynamicObject::NextC(int C) { + return ( ( MoverParameters->Couplers[ iDirection ].CouplingFlag & C ) == C ? + MoverParameters->Neighbours[ iDirection ].vehicle : + nullptr ); // hide neighbour lacking specified connection type +} + +// ustalenie następnego (1) albo poprzedniego (0) w składzie bez względu na prawidłowość iDirection +TDynamicObject * +TDynamicObject::Neighbour(int &dir) { + + auto *neighbour { ( + MoverParameters->Couplers[ dir ].CouplingFlag != coupling::faux ? + MoverParameters->Neighbours[ dir ].vehicle : + nullptr ) }; + // nowa wartość + dir = 1 - MoverParameters->Neighbours[ dir ].vehicle_end; + + return neighbour; }; -TDynamicObject * TDynamicObject::Neightbour(int &dir) -{ // ustalenie następnego (1) albo poprzedniego (0) w składzie bez - // względu na prawidłowość - // iDirection - int d = dir; // zapamiętanie kierunku - dir = 1 - (dir ? NextConnectedNo : PrevConnectedNo); // nowa wartość - return (d ? (MoverParameters->Couplers[1].CouplingFlag ? NextConnected : NULL) : - (MoverParameters->Couplers[0].CouplingFlag ? PrevConnected : NULL)); -}; +// updates potential collision sources +void +TDynamicObject::update_neighbours() { -void TDynamicObject::CoupleDist() -{ // obliczenie odległości sprzęgów - if (MyTrack ? (MyTrack->iCategoryFlag & 1) : - true) // jeśli nie ma przypisanego toru, to liczyć jak dla kolei - { // jeśli jedzie po szynach (również unimog), liczenie kul wystarczy - MoverParameters->SetCoupleDist(); + for( int end = end::front; end <= end::rear; ++end ) { + + auto &neighbour { MoverParameters->Neighbours[ end ] }; + auto const &coupler { MoverParameters->Couplers[ end ] }; + + if( ( coupler.Connected != nullptr ) + && ( neighbour.vehicle != nullptr ) ) { + // physical connection with another vehicle locks down collision source on this end +// neighbour.vehicle = coupler.Connected; +// neighbour.vehicle_end = coupler.ConnectedNr; + neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, coupler.Connected ); + } + else { + // if there's no connected vehicle check for potential collision sources in the vicinity + // NOTE: we perform a new scan on each update to ensure we always locate the nearest potential source + neighbour = neighbour_data(); + // 10m ~= 140 km/h at 4 fps + safety margin, potential distance between outer axles of involved vehicles + auto const scanrange { std::max( 10.0, std::abs( MoverParameters->V ) ) + 40.0 }; + auto const lookup { find_vehicle( end, scanrange ) }; + + if( false == std::get( lookup ) ) { continue; } + + neighbour.vehicle = std::get( lookup ); + neighbour.vehicle_end = std::get( lookup ); + neighbour.distance = std::get( lookup ); + + if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 25 : 50 ) ) { + // at short distances (re)calculate range between couplers directly + neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters ); + } + } } - else - { // na drodze trzeba uwzględnić wektory ruchu - double d0 = MoverParameters->Couplers[0].CoupleDist; - // double d1=MoverParameters->Couplers[1].CoupleDist; //sprzęg z tyłu - // samochodu można olać, - // dopóki nie jeździ na wstecznym - Math3D::vector3 p1, p2; - double d, w; // dopuszczalny dystans w poprzek - MoverParameters->SetCoupleDist(); // liczenie standardowe - if (MoverParameters->Couplers[0].Connected) // jeśli cokolwiek podłączone - if (MoverParameters->Couplers[0].CouplingFlag == 0) // jeśli wirtualny - if (MoverParameters->Couplers[0].CoupleDist < 300.0) // i mniej niż 300m - { // przez MoverParameters->Couplers[0].Connected nie da się dostać do - // DynObj, stąd - // prowizorka - // WriteLog("Collision of - // "+AnsiString(MoverParameters->Couplers[0].CoupleDist)+"m detected - // by - // "+asName+":0."); - w = 0.5 * (MoverParameters->Couplers[0].Connected->Dim.W + - MoverParameters->Dim.W); // minimalna odległość minięcia - d = -DotProduct(vLeft, vCoulpler[0]); // odległość prostej ruchu od początku - // układu współrzędnych - d = fabs( - DotProduct(vLeft, - ((TMoverParameters *)(MoverParameters->Couplers[0].Connected)) - ->vCoulpler[MoverParameters->Couplers[0].ConnectedNr]) + - d); - // WriteLog("Distance "+AnsiString(d)+"m from "+asName+":0."); - if (d > w) - MoverParameters->Couplers[0].CoupleDist = - (d0 < 10 ? 50 : d0); // przywrócenie poprzedniej - } - if (MoverParameters->Couplers[1].Connected) // jeśli cokolwiek podłączone - if (MoverParameters->Couplers[1].CouplingFlag == 0) // jeśli wirtualny - if (MoverParameters->Couplers[1].CoupleDist < 300.0) // i mniej niż 300m - { - // WriteLog("Collision of - // "+AnsiString(MoverParameters->Couplers[1].CoupleDist)+"m detected - // by - // "+asName+":1."); - w = 0.5 * (MoverParameters->Couplers[1].Connected->Dim.W + - MoverParameters->Dim.W); // minimalna odległość minięcia - d = -DotProduct(vLeft, vCoulpler[1]); // odległość prostej ruchu od początku - // układu współrzędnych - d = fabs( - DotProduct(vLeft, - ((TMoverParameters *)(MoverParameters->Couplers[1].Connected)) - ->vCoulpler[MoverParameters->Couplers[1].ConnectedNr]) + - d); - // WriteLog("Distance "+AnsiString(d)+"m from "+asName+":1."); - if (d > w) - MoverParameters->Couplers[0].CoupleDist = - (d0 < 10 ? 50 : d0); // przywrócenie poprzedniej - } +} + +// locates potential collision source within specified range, scanning track in specified direction. returns: true if neighbour was located, false otherwise +// NOTE: reuses legacy code. TBD, TODO: review, refactor? +std::tuple +TDynamicObject::find_vehicle( int const Direction, double const Distance ) const { + + auto direction { ( Direction == end::front ? 1 : -1 ) }; + auto const initialdirection { direction }; // zapamiętanie kierunku poszukiwań na torze początkowym, względem sprzęgów + + auto const *track { RaTrackGet() }; + if( RaDirectionGet() < 0 ) { + // czy oś jest ustawiona w stronę Point1? + direction = -direction; } -}; + + // (teraz względem toru) + auto const mycoupler { ( initialdirection < 0 ? end::rear : end::front ) }; // numer sprzęgu do podłączenia w obiekcie szukajacym + auto foundcoupler { -1 }; // numer sprzęgu w znalezionym obiekcie (znaleziony wypełni) + auto distance { 0.0 }; // przeskanowana odleglość; odległość do zawalidrogi + auto *foundobject { ABuFindObject( foundcoupler, distance, track, direction, mycoupler ) }; // zaczynamy szukać na tym samym torze + + if( foundobject == nullptr ) { + // jeśli nie ma na tym samym, szukamy po okolicy szukanie najblizszego toru z jakims obiektem + // praktycznie przeklejone z TraceRoute()... + if (direction >= 0) // uwzględniamy kawalek przeanalizowanego wcześniej toru + distance = track->Length() - RaTranslationGet(); // odległość osi od Point2 toru + else + distance = RaTranslationGet(); // 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 + direction = -direction; // to zmieniamy kierunek szukania na tym torze + } + track = track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik + } + 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 + distance = Distance + 1.0; // koniec przeglądania torów + break; + } + } + } // Koniec szukania najbliższego toru z jakimś obiektem. + + if( foundobject == nullptr ) { return {}; } +/* + auto const *vehicle { MoverParameters }; + auto const *foundvehicle { foundobject->MoverParameters }; + if( ( false == TestFlag( track->iCategoryFlag, 1 ) ) + && ( distance > 50.0 ) ) { + // 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! + // NOTE: the distance is approximated, and additionally less accurate for cars heading in opposite direction + distance -= ( 0.5 * ( vehicle->Dim.L + foundvehicle->Dim.L ) ); + } + else if( distance < 100.0 ) { + // at short distances start to calculate range between couplers directly + // odległość do najbliższego pojazdu w linii prostej + distance = TMoverParameters::CouplerDist( vehicle, foundvehicle ); + } +*/ + return { foundobject, foundcoupler, distance, true }; +} TDynamicObject * TDynamicObject::ControlledFind() { // taka proteza: - // chcę podłączyć - // kabinę EN57 - // bezpośrednio z - // silnikowym, aby - // nie robić tego - // przez - // ukrotnienie + // chcę podłączyć kabinę EN57 bezpośrednio z silnikowym, aby nie robić tego przez ukrotnienie // drugi silnikowy i tak musi być ukrotniony, podobnie jak kolejna jednostka - // lepiej by było przesyłać komendy sterowania, co jednak wymaga przebudowy - // transmisji komend - // (LD) - // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą - // świecić się w - // rozrządczych - // dla EZT światłą czołowe będą "zapalane w silnikowym", ale widziane z - // rozrządczych + // lepiej by było przesyłać komendy sterowania, co jednak wymaga przebudowy transmisji komend (LD) + // problem się robi ze światłami, które będą zapalane w silnikowym, ale muszą świecić się w rozrządczych + // dla EZT światłą czołowe będą "zapalane w silnikowym", ale widziane z rozrządczych // również wczytywanie MMD powinno dotyczyć aktualnego członu // problematyczna może być kwestia wybranej kabiny (w silnikowym...) - // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno - // jeździć dobrze + // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... TDynamicObject *d = this; // zaczynamy od aktualnego - if( d->MoverParameters->TrainType & dt_EZT ) { + if( ( d->MoverParameters->TrainType == dt_EZT ) + || ( d->MoverParameters->TrainType == dt_DMU ) ) { // na razie dotyczy to EZT - if( ( d->NextConnected != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ 1 ].AllowedFlag, coupling::permanent ) ) ) { + if( ( d->NextConnected() != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ end::rear ].AllowedFlag, coupling::permanent ) ) ) { // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) if( ( d->MoverParameters->Power < 1.0 ) - && ( d->NextConnected->MoverParameters->Power > 1.0 ) ) { + && ( d->NextConnected()->MoverParameters->Power > 1.0 ) ) { // my nie mamy mocy, ale ten drugi ma - d = d->NextConnected; // będziemy sterować tym z mocą + d = d->NextConnected(); // będziemy sterować tym z mocą } } - else if( ( d->PrevConnected != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ 0 ].AllowedFlag, coupling::permanent ) ) ) { + else if( ( d->PrevConnected() != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ end::front ].AllowedFlag, coupling::permanent ) ) ) { // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) if( ( d->MoverParameters->Power < 1.0 ) - && ( d->PrevConnected->MoverParameters->Power > 1.0 ) ) { + && ( d->PrevConnected()->MoverParameters->Power > 1.0 ) ) { // my nie mamy mocy, ale ten drugi ma - d = d->PrevConnected; // będziemy sterować tym z mocą + d = d->PrevConnected(); // będziemy sterować tym z mocą } } } @@ -6405,22 +6121,22 @@ TDynamicObject::ConnectedEnginePowerSource( TDynamicObject const *Caller ) const } // ...otherwise check rear first... // NOTE: the order should be reversed in flipped vehicles, but we ignore this out of laziness - if( ( nullptr != NextConnected ) - && ( NextConnected != Caller ) + if( ( nullptr != NextConnected() ) + && ( NextConnected() != Caller ) && ( ( MoverParameters->Couplers[1].CouplingFlag & ctrain_controll ) == ctrain_controll ) ) { - auto source = NextConnected->ConnectedEnginePowerSource( this ); + auto source = NextConnected()->ConnectedEnginePowerSource( this ); if( source != TPowerSource::NotDefined ) { return source; } } // ...then rear... - if( ( nullptr != PrevConnected ) - && ( PrevConnected != Caller ) + if( ( nullptr != PrevConnected() ) + && ( PrevConnected() != Caller ) && ( ( MoverParameters->Couplers[ 0 ].CouplingFlag & ctrain_controll ) == ctrain_controll ) ) { - auto source = PrevConnected->ConnectedEnginePowerSource( this ); + auto source = PrevConnected()->ConnectedEnginePowerSource( this ); if( source != TPowerSource::NotDefined ) { return source; @@ -7003,25 +6719,25 @@ vehicle_table::update( double Deltatime, int Iterationcount ) { update_traction( vehicle ); } vehicle->MoverParameters->ComputeConstans(); - vehicle->CoupleDist(); + vehicle->update_neighbours(); } if( Iterationcount > 1 ) { // ABu: ponizsze wykonujemy tylko jesli wiecej niz jedna iteracja for( int iteration = 0; iteration < ( Iterationcount - 1 ); ++iteration ) { for( auto *vehicle : m_items ) { - vehicle->UpdateForce( Deltatime, Deltatime, false ); + vehicle->UpdateForce( Deltatime ); } for( auto *vehicle : m_items ) { vehicle->FastUpdate( Deltatime ); } } } + for( auto *vehicle : m_items ) { + vehicle->UpdateForce( Deltatime ); + } auto const totaltime { Deltatime * Iterationcount }; // całkowity czas - for( auto *vehicle : m_items ) { - vehicle->UpdateForce( Deltatime, totaltime, true ); - } for( auto *vehicle : m_items ) { // Ra 2015-01: tylko tu przelicza sieć trakcyjną vehicle->Update( Deltatime, totaltime ); diff --git a/DynObj.h b/DynObj.h index 0a055f94..2ae80db9 100644 --- a/DynObj.h +++ b/DynObj.h @@ -183,12 +183,13 @@ public: std::string asDestination; // dokąd pojazd ma być kierowany "(stacja):(tor)" Math3D::matrix4x4 mMatrix; // macierz przekształcenia do renderowania modeli TMoverParameters *MoverParameters; // parametry fizyki ruchu oraz przeliczanie - TDynamicObject *NextConnected; // pojazd podłączony od strony sprzęgu 1 (kabina -1) - TDynamicObject *PrevConnected; // pojazd podłączony od strony sprzęgu 0 (kabina 1) - int NextConnectedNo; // numer sprzęgu podłączonego z tyłu - int PrevConnectedNo; // numer sprzęgu podłączonego z przodu - double fScanDist; // odległość skanowania torów na obecność innych pojazdów - double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) + inline TDynamicObject *NextConnected() { return MoverParameters->Neighbours[ end::rear ].vehicle; }; // pojazd podłączony od strony sprzęgu 1 (kabina -1) + inline TDynamicObject *PrevConnected() { return MoverParameters->Neighbours[ end::front ].vehicle; }; // pojazd podłączony od strony sprzęgu 0 (kabina 1) + inline TDynamicObject *NextConnected() const { return MoverParameters->Neighbours[ end::rear ].vehicle; }; // pojazd podłączony od strony sprzęgu 1 (kabina -1) + inline TDynamicObject *PrevConnected() const { return MoverParameters->Neighbours[ end::front ].vehicle; }; // pojazd podłączony od strony sprzęgu 0 (kabina 1) + inline int NextConnectedNo() const { return MoverParameters->Neighbours[ end::rear ].vehicle_end; } + inline int PrevConnectedNo() const { return MoverParameters->Neighbours[ end::front ].vehicle_end; } +// double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const; @@ -455,11 +456,8 @@ private: int iNumAxles; // ilość osi std::string asModel; - public: - void ABuScanObjects(int ScanDir, double ScanDist); - private: - TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ); + TDynamicObject *ABuFindObject( int &Foundcoupler, double &Distance, TTrack const *Track, int const Direction, int const Mycoupler ) const; void ABuCheckMyTrack(); public: @@ -470,7 +468,6 @@ private: TDynamicObject * Next(); TDynamicObject * PrevC(int C); TDynamicObject * NextC(int C); - double NextDistance(double d = -1.0); void SetdMoveLen(double dMoveLen) { MoverParameters->dMoveLen = dMoveLen; } void ResetdMoveLen() { @@ -485,6 +482,7 @@ private: return this ? asName : std::string(); }; + std::string asBaseDir; // std::ofstream PneuLogFile; //zapis parametrow pneumatycznych // youBy - dym @@ -506,7 +504,6 @@ private: bool bDisplayCab; // czy wyswietlac kabine w train.cpp int iCabs; // maski bitowe modeli kabin TTrack *MyTrack; // McZapkie-030303: tor na ktorym stoi, ABu - std::string asBaseDir; int iOverheadMask; // maska przydzielana przez AI pojazdom posiadającym pantograf, aby wymuszały jazdę bezprądową TTractionParam tmpTraction; double fAdjustment; // korekcja - docelowo przenieść do TrkFoll.cpp wraz z odległością od poprzedniego @@ -521,7 +518,7 @@ private: int init_sections( TModel3d const *Model, std::string const &Nameprefix ); void create_controller( std::string const Type, bool const Trainset ); void AttachPrev(TDynamicObject *Object, int iType = 1); - bool UpdateForce(double dt, double dt1, bool FullVer); + bool UpdateForce(double dt); // initiates load change by specified amounts, with a platform on specified side void LoadExchange( int const Disembark, int const Embark, int const Platform ); // calculates time needed to complete current load change @@ -605,14 +602,13 @@ private: Axle1.GetTranslation() : Axle0.GetTranslation(); }; // zwraca tor z aktywną osią - inline TTrack * RaTrackGet() { + inline TTrack * RaTrackGet() const { return iAxleFirst ? Axle1.GetTrack() : Axle0.GetTrack(); }; void couple( int const Side ); int uncouple( int const Side ); - void CouplersDettach(double MinDist, int MyScanDir); void RadioStop(); void Damage(char flag); void RaLightsSet(int head, int rear); @@ -626,8 +622,11 @@ private: return iDirection + iDirection - 1; }; int DettachStatus(int dir); int Dettach(int dir); - TDynamicObject * Neightbour(int &dir); - void CoupleDist(); + TDynamicObject * Neighbour(int &dir); + // updates potential collision sources + void update_neighbours(); + // locates potential collision source within specified range, scanning its route in specified direction + auto find_vehicle( int const Direction, double const Range ) const -> std::tuple; TDynamicObject * ControlledFind(); void ParamSet(int what, int into); // zapytanie do AI, po którym segmencie skrzyżowania jechać diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 697757ab..8c5e0969 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -140,7 +140,7 @@ static int const ctrain_depot = 128; //nie rozłączalny podczas zwykłyc // vehicle sides; exclusive enum end { front = 0, - rear + rear = 1 }; enum side { @@ -609,18 +609,16 @@ struct power_coupling { struct TCoupling { /*parametry*/ double SpringKB = 1.0; /*stala sprezystosci zderzaka/sprzegu, %tlumiennosci */ - double SpringKC = 1.0; - double beta = 0.0; double DmaxB = 0.1; /*tolerancja scisku/rozciagania, sila rozerwania*/ double FmaxB = 1000.0; + double SpringKC = 1.0; double DmaxC = 0.1; double FmaxC = 1000.0; - TCouplerType CouplerType = TCouplerType::NoCoupler; /*typ sprzegu*/ - /*zmienne*/ + double beta = 0.0; + TCouplerType CouplerType = TCouplerType::NoCoupler; /*typ sprzegu*/ + int AllowedFlag = 3; //Ra: maska dostępnych + /*zmienne*/ int CouplingFlag = 0; /*0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy*/ - int AllowedFlag = 3; //Ra: znaczenie jak wyżej, maska dostępnych - bool Render = false; /*ABu: czy rysowac jak zaczepiony sprzeg*/ - double CoupleDist = 0.0; /*ABu: optymalizacja - liczenie odleglosci raz na klatkę, bez iteracji*/ class TMoverParameters *Connected = nullptr; /*co jest podlaczone*/ int ConnectedNr = 0; //Ra: od której strony podłączony do (Connected): 0=przód, 1=tył double CForce = 0.0; /*sila z jaka dzialal*/ @@ -628,16 +626,25 @@ struct TCoupling { bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/ power_coupling power_high; - power_coupling power_low; // TODO: implement this +// power_coupling power_low; // TODO: implement this int sounds { 0 }; // sounds emitted by the coupling devices + bool Render = false; /*ABu: czy rysowac jak zaczepiony sprzeg*/ }; +struct neighbour_data { + TDynamicObject *vehicle { nullptr }; // detected obstacle + int vehicle_end { -1 }; // facing end of the obstacle + float distance { -1.f }; // distance to the obstacle +}; + + + class TMoverParameters { // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :) private: // types - +/* TODO: implement // communication cable, exchanging control signals with adjacent vehicle struct jumper_cable { // types @@ -651,7 +658,7 @@ private: // integers // std::array values {}; }; - +*/ // basic approximation of a generic device // TBD: inheritance or composition? struct basic_device { @@ -818,14 +825,12 @@ private: public: double dMoveLen = 0.0; - std::string filename; /*---opis lokomotywy, wagonu itp*/ /*--opis serii--*/ int CategoryFlag = 1; /*1 - pociag, 2 - samochod, 4 - statek, 8 - samolot*/ /*--sekcja stalych typowych parametrow*/ std::string TypeName; /*nazwa serii/typu*/ - //TrainType: string; {typ: EZT/elektrowoz - Winger 040304} - int TrainType = 0; /*Ra: powinno być szybciej niż string*/ + int TrainType = 0; /*typ: EZT/elektrowoz - Winger 040304 Ra: powinno być szybciej niż string*/ TEngineType EngineType = TEngineType::None; /*typ napedu*/ TPowerParameters EnginePowerSource; /*zrodlo mocy dla silnikow*/ TPowerParameters SystemPowerSource; /*zrodlo mocy dla systemow sterowania/przetwornic/sprezarek*/ @@ -1077,6 +1082,7 @@ public: TRotation Rot { 0.0, 0.0, 0.0 }; std::string Name; /*nazwa wlasna*/ TCoupling Couplers[2]; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami + std::array Neighbours; // potential collision sources bool EventFlag = false; /*!o true jesli cos nietypowego sie wydarzy*/ int SoundFlag = 0; /*!o patrz stale sound_ */ double DistCounter = 0.0; /*! licznik kilometrow */ @@ -1307,24 +1313,19 @@ public: double FrictConst2d= 0.0; double TotalMassxg = 0.0; /*TotalMass*g*/ - Math3D::vector3 vCoulpler[2]; // powtórzenie współrzędnych sprzęgów z DynObj :/ double fBrakeCtrlPos = -2.0; // płynna nastawa hamulca zespolonego bool bPantKurek3 = true; // kurek trójdrogowy (pantografu): true=połączenie z ZG, false=połączenie z małą sprężarką // domyślnie zbiornik pantografu połączony jest ze zbiornikiem głównym int iProblem = 0; // flagi problemów z taborem, aby AI nie musiało porównywać; 0=może jechać int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu -private: - double CouplerDist(int Coupler); public: TMoverParameters(double VelInitial, std::string TypeNameInit, std::string NameInit, int Cab); // obsługa sprzęgów - double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2); -/* double Distance(const vector3 &Loc1, const vector3 &Loc2, const vector3 &Dim1, const vector3 &Dim2); -*/ //bool AttachA(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false); + static double CouplerDist( TMoverParameters const *Left, TMoverParameters const *Right ); + static double Distance(const TLocation &Loc1, const TLocation &Loc2, const TDimension &Dim1, const TDimension &Dim2); bool Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced = false, bool Audible = true); int DettachStatus(int ConnectNo); bool Dettach(int ConnectNo); - void SetCoupleDist(); bool DirectionForward(); void BrakeLevelSet(double b); bool BrakeLevelAdd(double b); @@ -1340,7 +1341,7 @@ public: // Q ******************************************************************************************* double GetTrainsetVoltage(void); - bool Physic_ReActivation(void); + bool switch_physics(bool const State); double LocalBrakeRatio(void); double ManualBrakeRatio(void); double PipeRatio(void);/*ile napelniac*/ @@ -1412,17 +1413,17 @@ public: /*funkcje obliczajace sily*/ void ComputeConstans(void);//ABu: wczesniejsze wyznaczenie stalych dla liczenia sil double ComputeMass(void); - void ComputeTotalForce(double dt, double dt1, bool FullVer); + void ComputeTotalForce(double dt); double Adhesive(double staticfriction) const; double TractionForce(double dt); double FrictionForce(double R, int TDamage); double BrakeForceR(double ratio, double velocity); double BrakeForceP(double press, double velocity); double BrakeForce(const TTrackParam &Track); - double CouplerForce(int CouplerN, double dt); + double CouplerForce(int const End, double dt); void CollisionDetect(int CouplerN, double dt); /*obrot kol uwzgledniajacy poslizg*/ - double ComputeRotatingWheel(double WForce, double dt, double n); + double ComputeRotatingWheel(double WForce, double dt, double n) const; /*--funkcje dla lokomotyw*/ bool DirectionBackward(void);/*! kierunek ruchu*/ diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index b6535ce0..f39e97ae 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "MOVER.h" +#include "DynObj.h" #include "Oerlikon_ESt.h" #include "utilities.h" #include "Globals.h" @@ -383,168 +384,118 @@ double TMoverParameters::Distance(const TLocation &Loc1, const TLocation &Loc2, { // zwraca odległość pomiędzy pojazdami (Loc1) i (Loc2) z uwzględnieneim ich długości (kule!) return hypot(Loc2.X - Loc1.X, Loc1.Y - Loc2.Y) - 0.5 * (Dim2.L + Dim1.L); }; -/* -double TMoverParameters::Distance(const vector3 &s1, const vector3 &s2, const vector3 &d1, - const vector3 &d2){ - // obliczenie odległości prostopadłościanów o środkach (s1) i (s2) i wymiarach (d1) i (d2) - // return 0.0; //będzie zgłaszać warning - funkcja do usunięcia, chyba że się przyda... -}; -*/ -double TMoverParameters::CouplerDist(int Coupler) -{ // obliczenie odległości pomiędzy sprzęgami (kula!) - Couplers[Coupler].CoupleDist = - Distance( - Loc, Couplers[Coupler].Connected->Loc, - Dim, Couplers[Coupler].Connected->Dim); // odległość pomiędzy sprzęgami (kula!) - return Couplers[ Coupler ].CoupleDist; +double TMoverParameters::CouplerDist(TMoverParameters const *Left, TMoverParameters const *Right) +{ // obliczenie odległości pomiędzy sprzęgami (kula!) + return + Distance( + Left->Loc, Right->Loc, + Left->Dim, Right->Dim); // odległość pomiędzy sprzęgami (kula!) }; bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, int CouplingType, bool Forced, bool Audible) { //łączenie do swojego sprzęgu (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) // Ra: zwykle wykonywane dwukrotnie, dla każdego pojazdu oddzielnie - // Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do - // składu - if (ConnectTo) // jeśli nie pusty - { - auto &coupler = Couplers[ ConnectNo ]; - if (ConnectToNr != 2) - coupler.ConnectedNr = ConnectToNr; // 2=nic nie podłączone - coupler.Connected = ConnectTo; // tak podpiąć (do siebie) zawsze można, najwyżej będzie wirtualny - CouplerDist( ConnectNo ); // przeliczenie odległości pomiędzy sprzęgami + // Ra: trzeba by odróżnić wymóg dociśnięcia od uszkodzenia sprzęgu przy podczepianiu AI do składu - if (CouplingType == coupling::faux) - return false; // wirtualny więcej nic nie robi - - auto &othercoupler = ConnectTo->Couplers[ coupler.ConnectedNr ]; - if( ( Forced ) - || ( ( coupler.CoupleDist <= dEpsilon ) - && ( coupler.CouplerType != TCouplerType::NoCoupler ) - && ( coupler.CouplerType == othercoupler.CouplerType ) ) ) - { // stykaja sie zderzaki i kompatybilne typy sprzegow, chyba że łączenie na starcie - if( coupler.CouplingFlag == ctrain_virtual ) { - // jeśli wcześniej nie było połączone, ustalenie z której strony rysować sprzęg - coupler.Render = true; // tego rysować - othercoupler.Render = false; // a tego nie - }; - auto const couplingchange { CouplingType ^ coupler.CouplingFlag }; - coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu - // if (CouplingType!=ctrain_virtual) //Ra: wirtualnego nie łączymy zwrotnie! - //{//jeśli łączenie sprzęgiem niewirtualnym, ustawiamy połączenie zwrotne - othercoupler.CouplingFlag = CouplingType; - othercoupler.Connected = this; - othercoupler.CoupleDist = coupler.CoupleDist; - - if( ( true == Audible ) && ( couplingchange != 0 ) ) { - // set sound event flag - int soundflag{ sound::none }; - std::vector> const soundmappings = { - { coupling::coupler, sound::attachcoupler }, - { coupling::brakehose, sound::attachbrakehose }, - { coupling::mainhose, sound::attachmainhose }, - { coupling::control, sound::attachcontrol}, - { coupling::gangway, sound::attachgangway}, - { coupling::heating, sound::attachheating} }; - for( auto const &soundmapping : soundmappings ) { - if( ( couplingchange & soundmapping.first ) != 0 ) { - soundflag |= soundmapping.second; - } - } - SetFlag( coupler.sounds, soundflag ); - } - - return true; - //} - // podłączenie nie udało się - jest wirtualne - } + if( ( ConnectTo == nullptr ) + || ( CouplingType == coupling::faux ) ) { + return false; } - return false; // brak podłączanego pojazdu, zbyt duża odległość, niezgodny typ sprzęgu, brak - // sprzęgu, brak haka -}; + + auto &coupler { Couplers[ ConnectNo ] }; + auto &othercoupler = ConnectTo->Couplers[ ( ConnectToNr != 2 ? ConnectToNr : coupler.ConnectedNr ) ]; + auto const distance { CouplerDist( this, ConnectTo ) }; -// to jest już niepotrzebne bo nie ma Delphi -//bool TMoverParameters::Attach(int ConnectNo, int ConnectToNr, TMoverParameters *ConnectTo, -// int CouplingType, bool Forced) -//{ //łączenie do (ConnectNo) pojazdu (ConnectTo) stroną (ConnectToNr) -// return Attach(ConnectNo, ConnectToNr, (TMoverParameters *)ConnectTo, CouplingType, Forced); -//}; + auto const couplercheck { + ( Forced ) + || ( ( distance <= dEpsilon ) + && ( coupler.CouplerType != TCouplerType::NoCoupler ) + && ( coupler.CouplerType == othercoupler.CouplerType ) ) }; + + if( false == couplercheck ) { return false; } + + // stykaja sie zderzaki i kompatybilne typy sprzegow, chyba że łączenie na starcie + if( coupler.CouplingFlag == coupling::faux ) { + // jeśli wcześniej nie było połączone, ustalenie z której strony rysować sprzęg + coupler.Render = true; // tego rysować + othercoupler.Render = false; // a tego nie + }; + auto const couplingchange { CouplingType ^ coupler.CouplingFlag }; + coupler.Connected = ConnectTo; + coupler.CouplingFlag = CouplingType; // ustawienie typu sprzęgu + if( ConnectToNr != 2 ) { + coupler.ConnectedNr = ConnectToNr; // 2=nic nie podłączone + } + othercoupler.Connected = this; + othercoupler.CouplingFlag = CouplingType; + othercoupler.ConnectedNr = ConnectNo; + + if( ( true == Audible ) && ( couplingchange != 0 ) ) { + // set sound event flag + int soundflag{ sound::none }; + std::vector> const soundmappings = { + { coupling::coupler, sound::attachcoupler }, + { coupling::brakehose, sound::attachbrakehose }, + { coupling::mainhose, sound::attachmainhose }, + { coupling::control, sound::attachcontrol}, + { coupling::gangway, sound::attachgangway}, + { coupling::heating, sound::attachheating} }; + for( auto const &soundmapping : soundmappings ) { + if( ( couplingchange & soundmapping.first ) != 0 ) { + soundflag |= soundmapping.second; + } + } + SetFlag( coupler.sounds, soundflag ); + } + + return true; +} int TMoverParameters::DettachStatus(int ConnectNo) { // Ra: sprawdzenie, czy odległość jest dobra do rozłączania - // powinny być 3 informacje: =0 sprzęg już rozłączony, <0 da się rozłączyć. >0 nie da się - // rozłączyć + // powinny być 3 informacje: =0 sprzęg już rozłączony, <0 da się rozłączyć. >0 nie da się rozłączyć if (!Couplers[ConnectNo].Connected) return 0; // nie ma nic, to rozłączanie jest OK if ((Couplers[ConnectNo].CouplingFlag & ctrain_coupler) == 0) return -Couplers[ConnectNo].CouplingFlag; // hak nie połączony - rozłączanie jest OK if (TestFlag(DamageFlag, dtrain_coupling)) return -Couplers[ConnectNo].CouplingFlag; // hak urwany - rozłączanie jest OK - // ABu021104: zakomentowane 'and (CouplerType<>Articulated)' w warunku, nie wiem co to bylo, ale - // za to teraz dziala odczepianie... :) } - // if (CouplerType==Articulated) return false; //sprzęg nie do rozpięcia - może być tylko urwany - // Couplers[ConnectNo].CoupleDist=Distance(Loc,Couplers[ConnectNo].Connected->Loc,Dim,Couplers[ConnectNo].Connected->Dim); - CouplerDist(ConnectNo); - if (Couplers[ConnectNo].CouplerType == TCouplerType::Screw ? Couplers[ConnectNo].CoupleDist < 0.01 : true) +// CouplerDist(ConnectNo); + if (Couplers[ConnectNo].CouplerType == TCouplerType::Screw ? Neighbours[ConnectNo].distance < 0.01 : true) return -Couplers[ConnectNo].CouplingFlag; // można rozłączać, jeśli dociśnięty - return (Couplers[ConnectNo].CoupleDist > 0.2) ? -Couplers[ConnectNo].CouplingFlag : + return (Neighbours[ConnectNo].distance > 0.2) ? -Couplers[ConnectNo].CouplingFlag : Couplers[ConnectNo].CouplingFlag; }; bool TMoverParameters::Dettach(int ConnectNo) { // rozlaczanie - if (!Couplers[ConnectNo].Connected) - return true; // nie ma nic, to odczepiono - // with Couplers[ConnectNo] do - int i = DettachStatus(ConnectNo); // stan sprzęgu - if (i < 0) - { // gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony) - // Couplers[ConnectNo].Connected=NULL; //lepiej zostawic bo przeciez trzeba kontrolowac - // zderzenia odczepionych - Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = - 0; // pozostaje sprzęg wirtualny - Couplers[ConnectNo].CouplingFlag = 0; // pozostaje sprzęg wirtualny + auto &coupler { Couplers[ ConnectNo ] }; + auto &othervehicle { coupler.Connected }; + auto &othercoupler { othervehicle->Couplers[ coupler.ConnectedNr ] }; + + if( othervehicle == nullptr ) { return true; } // nie ma nic, to odczepiono + + auto const i = DettachStatus(ConnectNo); // stan sprzęgu + if (i < 0) { + // gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony) + std::tie( coupler.Connected, coupler.ConnectedNr, coupler.CouplingFlag ) + = std::tie( othercoupler.Connected, othercoupler.ConnectedNr, othercoupler.CouplingFlag ) + = std::make_tuple( nullptr, -1, coupling::faux ); // set sound event flag - SetFlag( Couplers[ ConnectNo ].sounds, sound::detachall ); + SetFlag( coupler.sounds, sound::detachall ); return true; } else if (i > 0) - { // odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym - // nic) - Couplers[ConnectNo].CouplingFlag &= ctrain_coupler; - Couplers[ConnectNo].Connected->Couplers[Couplers[ConnectNo].ConnectedNr].CouplingFlag = - Couplers[ConnectNo].CouplingFlag; + { // odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym nic) + coupler.CouplingFlag &= coupling::coupler; + othercoupler.CouplingFlag &= coupling::coupler; } return false; // jeszcze nie rozłączony }; -// przeliczenie odległości sprzęgów -void TMoverParameters::SetCoupleDist() { -/* - double const MaxDist = 100.0; // 2x average max proximity distance. TODO: rearrange ito something more elegant -*/ - for( int coupleridx = 0; coupleridx <= 1; ++coupleridx ) { - - if( Couplers[ coupleridx ].Connected == nullptr ) { continue; } - - CouplerDist( coupleridx ); - if( CategoryFlag & 2 ) { - // Ra: dla samochodów zderzanie kul to za mało - // NOTE: whatever calculation was supposed to be here, ain't - } -/* - if( ( Couplers[ coupleridx ].CouplingFlag == coupling::faux ) - && ( Couplers[ coupleridx ].CoupleDist > MaxDist ) ) { - // zerwij kontrolnie wirtualny sprzeg - // Connected.Couplers[CNext].Connected:=nil; //Ra: ten podłączony niekoniecznie jest wirtualny - Couplers[ coupleridx ].Connected = nullptr; - Couplers[ coupleridx ].ConnectedNr = 2; - } -*/ - } -}; - bool TMoverParameters::DirectionForward() { if ((MainCtrlPosNo > 0) && (ActiveDir < 1) && (MainCtrlPos == 0)) @@ -1064,7 +1015,8 @@ void TMoverParameters::CollisionDetect(int CouplerN, double dt) CCF = ComputeCollision( coupler.Connected->V, - V, coupler.Connected->TotalMass, + V, + coupler.Connected->TotalMass, TotalMass, (coupler.beta + coupler.Connected->Couplers[coupler.ConnectedNr].beta) / 2.0, VirtualCoupling) @@ -3755,7 +3707,7 @@ void TMoverParameters::UpdateScndPipePressure(double dt) c = Couplers[0].Connected; // skrot dv1 = 0.5 * dt * PF(ScndPipePress, c->ScndPipePress, Spz * 0.75); if (dv1 * dv1 > 0.00000000000001) - c->Physic_ReActivation(); + c->switch_physics( true ); c->Pipe2->Flow(-dv1); } // sprzeg 2 @@ -3765,7 +3717,7 @@ void TMoverParameters::UpdateScndPipePressure(double dt) c = Couplers[1].Connected; // skrot dv2 = 0.5 * dt * PF(ScndPipePress, c->ScndPipePress, Spz * 0.75); if (dv2 * dv2 > 0.00000000000001) - c->Physic_ReActivation(); + c->switch_physics( true ); c->Pipe2->Flow(-dv2); } if ((Couplers[1].Connected != NULL) && (Couplers[0].Connected != NULL)) @@ -3816,7 +3768,7 @@ double TMoverParameters::GetDVc(double dt) c = Couplers[0].Connected; // skrot //0.08 //e/D * L/D = e/D^2 * L dv1 = 0.5 * dt * PF(PipePress, c->PipePress, (Spg) / (1.0 + 0.015 / Spg * Dim.L)); if (dv1 * dv1 > 0.00000000000001) - c->Physic_ReActivation(); + c->switch_physics( true ); c->Pipe->Flow(-dv1); } // sprzeg 2 @@ -3826,7 +3778,7 @@ double TMoverParameters::GetDVc(double dt) c = Couplers[1].Connected; // skrot dv2 = 0.5 * dt * PF(PipePress, c->PipePress, (Spg) / (1.0 + 0.015 / Spg * Dim.L)); if (dv2 * dv2 > 0.00000000000001) - c->Physic_ReActivation(); + c->switch_physics( true ); c->Pipe->Flow(-dv2); } //if ((Couplers[1].Connected != NULL) && (Couplers[0].Connected != NULL)) @@ -3922,143 +3874,138 @@ double TMoverParameters::ComputeMass(void) // Q: 20160713 // Obliczanie wypadkowej siły z wszystkich działających sił // ************************************************************************************************* -void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer) -{ - int b; - double Fwheels = 0.0; +// TBD, TODO: move some of the calculations out of the method, they're relevant to more than just force calculations +void TMoverParameters::ComputeTotalForce(double dt) { - if (PhysicActivation) - { - // EventFlag:=false; {jesli cos sie zlego - // wydarzy to ustawiane na true} - // SoundFlag:=0; {jesli ma byc jakis dzwiek - // to zapalany jet odpowiedni bit} - // to powinno byc zerowane na zewnatrz - - // juz zoptymalizowane: - FStand = FrictionForce(RunningShape.R, RunningTrack.DamageFlag); // siła oporów ruchu - Vel = abs(V) * 3.6; // prędkość w km/h - nrot = v2n(); // przeliczenie prędkości liniowej na obrotową - - if( (true == TestFlag(BrakeMethod, bp_MHS)) - && (PipePress < 3.0) - && (Vel > 45) - && (true == TestFlag(BrakeDelayFlag, bdelay_M))) // ustawione na sztywno na 3 bar - FStand += TrackBrakeForce; // doliczenie hamowania hamulcem szynowym - // w charakterystykach jest wartość siły hamowania zamiast nacisku - // if(FullVer=true) then - // ABu: to dla optymalizacji, bo chyba te rzeczy wystarczy sprawdzac 1 raz na - // klatke? - LastSwitchingTime += dt1; - if (EngineType == TEngineType::ElectricSeriesMotor) - LastRelayTime += dt1; - if( Mains && /*(abs(CabNo) < 2) &&*/ ( EngineType == TEngineType::ElectricSeriesMotor ) ) // potem ulepszyc! pantogtrafy! - { // Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być - // zdefiniowany nawrotnik - if( CabNo == 0 ) - Voltage = RunningTraction.TractionVoltage * ActiveDir; - else - Voltage = RunningTraction.TractionVoltage * DirAbsolute; // ActiveDir*CabNo; - } // bo nie dzialalo - else if( ( EngineType == TEngineType::ElectricInductionMotor ) - || ( ( ( Couplers[ end::front ].CouplingFlag & ctrain_power ) == ctrain_power ) - || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) { - // potem ulepszyc! pantogtrafy! - Voltage = - std::max( - RunningTraction.TractionVoltage, - std::max( - Couplers[ end::front ].power_high.voltage, - Couplers[ end::rear ].power_high.voltage ) ); - } - else { - Voltage = 0; - } - - if (Power > 0) - FTrain = TractionForce(dt); - else - FTrain = 0; - - Fb = BrakeForce(RunningTrack); - Fwheels = FTrain - Fb * Sign(V); - if( ( Vel > 0.001 ) // crude trap, to prevent braked stationary vehicles from passing fb > mass * adhesive test - && ( std::abs(Fwheels) > TotalMassxg * Adhesive( RunningTrack.friction ) ) ) // poslizg - { - SlippingWheels = true; - } - if( true == SlippingWheels ) { - // TrainForce:=TrainForce-Fb; - double temp_nrot = ComputeRotatingWheel(Fwheels - - Sign(nrot * M_PI * WheelDiameter - V) * - Adhesive(RunningTrack.friction) * TotalMassxg, - dt, nrot); - Fwheels = Sign(temp_nrot * M_PI * WheelDiameter - V) * TotalMassxg * Adhesive(RunningTrack.friction); - if (Fwheels*Sign(V)>0) - { - FTrain = Fwheels + Fb*Sign(V); - } - else if (FTrain*Sign(V)>0) - { - Fb = FTrain*Sign(V) - Fwheels*Sign(V); - } - else - { - Fb = -Fwheels*Sign(V); - FTrain = 0; - } - if (nrot < 0.1) - { - WheelFlat = sqrt(square(WheelFlat) + abs(Fwheels) / NAxles*Vel*0.000002); - } - if (Sign(nrot * M_PI * WheelDiameter - V)*Sign(temp_nrot * M_PI * WheelDiameter - V) < 0) - { - SlippingWheels = false; - temp_nrot = V / M_PI / WheelDiameter; - } - - - nrot = temp_nrot; - } - // else SlippingWheels:=false; - // FStand:=0; - for (b = 0; b < 2; ++b) - if (Couplers[b].Connected != NULL) /*and (Couplers[b].CouplerType<>Bare) and - (Couplers[b].CouplerType<>Articulated)*/ - { // doliczenie sił z innych pojazdów - Couplers[b].CForce = CouplerForce(b, dt); - FTrain += Couplers[b].CForce; - } - else - Couplers[b].CForce = 0; - // FStand:=Fb+FrictionForce(RunningShape.R,RunningTrack.DamageFlag); - FStand += Fb; - FTrain += - TotalMassxg * RunningShape.dHtrack; // doliczenie składowej stycznej grawitacji - //!niejawne przypisanie zmiennej! - FTotal = FTrain - Sign(V) * FStand; - } + Vel = std::abs(V) * 3.6; // prędkość w km/h // McZapkie-031103: sprawdzanie czy warto liczyc fizyke i inne updaty // ABu 300105: cos tu mieszalem , dziala teraz troche lepiej, wiec zostawiam - if ((CabNo == 0) && (Vel < 0.0001) && (abs(AccS) < 0.0001) && (TrainType != dt_EZT)) { - if (!PhysicActivation) - { - if (Couplers[0].Connected != NULL) - if ((Couplers[0].Connected->Vel > 0.0001) || - (abs(Couplers[0].Connected->AccS) > 0.0001)) - Physic_ReActivation(); - if (Couplers[1].Connected != NULL) - if ((Couplers[1].Connected->Vel > 0.0001) || - (abs(Couplers[1].Connected->AccS) > 0.0001)) - Physic_ReActivation(); - } - if (LastSwitchingTime > 5) // 10+Random(100) then - PhysicActivation = false; // zeby nie brac pod uwage braku V po uruchomieniu programu + auto const vehicleisactive { + ( CabNo != 0 ) + || ( Vel > 0.0001 ) + || ( std::abs( AccS ) > 0.0001 ) + || ( LastSwitchingTime < 5 ) + || ( TrainType == dt_EZT ) + || ( TrainType == dt_DMU ) }; + + auto const movingvehicleahead { + ( Neighbours[ end::front ].vehicle != nullptr ) + && ( ( Neighbours[ end::front ].vehicle->MoverParameters->Vel > 0.0001 ) + || ( std::abs( Neighbours[ end::front ].vehicle->MoverParameters->AccS ) > 0.0001 ) ) }; + + auto const movingvehiclebehind { + ( Neighbours[ end::rear ].vehicle != nullptr ) + && ( ( Neighbours[ end::rear ].vehicle->MoverParameters->Vel > 0.0001 ) + || ( std::abs( Neighbours[ end::rear ].vehicle->MoverParameters->AccS ) > 0.0001 ) ) }; + + auto const calculatephysics { vehicleisactive || movingvehicleahead || movingvehiclebehind }; + + switch_physics( calculatephysics ); } - else - PhysicActivation = true; + + if( false == PhysicActivation ) { return; } + + // juz zoptymalizowane: + FStand = FrictionForce(RunningShape.R, RunningTrack.DamageFlag); // siła oporów ruchu + nrot = v2n(); // przeliczenie prędkości liniowej na obrotową + + if( ( true == TestFlag( BrakeMethod, bp_MHS ) ) + && ( PipePress < 3.0 ) // ustawione na sztywno na 3 bar + && ( Vel > 45 ) + && ( true == TestFlag( BrakeDelayFlag, bdelay_M ) ) ) { + // doliczenie hamowania hamulcem szynowym + FStand += TrackBrakeForce; + } + // w charakterystykach jest wartość siły hamowania zamiast nacisku + + LastSwitchingTime += dt; + if( EngineType == TEngineType::ElectricSeriesMotor ) { + LastRelayTime += dt; + } + if( Mains && /*(abs(CabNo) < 2) &&*/ ( EngineType == TEngineType::ElectricSeriesMotor ) ) // potem ulepszyc! pantogtrafy! + { // Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być zdefiniowany nawrotnik + if( CabNo == 0 ) + Voltage = RunningTraction.TractionVoltage * ActiveDir; + else + Voltage = RunningTraction.TractionVoltage * DirAbsolute; // ActiveDir*CabNo; + } // bo nie dzialalo + else if( ( EngineType == TEngineType::ElectricInductionMotor ) + || ( ( ( Couplers[ end::front ].CouplingFlag & ctrain_power ) == ctrain_power ) + || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) { + // potem ulepszyc! pantogtrafy! + Voltage = + std::max( + RunningTraction.TractionVoltage, + std::max( + Couplers[ end::front ].power_high.voltage, + Couplers[ end::rear ].power_high.voltage ) ); + } + else { + Voltage = 0; + } + + FTrain = ( + Power > 0 ? + TractionForce( dt ) : + 0 ); + + Fb = BrakeForce(RunningTrack); + // poslizg + auto Fwheels { FTrain - Fb * Sign( V ) }; + if( ( Vel > 0.001 ) // crude trap, to prevent braked stationary vehicles from passing fb > mass * adhesive test + && ( std::abs(Fwheels) > TotalMassxg * Adhesive( RunningTrack.friction ) ) ) { + SlippingWheels = true; + } + if( true == SlippingWheels ) { + + double temp_nrot = ComputeRotatingWheel(Fwheels - + Sign(nrot * M_PI * WheelDiameter - V) * + Adhesive(RunningTrack.friction) * TotalMassxg, + dt, nrot); + Fwheels = Sign(temp_nrot * M_PI * WheelDiameter - V) * TotalMassxg * Adhesive(RunningTrack.friction); + if (Fwheels*Sign(V)>0) + { + FTrain = Fwheels + Fb*Sign(V); + } + else if (FTrain*Sign(V)>0) + { + Fb = FTrain*Sign(V) - Fwheels*Sign(V); + } + else + { + Fb = -Fwheels*Sign(V); + FTrain = 0; + } + if (nrot < 0.1) + { + WheelFlat = sqrt(square(WheelFlat) + abs(Fwheels) / NAxles*Vel*0.000002); + } + if (Sign(nrot * M_PI * WheelDiameter - V)*Sign(temp_nrot * M_PI * WheelDiameter - V) < 0) + { + SlippingWheels = false; + temp_nrot = V / M_PI / WheelDiameter; + } + + + nrot = temp_nrot; + } + // doliczenie sił z innych pojazdów + for( int end = end::front; end <= end::rear; ++end ) { + if( Neighbours[ end ].vehicle != nullptr ) { + Couplers[ end ].CForce = CouplerForce( end, dt ); + FTrain += Couplers[ end ].CForce; + } + else + Couplers[ end ].CForce = 0; + } + + FStand += Fb; + // doliczenie składowej stycznej grawitacji + FTrain += TotalMassxg * RunningShape.dHtrack; + //!niejawne przypisanie zmiennej! + FTotal = FTrain - Sign(V) * FStand; } double TMoverParameters::BrakeForceR(double ratio, double velocity) @@ -4235,175 +4182,121 @@ double TMoverParameters::Adhesive(double staticfriction) const return adhesion; } -// poprawka dla liczenia sil przy ustawieniu przeciwnym obiektow: -/* -double DirPatch(int Coupler1, int Coupler2) -{ - if (Coupler1 != Coupler2) return 1; - else return -1; -} - - -double DirF(int CouplerN) -{ - double rDirF; - switch (CouplerN) - { - case 0: return -1; break; - case 1: return 1; break; - default: return 0; - } - // if (CouplerN == 0) return -1; -// else if (CouplerN == 0) return 1; -// else return 0; -} -*/ - // ************************************************************************************************* // Q: 20160713 // Obliczanie sił dzialających na sprzęgach // ************************************************************************************************* -double TMoverParameters::CouplerForce(int CouplerN, double dt) -{ - // wyliczenie siły na sprzęgu - double tempdist = 0, newdist = 0, distDelta = 0, CF = 0, dV = 0, absdV = 0, Fmax = 0; - double BetaAvg = 0; - int CNext = 0; - const double MaxDist = 405.0; // ustawione + 5 m, bo skanujemy do 400 m - const double MinDist = 0.5; // ustawione +.5 m, zeby nie rozlaczac przy malych odleglosciach - const int MaxCount = 1500; - bool rCF = false; - // distDelta:=0; //Ra: value never used - CNext = Couplers[CouplerN].ConnectedNr; - // if (Couplers[CouplerN].CForce == 0) //nie bylo uzgadniane wiec policz +double TMoverParameters::CouplerForce( int const End, double dt ) { - Couplers[CouplerN].CheckCollision = false; - newdist = Couplers[CouplerN].CoupleDist; // odległość od sprzęgu sąsiada - // newdist:=Distance(Loc,Connected^.Loc,Dim,Connected^.Dim); - if (CouplerN == 0) - { - // ABu: bylo newdist+10*((... - tempdist = ((Couplers[CouplerN].Connected->dMoveLen * - DirPatch(0, Couplers[CouplerN].ConnectedNr)) - - dMoveLen); - newdist += 10.0 * tempdist; - // tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu - } - else - { - // ABu: bylo newdist+10*((... - tempdist = ((dMoveLen - (Couplers[CouplerN].Connected->dMoveLen * - DirPatch(1, Couplers[CouplerN].ConnectedNr)))); - newdist += 10.0 * tempdist; - // tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu - } + auto &coupler { Couplers[ End ] }; + auto *othervehicle { Neighbours[ End ].vehicle->MoverParameters }; + auto const otherend { Neighbours[ End ].vehicle_end }; + auto &othercoupler { othervehicle->Couplers[ otherend ] }; + + auto const othervehiclemove { ( othervehicle->dMoveLen * DirPatch( End, otherend ) ) }; + auto const distancedelta { ( + End == end::front ? + othervehiclemove - dMoveLen : + dMoveLen - othervehiclemove ) }; + auto const initialdistance { Neighbours[ End ].distance }; // odległość od sprzęgu sąsiada + + auto const newdistance = + initialdistance + + 10.0 * distancedelta; + + auto const dV { V - ( othervehicle->V * DirPatch( End, otherend ) ) }; + auto const absdV { std::abs( dV ) }; - dV = V - (double)DirPatch( CouplerN, CNext ) * Couplers[ CouplerN ].Connected->V; - absdV = abs( dV ); // potentially generate sounds on clash or stretch - if( ( newdist < 0.0 ) - && ( Couplers[ CouplerN ].Dist > newdist ) + if( ( newdistance < 0.0 ) + && ( coupler.Dist > newdistance ) && ( dV < -0.5 ) ) { // 090503: dzwieki pracy zderzakow SetFlag( - Couplers[ CouplerN ].sounds, + coupler.sounds, ( absdV > 5.0 ? ( sound::bufferclash | sound::loud ) : sound::bufferclash ) ); } - else if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux ) - && ( newdist > 0.001 ) - && ( Couplers[ CouplerN ].Dist <= 0.001 ) + else if( ( coupler.CouplingFlag != coupling::faux ) + && ( newdistance > 0.001 ) + && ( coupler.Dist <= 0.001 ) && ( absdV > 0.005 ) && ( Vel > 1.0 ) ) { // 090503: dzwieki pracy sprzegu SetFlag( - Couplers[ CouplerN ].sounds, + coupler.sounds, ( absdV > 0.035 ? ( sound::couplerstretch | sound::loud ) : sound::couplerstretch ) ); } - // blablabla - // ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami - //if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then - if( ( Couplers[ CouplerN ].CouplingFlag != coupling::faux ) - || ( Couplers[ CouplerN ].CoupleDist < 0 ) ) { + coupler.CheckCollision = false; + double CF { 0.0 }; - if( Couplers[ CouplerN ].CouplingFlag == coupling::faux ) { + if( ( coupler.CouplingFlag != coupling::faux ) + || ( initialdistance < 0 ) ) { - BetaAvg = Couplers[CouplerN].beta; - Fmax = (Couplers[CouplerN].FmaxC + Couplers[CouplerN].FmaxB) * CouplerTune; + double BetaAvg = 0; + double Fmax = 0; + + if( coupler.CouplingFlag == coupling::faux ) { + + BetaAvg = coupler.beta; + Fmax = (coupler.FmaxC + coupler.FmaxB) * CouplerTune; } - else // usrednij bo wspolny sprzeg - { - BetaAvg = - (Couplers[CouplerN].beta + Couplers[CouplerN].Connected->Couplers[CNext].beta) / - 2.0; - Fmax = (Couplers[CouplerN].FmaxC + Couplers[CouplerN].FmaxB + - Couplers[CouplerN].Connected->Couplers[CNext].FmaxC + - Couplers[CouplerN].Connected->Couplers[CNext].FmaxB) * - CouplerTune / 2.0; + else { + // usrednij bo wspolny sprzeg + BetaAvg = 0.5 * ( coupler.beta + othercoupler.beta ); + Fmax = 0.5 * ( coupler.FmaxC + coupler.FmaxB + othercoupler.FmaxC + othercoupler.FmaxB ) * CouplerTune; } - distDelta = - abs(newdist) - abs(Couplers[CouplerN].Dist); // McZapkie-191103: poprawka na histereze - Couplers[CouplerN].Dist = newdist; - if (Couplers[CouplerN].Dist > 0) - { - if (distDelta > 0) - CF = (-(Couplers[CouplerN].SpringKC + - Couplers[CouplerN].Connected->Couplers[CNext].SpringKC) * - Couplers[CouplerN].Dist / 2.0) * - DirF(CouplerN) - - Fmax * dV * BetaAvg; - else - CF = (-(Couplers[CouplerN].SpringKC + - Couplers[CouplerN].Connected->Couplers[CNext].SpringKC) * - Couplers[CouplerN].Dist / 2.0) * - DirF(CouplerN) * BetaAvg - - Fmax * dV * BetaAvg; + auto const distDelta { std::abs( newdistance ) - std::abs( coupler.Dist ) }; // McZapkie-191103: poprawka na histereze + coupler.Dist = newdistance; + if (coupler.Dist > 0) { + + if( distDelta > 0 ) { + CF = ( -( coupler.SpringKC + othercoupler.SpringKC ) * coupler.Dist / 2.0 ) * DirF( End ) + - Fmax * dV * BetaAvg; + } + else { + CF = ( -( coupler.SpringKC + othercoupler.SpringKC ) * coupler.Dist / 2.0 ) * DirF( End ) * BetaAvg + - Fmax * dV * BetaAvg; + } // liczenie sily ze sprezystosci sprzegu - if (Couplers[CouplerN].Dist > - (Couplers[CouplerN].DmaxC + - Couplers[CouplerN].Connected->Couplers[CNext].DmaxC)) // zderzenie - //***if tempdist>(DmaxC+Connected^.Couplers[CNext].DmaxC) then {zderzenie} - Couplers[CouplerN].CheckCollision = true; + if( coupler.Dist > ( coupler.DmaxC + othercoupler.DmaxC ) ) { + // zderzenie + coupler.CheckCollision = true; + } } - if (Couplers[CouplerN].Dist < 0) - { - if (distDelta > 0) - CF = (-(Couplers[CouplerN].SpringKB + - Couplers[CouplerN].Connected->Couplers[CNext].SpringKB) * - Couplers[CouplerN].Dist / 2.0) * - DirF(CouplerN) - - Fmax * dV * BetaAvg; - else - CF = (-(Couplers[CouplerN].SpringKB + - Couplers[CouplerN].Connected->Couplers[CNext].SpringKB) * - Couplers[CouplerN].Dist / 2.0) * - DirF(CouplerN) * BetaAvg - - Fmax * dV * BetaAvg; + if( coupler.Dist < 0 ) { + + if( distDelta > 0 ) { + CF = ( -( coupler.SpringKB + othercoupler.SpringKB ) * coupler.Dist / 2.0 ) * DirF( End ) + - Fmax * dV * BetaAvg; + } + else { + CF = ( -( coupler.SpringKB + othercoupler.SpringKB ) * coupler.Dist / 2.0 ) * DirF( End ) * BetaAvg + - Fmax * dV * BetaAvg; + } // liczenie sily ze sprezystosci zderzaka - if (-Couplers[CouplerN].Dist > - (Couplers[CouplerN].DmaxB + - Couplers[CouplerN].Connected->Couplers[CNext].DmaxB)) // zderzenie - //***if -tempdist>(DmaxB+Connected^.Couplers[CNext].DmaxB)/10 then {zderzenie} - { - Couplers[CouplerN].CheckCollision = true; - if( ( Couplers[ CouplerN ].CouplerType == TCouplerType::Automatic ) - && ( Couplers[ CouplerN ].CouplingFlag == coupling::faux ) ) { - // sprzeganie wagonow z samoczynnymi sprzegami} - // CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic; + if( -coupler.Dist > ( coupler.DmaxB + othercoupler.DmaxB ) ) { + // zderzenie + coupler.CheckCollision = true; + if( ( coupler.CouplerType == TCouplerType::Automatic ) + && ( coupler.CouplingFlag == coupling::faux ) ) { + // sprzeganie wagonow z samoczynnymi sprzegami // EN57 - Couplers[ CouplerN ].CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/; - SetFlag( Couplers[ CouplerN ].sounds, sound::attachcoupler ); + // TBD, TODO: configurable flag for automatic coupling + coupler.CouplingFlag = coupling::coupler /*| coupling::brakehose | coupling::mainhose | coupling::control*/; + SetFlag( coupler.sounds, sound::attachcoupler ); } } } } - if( Couplers[ CouplerN ].CouplingFlag != coupling::faux ) { + + if( coupler.CouplingFlag != coupling::faux ) { // uzgadnianie prawa Newtona - Couplers[ CouplerN ].Connected->Couplers[ 1 - CouplerN ].CForce = -CF; + othervehicle->Couplers[ 1 - End ].CForce = -CF; } return CF; @@ -5314,7 +5207,7 @@ double TMoverParameters::TractionForce( double dt ) { // Q: 20160713 //Obliczenie predkości obrotowej kół??? // ************************************************************************************************* -double TMoverParameters::ComputeRotatingWheel(double WForce, double dt, double n) +double TMoverParameters::ComputeRotatingWheel(double WForce, double dt, double n) const { double newn = 0, eps = 0; if ((n == 0) && (WForce * Sign(V) < 0)) @@ -7150,17 +7043,16 @@ double TMoverParameters::GetTrainsetVoltage(void) // ************************************************************************************************* // Kasowanie zmiennych pracy fizyki // ************************************************************************************************* -bool TMoverParameters::Physic_ReActivation(void) // DO PRZETLUMACZENIA NA KONCU +bool TMoverParameters::switch_physics(bool const State) // DO PRZETLUMACZENIA NA KONCU { -// bool pr; - if (PhysicActivation) - return false; - else - { - PhysicActivation = true; + if( PhysicActivation == State ) { return false; } + + PhysicActivation = State; + if( true == State ) { LastSwitchingTime = 0; - return true; } + + return true; } // ************************************************************************************************* @@ -9970,8 +9862,7 @@ bool TMoverParameters::RunInternalCommand() CommandIn.Location.X = 0; CommandIn.Location.Y = 0; CommandIn.Location.Z = 0; - if (!PhysicActivation) - Physic_ReActivation(); + switch_physics( true ); } } else diff --git a/Train.cpp b/Train.cpp index 1aab4f76..ef173233 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4867,11 +4867,11 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm if( false == Train->CabChange( 1 ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ end::front ].CouplingFlag, coupling::gangway ) ) { // przejscie do nastepnego pojazdu - Global.changeDynObj = Train->DynamicObject->PrevConnected; + Global.changeDynObj = Train->DynamicObject->PrevConnected(); Global.changeDynObj->MoverParameters->ActiveCab = ( - Train->DynamicObject->PrevConnectedNo ? - -1 : - 1 ); + Train->DynamicObject->MoverParameters->Neighbours[end::front].vehicle_end ? + -1 : + 1 ); } } } @@ -4883,11 +4883,11 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com if( false == Train->CabChange( -1 ) ) { if( TestFlag( Train->DynamicObject->MoverParameters->Couplers[ end::rear ].CouplingFlag, coupling::gangway ) ) { // przejscie do nastepnego pojazdu - Global.changeDynObj = Train->DynamicObject->NextConnected; + Global.changeDynObj = Train->DynamicObject->NextConnected(); Global.changeDynObj->MoverParameters->ActiveCab = ( - Train->DynamicObject->NextConnectedNo ? - -1 : - 1 ); + Train->DynamicObject->MoverParameters->Neighbours[end::rear].vehicle_end ? + -1 : + 1 ); } } } @@ -5260,14 +5260,14 @@ bool TTrain::Update( double const Deltatime ) { TDynamicObject *tmp; tmp = NULL; - if (DynamicObject->NextConnected) + if (DynamicObject->NextConnected()) if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && (mvOccupied->ActiveCab == 1)) - tmp = DynamicObject->NextConnected; - if (DynamicObject->PrevConnected) + tmp = DynamicObject->NextConnected(); + if (DynamicObject->PrevConnected()) if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && (mvOccupied->ActiveCab == -1)) - tmp = DynamicObject->PrevConnected; + tmp = DynamicObject->PrevConnected(); if( tmp ) { if( tmp->MoverParameters->Power > 0 ) { if( ggI1B.SubModel ) { @@ -5668,10 +5668,10 @@ bool TTrain::Update( double const Deltatime ) tmp = NULL; if ((TestFlag(mvControlled->Couplers[1].CouplingFlag, ctrain_controll)) && (mvOccupied->ActiveCab > 0)) - tmp = DynamicObject->NextConnected; + tmp = DynamicObject->NextConnected(); if ((TestFlag(mvControlled->Couplers[0].CouplingFlag, ctrain_controll)) && (mvOccupied->ActiveCab < 0)) - tmp = DynamicObject->PrevConnected; + tmp = DynamicObject->PrevConnected(); if (tmp) if ( mvControlled->Battery || mvControlled->ConverterFlag ) { @@ -6954,26 +6954,25 @@ void TTrain::DynamicSet(TDynamicObject *d) mvOccupied = mvControlled = d ? DynamicObject->MoverParameters : NULL; // albo silnikowy w EZT if (!DynamicObject) return; - if (mvControlled->TrainType & dt_EZT) // na razie dotyczy to EZT - if (DynamicObject->NextConnected ? mvControlled->Couplers[1].AllowedFlag & ctrain_depot : - false) - { // gdy jest człon od sprzęgu 1, a sprzęg łączony - // warsztatowo (powiedzmy) - if ((mvControlled->Power < 1.0) && (mvControlled->Couplers[1].Connected->Power > - 1.0)) // my nie mamy mocy, ale ten drugi ma - mvControlled = - DynamicObject->NextConnected->MoverParameters; // będziemy sterować tym z mocą + // TODO: leverage code already present in TDynamicObject::ControlledFind() + if( ( d->MoverParameters->TrainType == dt_EZT ) + || ( d->MoverParameters->TrainType == dt_DMU ) ) { + + if( ( d->NextConnected() != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ end::rear ].AllowedFlag, coupling::permanent ) ) ) { + if( ( mvControlled->Power < 1.0 ) && ( mvControlled->Couplers[ 1 ].Connected->Power > 1.0 ) ) { + // my nie mamy mocy, ale ten drugi ma + mvControlled = DynamicObject->NextConnected()->MoverParameters; // będziemy sterować tym z mocą + } } - else if (DynamicObject->PrevConnected ? - mvControlled->Couplers[0].AllowedFlag & ctrain_depot : - false) - { // gdy jest człon od sprzęgu 0, a sprzęg łączony - // warsztatowo (powiedzmy) - if ((mvControlled->Power < 1.0) && (mvControlled->Couplers[0].Connected->Power > - 1.0)) // my nie mamy mocy, ale ten drugi ma - mvControlled = - DynamicObject->PrevConnected->MoverParameters; // będziemy sterować tym z mocą + else if( ( d->PrevConnected() != nullptr ) + && ( true == TestFlag( d->MoverParameters->Couplers[ end::front ].AllowedFlag, coupling::permanent ) ) ) { + if( ( mvControlled->Power < 1.0 ) && ( mvControlled->Couplers[ 0 ].Connected->Power > 1.0 ) ) { + // my nie mamy mocy, ale ten drugi ma + mvControlled = DynamicObject->PrevConnected()->MoverParameters; // będziemy sterować tym z mocą + } } + } mvSecond = NULL; // gdyby się nic nie znalazło if (mvOccupied->Power > 1.0) // dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo if (mvOccupied->Couplers[1].Connected ? diff --git a/driveruipanels.cpp b/driveruipanels.cpp index a4f9ca01..5957935d 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -218,8 +218,7 @@ timetable_panel::update() { auto consistmass { owner->fMass }; auto consistlength { owner->fLength }; if( ( owner->mvControlling->TrainType != dt_DMU ) - && ( owner->mvControlling->TrainType != dt_EZT ) - && ( owner->pVehicles[end::front] != owner->pVehicles[end::rear] ) ) { + && ( owner->mvControlling->TrainType != dt_EZT ) ) { //odejmij lokomotywy czynne, a przynajmniej aktualną consistmass -= owner->pVehicle->MoverParameters->TotalMass; // subtract potential other half of a two-part vehicle @@ -227,7 +226,6 @@ timetable_panel::update() { if( previous != nullptr ) { consistmass -= previous->MoverParameters->TotalMass; } auto const *next { owner->pVehicle->NextC( coupling::permanent ) }; if( next != nullptr ) { consistmass -= next->MoverParameters->TotalMass; } -// consistlength -= owner->pVehicle->MoverParameters->Dim.L; } std::snprintf( m_buffer.data(), m_buffer.size(), @@ -563,10 +561,7 @@ debug_panel::update_vehicle_coupler( int const Side ) { // NOTE: mover and vehicle are guaranteed to be valid by the caller std::string couplerstatus { locale::strings[ locale::string::debug_vehicle_none ] }; - auto const *connected { ( - Side == end::front ? - m_input.vehicle->PrevConnected : - m_input.vehicle->NextConnected ) }; + auto const *connected { m_input.vehicle->MoverParameters->Neighbours[ Side ].vehicle }; if( connected == nullptr ) { return couplerstatus; } @@ -574,10 +569,10 @@ debug_panel::update_vehicle_coupler( int const Side ) { std::snprintf( m_buffer.data(), m_buffer.size(), - "%s [%d]%s", + "%s [%d] (%.1f m)", connected->name().c_str(), mover.Couplers[ Side ].CouplingFlag, - std::string( mover.Couplers[ Side ].CouplingFlag == 0 ? " (" + to_string( mover.Couplers[ Side ].CoupleDist, 1 ) + " m)" : "" ).c_str() ); + mover.Neighbours[ Side ].distance ); return { m_buffer.data() }; } @@ -700,6 +695,10 @@ debug_panel::update_section_ai( std::vector &Output ) { "Distances:\n proximity: " + to_string( mechanik.ActualProximityDist, 0 ) + ", braking: " + to_string( mechanik.fBrakeDist, 0 ); + if( mechanik.Obstacle.distance < 5000 ) { + textline += "\n obstacle: " + to_string( mechanik.Obstacle.distance, 0 ); + } + Output.emplace_back( textline, Global.UITextColor ); // velocity factors From 8da3a9a74ff0e9bf147377c14164d9e33c610557 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 24 Feb 2019 02:26:53 +0100 Subject: [PATCH 6/7] build 190223. doorstep cab control devices, door control system logic tweaks and fixes --- Button.cpp | 9 ++--- Button.h | 2 +- Driver.cpp | 9 +++-- DynObj.cpp | 43 +++++++++++------------ Gauge.cpp | 36 ++++++++++++++------ Gauge.h | 2 ++ McZapkie/MOVER.h | 4 +++ McZapkie/Mover.cpp | 75 ++++++++++++++++++++++++++++++----------- Train.cpp | 62 ++++++++++++++++++++++------------ Train.h | 5 +-- command.cpp | 1 + command.h | 1 + driverkeyboardinput.cpp | 1 + drivermouseinput.cpp | 3 ++ translation.cpp | 3 ++ translation.h | 1 + version.h | 2 +- 17 files changed, 176 insertions(+), 83 deletions(-) diff --git a/Button.cpp b/Button.cpp index 6b971d9c..24644d24 100644 --- a/Button.cpp +++ b/Button.cpp @@ -123,12 +123,13 @@ TButton::Turn( bool const State ) { } } -void TButton::Update() { +void TButton::Update( bool const Power ) { - if( ( bData != nullptr ) - && ( *bData != m_state ) ) { + auto const state { Power && ( bData ? *bData : m_state ) }; - m_state = ( *bData ); + if( state != m_state ) { + + m_state = state; play(); } diff --git a/Button.h b/Button.h index 67bd312d..1bbe4b16 100644 --- a/Button.h +++ b/Button.h @@ -30,7 +30,7 @@ public: bool Active() { return ( ( pModelOn != nullptr ) || ( pModelOff != nullptr ) ); } - void Update(); + void Update( bool const Power = true ); bool Init( std::string const &asName, TModel3d const *pModel, bool bNewOn = false ); void Load( cParser &Parser, TDynamicObject const *Owner ); void AssignBool(bool const *bValue); diff --git a/Driver.cpp b/Driver.cpp index 2f7a191b..edcf3fe0 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3274,6 +3274,10 @@ void TController::Doors( bool const Open, int const Side ) { // the train conductor, if present, handles door operation also for human-driven trains pVehicle->MoverParameters->OperateDoors( side::right, false ); pVehicle->MoverParameters->OperateDoors( side::left, false ); + if( pVehicle->MoverParameters->Doors.permit_needed ) { + pVehicle->MoverParameters->PermitDoors( side::right, false ); + pVehicle->MoverParameters->PermitDoors( side::left, false ); + } } auto *vehicle = pVehicles[ 0 ]; // pojazd na czole składu @@ -4184,11 +4188,12 @@ TController::UpdateSituation(double dt) { { // HACK: vehicle order in the consist is based on intended travel direction // if our actual travel direction doesn't match that, we should be scanning from the other end of the consist - auto *frontvehicle { pVehicles[ ( mvOccupied->V * iDirection >= 0 ? end::front : end::rear ) ] }; + // we cast to int to avoid getting confused by microstutters + auto *frontvehicle { pVehicles[ ( static_cast( mvOccupied->V ) * iDirection >= 0 ? end::front : end::rear ) ] }; int routescandirection; // for moving vehicle determine heading from velocity; for standing fall back on the set direction - if( ( std::abs( frontvehicle->MoverParameters->V ) > 0.1 ? // ignore potential micro-stutters in oposite direction during "almost stop" + if( ( std::abs( frontvehicle->MoverParameters->V ) > 0.5 ? // ignore potential micro-stutters in oposite direction during "almost stop" frontvehicle->MoverParameters->V > 0.0 : ( pVehicle->DirectionGet() == frontvehicle->DirectionGet() ? iDirection > 0 : diff --git a/DynObj.cpp b/DynObj.cpp index 870e9ee4..d79f24f5 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2745,10 +2745,13 @@ bool TDynamicObject::Update(double dt, double dt1) auto const amax = RapidMult * std::min(FmaxPN / masamax, MoverParameters->MED_amax); auto const doorisopen { - ( false == MoverParameters->Doors.instances[ side::right ].is_closed ) - || ( false == MoverParameters->Doors.instances[ side::left ].is_closed ) }; + ( false == MoverParameters->Doors.instances[ side::left ].is_closed ) + || ( false == MoverParameters->Doors.instances[ side::right ].is_closed ) + || ( MoverParameters->Doors.permit_needed + && ( MoverParameters->Doors.instances[ side::left ].open_permit + || MoverParameters->Doors.instances[ side::right ].open_permit ) ) }; - if ((MoverParameters->Vel < 0.5) && (MoverParameters->BrakePress > 0.2) || doorisopen ) + if ((MoverParameters->Vel < 0.5) && (MoverParameters->BrakePress > 0.2 || doorisopen)) { MoverParameters->ShuntMode = true; } @@ -3822,15 +3825,6 @@ void TDynamicObject::RenderSounds() { } } } - // doorstep sounds - if( door.step_position < 1.f ) { - for( auto &doorsounds : m_doorsounds ) { - if( doorsounds.placement == side ) { - doorsounds.step_open.play( sound_flags::exclusive ); - doorsounds.step_close.stop(); - } - } - } } if( true == door.is_closing ) { // door sounds can start playing before the door begins moving but shouldn't cease once the door closes @@ -3843,15 +3837,22 @@ void TDynamicObject::RenderSounds() { } } } - // doorstep sounds are played only when the doorstep is moving - if( ( door.step_position > 0.f ) - && ( door.step_position < 1.f ) ) { - for( auto &doorsounds : m_doorsounds ) { - if( doorsounds.placement == side ) { - // determine left side doors from their offset - doorsounds.step_close.play( sound_flags::exclusive ); - doorsounds.step_open.stop(); - } + } + // doorstep sounds + if( door.step_unfolding ) { + for( auto &doorsounds : m_doorsounds ) { + if( doorsounds.placement == side ) { + doorsounds.step_open.play( sound_flags::exclusive ); + doorsounds.step_close.stop(); + } + } + } + if( door.step_folding ) { + for( auto &doorsounds : m_doorsounds ) { + if( doorsounds.placement == side ) { + // determine left side doors from their offset + doorsounds.step_close.play( sound_flags::exclusive ); + doorsounds.step_open.stop(); } } } diff --git a/Gauge.cpp b/Gauge.cpp index 79218ce8..0ee74581 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -360,21 +360,35 @@ void TGauge::AssignInt(int *iValue) iData = iValue; }; +void TGauge::AssignBool(bool *bValue) +{ + m_datatype = 'b'; + bData = bValue; +}; + void TGauge::UpdateValue() { // ustawienie wartości docelowej z parametru switch (m_datatype) { // to nie jest zbyt optymalne, można by zrobić osobne funkcje - case 'f': - UpdateValue( *fData ); - break; - case 'd': - UpdateValue( *dData ); - break; - case 'i': - UpdateValue( *iData ); - break; - default: - break; + case 'f': { + UpdateValue( *fData ); + break; + } + case 'd': { + UpdateValue( *dData ); + break; + } + case 'i': { + UpdateValue( *iData ); + break; + } + case 'b': { + UpdateValue( ( *bData ? 1.f : 0.f ) ); + break; + } + default: { + break; + } } }; diff --git a/Gauge.h b/Gauge.h index e812831b..0a84d5d9 100644 --- a/Gauge.h +++ b/Gauge.h @@ -48,6 +48,7 @@ public: void AssignFloat(float *fValue); void AssignDouble(double *dValue); void AssignInt(int *iValue); + void AssignBool(bool *bValue); void UpdateValue(); // returns offset of submodel associated with the button from the model centre glm::vec3 model_offset() const; @@ -82,6 +83,7 @@ private: float *fData; double *dData { nullptr }; int *iData; + bool *bData; }; int m_soundtype { 0 }; // toggle between exclusive and multiple sound generation sound_source m_soundtemplate { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; // shared properties for control's sounds diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 8c5e0969..d56bbf16 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -723,6 +723,8 @@ private: bool is_closing { false }; // the door is currently closing bool is_opening { false }; // the door is currently opening bool is_open { false }; // the door is fully open + bool step_folding { false }; // the doorstep is currently closing + bool step_unfolding { false }; // the doorstep is currently opening }; struct door_data { @@ -748,6 +750,7 @@ private: std::vector permit_presets; // permit presets selectable with preset switch // ld inputs bool lock_enabled { true }; + bool step_enabled { true }; // internal data int permit_preset { -1 }; // curent position of preset selection switch // vehicle parts @@ -1493,6 +1496,7 @@ public: bool LoadingDone(double LSpeed, std::string const &Loadname); bool PermitDoors( side const Door, bool const State = true, range_t const Notify = range_t::consist ); bool ChangeDoorPermitPreset( int const Change, range_t const Notify = range_t::consist ); + bool PermitDoorStep( bool const State, range_t const Notify = range_t::consist ); bool OperateDoors( side const Door, bool const State, range_t const Notify = range_t::consist ); bool LockDoors( bool const State, range_t const Notify = range_t::consist ); bool signal_departure( bool const State, range_t const Notify = range_t::consist ); // toggles departure warning diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index f39e97ae..c3dbec3d 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -4956,8 +4956,9 @@ double TMoverParameters::TractionForce( double dt ) { } dtrans = Hamulec->GetEDBCP(); - if( ( ( false == Doors.instances[ side::left ].is_closed ) - || ( false == Doors.instances[ side::right ].is_closed ) ) ) { + if( ( false == Doors.instances[ side::left ].is_closed ) + || ( false == Doors.instances[ side::right ].is_closed ) + || ( Doors.permit_needed && ( Doors.instances[ side::left ].open_permit || Doors.instances[ side::right ].open_permit ) ) ) { DynamicBrakeFlag = true; } else if (((dtrans < 0.25) && (LocHandle->GetCP() < 0.25) && (AnPos < 0.01)) || @@ -6637,6 +6638,27 @@ bool TMoverParameters::ChangeDoorPermitPreset( int const Change, range_t const N return ( Doors.permit_preset != initialstate ); } +bool TMoverParameters::PermitDoorStep( bool const State, range_t const Notify ) { + + auto const initialstate { Doors.step_enabled }; + + Doors.step_enabled = State; + if( Notify != range_t::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "DoorStep", + ( State == true ? + 1 : + 0 ), + CabNo, + ( Notify == range_t::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( Doors.step_enabled != initialstate ); +} + bool TMoverParameters::PermitDoors( side const Door, bool const State, range_t const Notify ) { bool const initialstate { Doors.instances[Door].open_permit }; @@ -6719,6 +6741,8 @@ bool TMoverParameters::OperateDoors( side const Door, bool const State, range_t // toggle door lock bool TMoverParameters::LockDoors( bool const State, range_t const Notify ) { + auto const initialstate { Doors.lock_enabled }; + Doors.lock_enabled = State; if( Notify != range_t::local ) { // wysłanie wyłączenia do pozostałych? @@ -6733,7 +6757,7 @@ bool TMoverParameters::LockDoors( bool const State, range_t const Notify ) { coupling::control ) ); } - return true; + return ( Doors.lock_enabled != initialstate ); } // toggles departure warning @@ -6799,7 +6823,8 @@ TMoverParameters::update_doors( double const Deltatime ) { door.is_open = ( door.position >= Doors.range ) - && ( door.step_position >= ( Doors.step_range != 0.f ? 1.f : 0.f ) ); + && ( ( false == Doors.step_enabled ) + || ( door.step_position >= ( Doors.step_range != 0.f ? 1.f : 0.f ) ) ); door.is_closed = ( door.position <= 0.f ) && ( door.step_position <= 0.f ); @@ -6833,6 +6858,19 @@ TMoverParameters::update_doors( double const Deltatime ) { && ( true == Battery ) && ( false == openrequest ) && ( door.is_closing || closerequest ); + door.step_unfolding = ( + ( Doors.step_range != 0.f ) + && ( Doors.step_enabled ) + && ( false == Doors.is_locked ) + && ( door.step_position < 1.f ) + && ( door.is_opening ) ); + door.step_folding = ( + ( door.step_position > 0.f ) // is unfolded + && ( ( false == Doors.step_enabled ) // we lost permission to stay open or our door is calling the shots + || ( Doors.permit_needed ? + ( false == door.open_permit ) : + door.is_closing ) ) + && ( ( door.close_delay > Doors.close_delay ) || door.position <= 0.f ) ); // door is about to close, or already done if( true == door.is_opening ) { door.auto_timer = ( @@ -6840,17 +6878,14 @@ TMoverParameters::update_doors( double const Deltatime ) { ( remoteopencontrol && door.remote_open && Doors.auto_include_remote ) ? Doors.auto_duration : -1.f ); } - // doors - if( ( true == door.is_opening ) - && ( door.position < Doors.range ) ) { + if( true == door.is_opening ) { // open door if( ( TrainType == dt_EZT ) || ( TrainType == dt_DMU ) ) { // multi-unit vehicles typically open door only after unfolding the doorstep - if( ( Doors.step_range == 0.f ) // no wait if no doorstep - || ( Doors.step_type == 2 ) // no wait for rotating doorstep - || ( door.step_position == 1.f ) ) { + if( ( false == door.step_unfolding ) // no wait if no doorstep + || ( Doors.step_type == 2 ) ) { // no wait for rotating doorstep door.position = std::min( Doors.range, door.position + Doors.open_rate * Deltatime ); @@ -6863,8 +6898,7 @@ TMoverParameters::update_doors( double const Deltatime ) { } door.close_delay = 0.f; } - if( ( true == door.is_closing ) - && ( door.position > 0.f ) ) { + if( true == door.is_closing ) { // close door door.close_delay += Deltatime; if( door.close_delay > Doors.close_delay ) { @@ -6874,22 +6908,18 @@ TMoverParameters::update_doors( double const Deltatime ) { } } // doorsteps - if( ( true == door.is_opening ) - && ( Doors.step_range != 0.f ) - && ( door.step_position < 1.f ) ) { + if( door.step_unfolding ) { // unfold left doorstep door.step_position = std::min( 1.f, door.step_position + Doors.step_rate * Deltatime ); } - if( ( true == door.is_closing ) - && ( door.step_position > 0.f ) - && ( door.close_delay > Doors.close_delay ) ) { + if( door.step_folding ) { // fold left doorstep if( ( TrainType == dt_EZT ) || ( TrainType == dt_DMU ) ) { // multi-unit vehicles typically fold the doorstep only after closing the door - if( door.position == 0.f ) { + if( door.position <= 0.f ) { door.step_position = std::max( 0.f, door.step_position - Doors.step_rate * Deltatime ); @@ -9640,6 +9670,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C false ); OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } + else if( Command == "DoorStep" ) { + Doors.step_enabled = ( + CValue1 == 1 ? + true : + false ); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if( Command == "DepartureSignal" ) { DepartureSignal = ( CValue1 == 1 ? diff --git a/Train.cpp b/Train.cpp index ef173233..30f82b53 100644 --- a/Train.cpp +++ b/Train.cpp @@ -138,28 +138,17 @@ TButton &TCab::Button(int n) } }; -void TCab::Update() +void TCab::Update( bool const Power ) { // odczyt parametrów i ustawienie animacji submodelom -/* - int i; - for (i = 0; i < iGauges; ++i) - { // animacje izometryczne - ggList[i].UpdateValue(); // odczyt parametru i przeliczenie na kąt - ggList[i].Update(); // ustawienie animacji - } - for (i = 0; i < iButtons; ++i) - { // animacje dwustanowe - btList[i].Update(); // odczyt parametru i wybór submodelu - } -*/ for( auto &gauge : ggList ) { // animacje izometryczne gauge.UpdateValue(); // odczyt parametru i przeliczenie na kąt gauge.Update(); // ustawienie animacji } + for( auto &button : btList ) { // animacje dwustanowe - button.Update(); // odczyt parametru i wybór submodelu + button.Update( Power ); // odczyt parametru i wybór submodelu } }; @@ -333,6 +322,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::doorcloseright, &TTrain::OnCommand_doorcloseright }, { user_command::dooropenall, &TTrain::OnCommand_dooropenall }, { user_command::doorcloseall, &TTrain::OnCommand_doorcloseall }, + { user_command::doorsteptoggle, &TTrain::OnCommand_doorsteptoggle }, { user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease }, { user_command::carcouplingdisconnect, &TTrain::OnCommand_carcouplingdisconnect }, { user_command::departureannounce, &TTrain::OnCommand_departureannounce }, @@ -4598,6 +4588,13 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command } } +void TTrain::OnCommand_doorsteptoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + Train->mvOccupied->PermitDoorStep( false == Train->mvOccupied->Doors.step_enabled ); + } +} + void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ) { if( ( true == FreeFlyModeFlag ) @@ -5308,7 +5305,7 @@ bool TTrain::Update( double const Deltatime ) ggClockHInd.Update(); } - Cabine[iCabn].Update(); // nowy sposób ustawienia animacji + Cabine[iCabn].Update( mvControlled->Battery || mvControlled->ConverterFlag ); // nowy sposób ustawienia animacji if (ggZbS.SubModel) { ggZbS.UpdateValue(mvOccupied->Handle->GetCP()); @@ -7678,7 +7675,8 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co // TODO: move viable dedicated lights to the automatic light array std::unordered_map const autolights = { { "i-doorpermit_left:", &mvOccupied->Doors.instances[side::left].open_permit }, - { "i-doorpermit_right:", &mvOccupied->Doors.instances[ side::right ].open_permit } + { "i-doorpermit_right:", &mvOccupied->Doors.instances[ side::right ].open_permit }, + { "i-doorstep:", &mvOccupied->Doors.step_enabled } }; { auto lookup = autolights.find( Label ); @@ -7835,14 +7833,31 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "universal8:", ggUniversals[ 8 ] }, { "universal9:", ggUniversals[ 9 ] } }; - auto lookup = gauges.find( Label ); - if( lookup != gauges.end() ) { - lookup->second.Load( Parser, DynamicObject); - m_controlmapper.insert( lookup->second, lookup->first ); - return true; + { + auto lookup = gauges.find( Label ); + if( lookup != gauges.end() ) { + lookup->second.Load( Parser, DynamicObject ); + m_controlmapper.insert( lookup->second, lookup->first ); + return true; + } } + // TODO: move viable dedicated gauges to the automatic array + std::unordered_map const autoboolgauges = { + { "doorstep_sw:", &mvOccupied->Doors.step_enabled } + }; + { + auto lookup = autoboolgauges.find( Label ); + if( lookup != autoboolgauges.end() ) { + auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna lampka + gauge.Load( Parser, DynamicObject ); + gauge.AssignBool( lookup->second ); + m_controlmapper.insert( gauge, lookup->first ); + return true; + } + } + // ABu 090305: uniwersalne przyciski lub inne rzeczy - else if( Label == "mainctrlact:" ) { + if( Label == "mainctrlact:" ) { ggMainCtrlAct.Load( Parser, DynamicObject); } // SEKCJA WSKAZNIKOW @@ -8032,6 +8047,9 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con } } } + else if( Label == "clock_seconds:" ) { + ggClockSInd.Load( Parser, DynamicObject ); + } else if (Label == "evoltage:") { // woltomierz napiecia silnikow diff --git a/Train.h b/Train.h index 7ebaff11..35701da2 100644 --- a/Train.h +++ b/Train.h @@ -32,7 +32,7 @@ class TCab { public: // methods void Load(cParser &Parser); - void Update(); + void Update( bool const Power ); TGauge &Gauge( int n = -1 ); // pobranie adresu obiektu TButton &Button( int n = -1 ); // pobranie adresu obiektu // members @@ -51,7 +51,7 @@ public: private: // members - std::vector ggList; + std::deque ggList; // need a container which doesn't invalidate references std::vector btList; }; @@ -323,6 +323,7 @@ class TTrain static void OnCommand_doorcloseright( TTrain *Train, command_data const &Command ); static void OnCommand_dooropenall( TTrain *Train, command_data const &Command ); static void OnCommand_doorcloseall( TTrain *Train, command_data const &Command ); + static void OnCommand_doorsteptoggle( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_departureannounce( TTrain *Train, command_data const &Command ); diff --git a/command.cpp b/command.cpp index fda03c21..b4036625 100644 --- a/command.cpp +++ b/command.cpp @@ -152,6 +152,7 @@ commanddescription_sequence Commands_descriptions = { { "doorcloseleft", command_target::vehicle }, { "doorcloseright", command_target::vehicle }, { "doorcloseall", command_target::vehicle }, + { "doorsteptoggle", command_target::vehicle }, { "departureannounce", command_target::vehicle }, { "doorlocktoggle", command_target::vehicle }, { "pantographcompressorvalvetoggle", command_target::vehicle }, diff --git a/command.h b/command.h index f5875aa5..c873cdee 100644 --- a/command.h +++ b/command.h @@ -145,6 +145,7 @@ enum class user_command { doorcloseleft, doorcloseright, doorcloseall, + doorsteptoggle, departureannounce, doorlocktoggle, pantographcompressorvalvetoggle, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 7da92746..80225887 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -154,6 +154,7 @@ driverkeyboard_input::default_bindings() { // doorcloseleft, // doorcloseright, { user_command::doorcloseall, GLFW_KEY_SLASH | keymodifier::control }, + // doorsteptoggle, { user_command::departureannounce, GLFW_KEY_SLASH }, { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::control }, { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index d0ff7b5b..6237935c 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -584,6 +584,9 @@ drivermouse_input::default_bindings() { { "dooralloff_sw:", { user_command::doorcloseall, user_command::none } }, + { "doorstep_sw:", { + user_command::doorsteptoggle, + user_command::none } }, { "departure_signal_bt:", { user_command::departureannounce, user_command::none } }, diff --git a/translation.cpp b/translation.cpp index 09811e91..854cbfdf 100644 --- a/translation.cpp +++ b/translation.cpp @@ -109,6 +109,7 @@ init() { "right door (close)", "all doors (open)", "all doors (close)", + "doorstep", "departure signal", "upper headlight", "left headlight", @@ -252,6 +253,7 @@ init() { "drzwi prawe (zamknij)", "drzwi (otworz)", "drzwi (zamknij)", + "stopien drzwi", "sygnal odjazdu", "reflektor gorny", "reflektor lewy", @@ -366,6 +368,7 @@ init() { "doorrightoff_sw:", "doorallon_sw:", "dooralloff_sw:", + "doorstep_sw:", "departure_signal_bt:", "upperlight_sw:", "leftlight_sw:", diff --git a/translation.h b/translation.h index aa0ab028..d991a771 100644 --- a/translation.h +++ b/translation.h @@ -98,6 +98,7 @@ enum string { cab_doorrightoff_sw, cab_doorallon_sw, cab_dooralloff_sw, + cab_doorstep_sw, cab_departure_signal_bt, cab_upperlight_sw, cab_leftlight_sw, diff --git a/version.h b/version.h index 35fb08b2..e1d32d9f 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 215 +#define VERSION_MINOR 223 #define VERSION_REVISION 0 From e356172a8154cb3448ff7032ee658364c8b8c9c4 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 27 Feb 2019 16:22:46 +0100 Subject: [PATCH 7/7] build 190227. joint master controlled cab control, minor bug fixes --- Driver.cpp | 58 ++++++++++++---------- DynObj.cpp | 4 +- Event.cpp | 6 ++- Train.cpp | 105 ++++++++++++++++++++++++++++++++++++---- Train.h | 2 + command.cpp | 1 + command.h | 1 + driverkeyboardinput.cpp | 1 + drivermouseinput.cpp | 48 ++++++++++++++++-- drivermouseinput.h | 1 + driveruipanels.cpp | 4 +- scenenode.cpp | 6 ++- scenenode.h | 4 +- translation.cpp | 3 ++ translation.h | 1 + version.h | 2 +- 16 files changed, 200 insertions(+), 47 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index edcf3fe0..bf336f98 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -372,14 +372,13 @@ bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders orde iFlags = spEvent; evEvent = event; vPos = event->input_location(); // współrzędne eventu albo komórki pamięci (zrzutować na tor?) - if( dist + length >= 0 ) { - iFlags |= spEnabled; - CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości - } - else { - // located behind the tracking consist, don't bother with it + // ignore events located behind the consist, but with exception of stop points which may be needed to update freshly received timetable + if( ( dist + length < 0 ) + && ( event->input_command() != TCommandType::cm_PassengerStopPoint ) ) { return false; } + iFlags |= spEnabled; + CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości // zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa // jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania // WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order)); @@ -486,6 +485,20 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) if (iTableDirection != iDirection ) { // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem + TableClear(); +/* + // aktualna prędkość // changed to -1 to recognize speed limit, if any + fLastVel = -1.0; + sSpeedTable.clear(); + iLast = -1; + tLast = nullptr; //żaden nie sprawdzony + SemNextIndex = -1; + SemNextStopIndex = -1; +*/ + if( VelSignalLast == 0.0 ) { + // don't allow potential red light overrun keep us from reversing + VelSignalLast = -1.0; + } iTableDirection = iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1) @@ -503,17 +516,6 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) .Length(); // aktualna odległość ma być ujemna gdyż jesteśmy na końcu składu fCurrentDistance = -fLength - fTrackLength; - // aktualna prędkość // changed to -1 to recognize speed limit, if any - fLastVel = -1.0; - sSpeedTable.clear(); - iLast = -1; - tLast = nullptr; //żaden nie sprawdzony - SemNextIndex = -1; - SemNextStopIndex = -1; - if( VelSignalLast == 0.0 ) { - // don't allow potential red light overrun keep us from reversing - VelSignalLast = -1.0; - } fTrackLength = pTrack->Length(); //skasowanie zmian w zmiennej żeby poprawnie liczyło w dalszych krokach MoveDistanceReset(); // AI startuje 1s po zaczęciu jazdy i mógł już coś przejechać } @@ -759,7 +761,7 @@ void TController::TableCheck(double fDistance) { // przeliczenie odległości w tabelce, ewentualnie doskanowanie (bez analizy prędkości itp.) if( iTableDirection != iDirection ) { // jak zmiana kierunku, to skanujemy od końca składu - TableTraceRoute( fDistance, pVehicles[ 1 ] ); + TableTraceRoute( fDistance, pVehicles[ end::rear ] ); TableSort(); } else if (iTableDirection) @@ -786,7 +788,7 @@ void TController::TableCheck(double fDistance) --iLast; } tLast = sSpeedTable[ i ].trTrack; - TableTraceRoute( fDistance, pVehicles[ 1 ] ); + TableTraceRoute( fDistance, pVehicles[ end::rear ] ); TableSort(); // nie kontynuujemy pętli, trzeba doskanować ciąg dalszy break; @@ -824,7 +826,7 @@ void TController::TableCheck(double fDistance) sSpeedTable[iLast].Update(); // aktualizacja ostatniego // WriteLog("TableCheck: Upate last track. Dist=" + AnsiString(sSpeedTable[iLast].fDist)); if( sSpeedTable[ iLast ].fDist < fDistance ) { - TableTraceRoute( fDistance, pVehicles[ 1 ] ); // doskanowanie dalszego odcinka + TableTraceRoute( fDistance, pVehicles[ end::rear ] ); // doskanowanie dalszego odcinka TableSort(); } // garbage collection @@ -2353,7 +2355,6 @@ bool TController::PrepareEngine() voltrear = false; LastReactionTime = 0.0; ReactionTime = PrepareTime; - iDrivigFlags |= moveActive; // może skanować sygnały i reagować na komendy if ( mvControlling->EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) { voltfront = true; @@ -2484,6 +2485,8 @@ bool TController::PrepareEngine() } eAction = TAction::actUnknown; iEngineActive = 1; + iDrivigFlags |= moveActive; // może skanować sygnały i reagować na komendy + return true; } else { @@ -3266,10 +3269,10 @@ void TController::Doors( bool const Open, int const Side ) { && ( ( fActionTime > -0.5 ) || ( false == AIControllFlag ) ) ) { // ai doesn't close the door until it's free to depart, but human driver has free reign to do stupid things - if( ( pVehicle->MoverParameters->Doors.open_control == control_t::conductor ) + if( ( pVehicle->MoverParameters->Doors.close_control == control_t::conductor ) || ( ( true == AIControllFlag ) - && ( ( pVehicle->MoverParameters->Doors.open_control == control_t::driver ) - || ( pVehicle->MoverParameters->Doors.open_control == control_t::mixed ) ) ) ) { + && ( ( pVehicle->MoverParameters->Doors.close_control == control_t::driver ) + || ( pVehicle->MoverParameters->Doors.close_control == control_t::mixed ) ) ) ) { // if the door are controlled by the driver, we let the user operate them unless this user is an ai // the train conductor, if present, handles door operation also for human-driven trains pVehicle->MoverParameters->OperateDoors( side::right, false ); @@ -3306,6 +3309,10 @@ void TController::Doors( bool const Open, int const Side ) { bool TController::doors_open() const { + return ( + IsAnyDoorOpen[ side::right ] + || IsAnyDoorOpen[ side::left ] ); +/* auto *vehicle = pVehicles[ 0 ]; // pojazd na czole składu while( vehicle != nullptr ) { if( ( false == vehicle->MoverParameters->Doors.instances[side::right].is_closed ) @@ -3317,6 +3324,7 @@ TController::doors_open() const { } // if we're still here there's nothing open return false; +*/ } void TController::RecognizeCommand() @@ -4215,7 +4223,7 @@ TController::UpdateSituation(double dt) { Obstacle.vehicle_end = std::get( lookup ); Obstacle.distance = std::get( lookup ); - if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 25 : 75 ) ) { + if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 25 : 100 ) ) { // at short distances (re)calculate range between couplers directly Obstacle.distance = TMoverParameters::CouplerDist( frontvehicle->MoverParameters, Obstacle.vehicle->MoverParameters ); } diff --git a/DynObj.cpp b/DynObj.cpp index d79f24f5..3be66387 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -3439,13 +3439,13 @@ bool TDynamicObject::Update(double dt, double dt1) else { // unfold mirror on the side with open doors, if not moving too fast if( ( dMirrorMoveL < 1.0 ) - && ( true == MoverParameters->Doors.instances[side::left].is_open ) ) { + && ( true == MoverParameters->Doors.instances[side::left].open_permit ) ) { dMirrorMoveL = std::min( 1.0, dMirrorMoveL + 1.0 * dt1 ); } if( ( dMirrorMoveR < 1.0 ) - && ( true == MoverParameters->Doors.instances[side::right].is_open ) ) { + && ( true == MoverParameters->Doors.instances[side::right].open_permit ) ) { dMirrorMoveR = std::min( 1.0, dMirrorMoveR + 1.0 * dt1 ); diff --git a/Event.cpp b/Event.cpp index 12593cdf..ac58a10e 100644 --- a/Event.cpp +++ b/Event.cpp @@ -960,7 +960,11 @@ whois_event::run_() { 1 : 0, // 1, gdy ma tu zatrzymanie m_input.flags ); - WriteLog( "Train detected: " + m_activator->Mechanik->TrainName() ); + WriteLog( + "Type: WhoIs (" + to_string( m_input.flags ) + ") - " + + "[train: " + m_activator->Mechanik->TrainName() + "], " + + "[stations left: " + to_string( m_activator->Mechanik->StationCount() - m_activator->Mechanik->StationIndex() ) + "], " + + "[stop at next: " + ( m_activator->Mechanik->IsStop() ? "yes" : "no") + "]" ); } } } diff --git a/Train.cpp b/Train.cpp index 30f82b53..75a1942d 100644 --- a/Train.cpp +++ b/Train.cpp @@ -158,6 +158,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::aidriverenable, &TTrain::OnCommand_aidriverenable }, { user_command::aidriverdisable, &TTrain::OnCommand_aidriverdisable }, + { user_command::jointcontrollerset, &TTrain::OnCommand_jointcontrollerset }, { user_command::mastercontrollerincrease, &TTrain::OnCommand_mastercontrollerincrease }, { user_command::mastercontrollerincreasefast, &TTrain::OnCommand_mastercontrollerincreasefast }, { user_command::mastercontrollerdecrease, &TTrain::OnCommand_mastercontrollerdecrease }, @@ -757,12 +758,49 @@ void TTrain::OnCommand_aidriverdisable( TTrain *Train, command_data const &Comma auto const EU07_CONTROLLER_BASERETURNDELAY { 0.5f }; auto const EU07_CONTROLLER_KEYBOARDETURNDELAY { 1.5f }; +void TTrain::OnCommand_jointcontrollerset( TTrain *Train, command_data const &Command ) { + + if( Command.action != GLFW_RELEASE ) { + // on press or hold + // value controls brake in range 0-0.5, master controller in range 0.5-1.0 + if( Command.param1 >= 0.5 ) { + Train->set_master_controller( + ( Command.param1 * 2 - 1 ) + * ( Train->mvControlled->CoupledCtrl ? + Train->mvControlled->MainCtrlPosNo + Train->mvControlled->ScndCtrlPosNo : + Train->mvControlled->MainCtrlPosNo ) ); + Train->m_mastercontrollerinuse = true; + Train->mvOccupied->LocalBrakePosA = 0; + } + else { + Train->mvOccupied->LocalBrakePosA = ( + clamp( + 1.0 - ( Command.param1 * 2 ), + 0.0, 1.0 ) ); + if( Train->mvControlled->MainCtrlPos > 0 ) { + Train->set_master_controller( 0 ); + } + } + } + else { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_BASERETURNDELAY; // NOTE: keyboard return delay is omitted for other input sources + } +} + void TTrain::OnCommand_mastercontrollerincrease( TTrain *Train, command_data const &Command ) { if( Command.action != GLFW_RELEASE ) { // on press or hold - Train->mvControlled->IncMainCtrl( 1 ); - Train->m_mastercontrollerinuse = true; + if( ( Train->ggJointCtrl.SubModel != nullptr ) + && ( Train->mvControlled->LocalBrakePosA > 0.0 ) ) { + OnCommand_independentbrakedecrease( Train, Command ); + } + else { + Train->mvControlled->IncMainCtrl( 1 ); + Train->m_mastercontrollerinuse = true; + } } else { // release @@ -775,7 +813,19 @@ void TTrain::OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold - Train->mvControlled->IncMainCtrl( 2 ); + if( ( Train->ggJointCtrl.SubModel != nullptr ) + && ( Train->mvControlled->LocalBrakePosA > 0.0 ) ) { + OnCommand_independentbrakedecreasefast( Train, Command ); + } + else { + Train->mvControlled->IncMainCtrl( 2 ); + Train->m_mastercontrollerinuse = true; + } + } + else { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; } } @@ -783,8 +833,14 @@ void TTrain::OnCommand_mastercontrollerdecrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold - Train->mvControlled->DecMainCtrl( 1 ); - Train->m_mastercontrollerinuse = true; + if( ( Train->ggJointCtrl.SubModel != nullptr ) + && ( Train->mvControlled->MainCtrlPos == 0 ) ) { + OnCommand_independentbrakeincrease( Train, Command ); + } + else { + Train->mvControlled->DecMainCtrl( 1 ); + Train->m_mastercontrollerinuse = true; + } } else { // release @@ -797,7 +853,19 @@ void TTrain::OnCommand_mastercontrollerdecreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold - Train->mvControlled->DecMainCtrl( 2 ); + if( ( Train->ggJointCtrl.SubModel != nullptr ) + && ( Train->mvControlled->MainCtrlPos == 0 ) ) { + OnCommand_independentbrakeincreasefast( Train, Command ); + } + else { + Train->mvControlled->DecMainCtrl( 2 ); + Train->m_mastercontrollerinuse = true; + } + } + else { + // release + Train->m_mastercontrollerinuse = false; + Train->m_mastercontrollerreturndelay = EU07_CONTROLLER_KEYBOARDETURNDELAY + EU07_CONTROLLER_BASERETURNDELAY; } } @@ -981,7 +1049,7 @@ void TTrain::OnCommand_independentbrakeset( TTrain *Train, command_data const &C if( Command.action != GLFW_RELEASE ) { - Train->mvControlled->LocalBrakePosA = ( + Train->mvOccupied->LocalBrakePosA = ( clamp( Command.param1, 0.0, 1.0 ) ); @@ -5735,7 +5803,21 @@ bool TTrain::Update( double const Deltatime ) } } // McZapkie-080602: obroty (albo translacje) regulatorow - if (ggMainCtrl.SubModel) { + if( ggJointCtrl.SubModel != nullptr ) { + // joint master controller moves forward to adjust power and backward to adjust brakes + auto const brakerangemultiplier { + ( mvControlled->CoupledCtrl ? + mvControlled->MainCtrlPosNo + mvControlled->ScndCtrlPosNo : + mvControlled->MainCtrlPosNo ) + / static_cast(LocalBrakePosNo) }; + ggJointCtrl.UpdateValue( + ( mvOccupied->LocalBrakePosA > 0.0 ? mvOccupied->LocalBrakePosA * LocalBrakePosNo * -1 * brakerangemultiplier : + mvControlled->CoupledCtrl ? double( mvControlled->MainCtrlPos + mvControlled->ScndCtrlPos ) : + double( mvControlled->MainCtrlPos ) ), + dsbNastawnikJazdy ); + ggJointCtrl.Update(); + } + if ( ggMainCtrl.SubModel != nullptr ) { #ifdef _WIN32 if( ( DynamicObject->Mechanik != nullptr ) @@ -5822,7 +5904,7 @@ bool TTrain::Update( double const Deltatime ) ggBrakeCtrl.Update(); } - if( ggLocalBrake.SubModel ) { + if( ggLocalBrake.SubModel != nullptr ) { #ifdef _WIN32 if( ( DynamicObject->Mechanik != nullptr ) && ( false == DynamicObject->Mechanik->AIControllFlag ) // nie blokujemy AI @@ -6853,6 +6935,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) if( dsbReverserKey.offset() == nullvector ) { dsbReverserKey.offset( ggDirKey.model_offset() ); } + if( dsbNastawnikJazdy.offset() == nullvector ) { + dsbNastawnikJazdy.offset( ggJointCtrl.model_offset() ); + } if( dsbNastawnikJazdy.offset() == nullvector ) { dsbNastawnikJazdy.offset( ggMainCtrl.model_offset() ); } @@ -7094,6 +7179,7 @@ void TTrain::clear_cab_controls() // other cab controls // TODO: arrange in more readable manner, and eventually refactor + ggJointCtrl.Clear(); ggMainCtrl.Clear(); ggMainCtrlAct.Clear(); ggScndCtrl.Clear(); @@ -7729,6 +7815,7 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int const Cabindex) { std::unordered_map const gauges = { + { "jointctrl:", ggJointCtrl }, { "mainctrl:", ggMainCtrl }, { "scndctrl:", ggScndCtrl }, { "dirkey:" , ggDirKey }, diff --git a/Train.h b/Train.h index 35701da2..9cb8eb90 100644 --- a/Train.h +++ b/Train.h @@ -155,6 +155,7 @@ class TTrain // TBD, TODO: consider this approach if we ever want to have customized consist behaviour to received commands, based on the consist/vehicle type or whatever static void OnCommand_aidriverenable( TTrain *Train, command_data const &Command ); static void OnCommand_aidriverdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_jointcontrollerset( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerincrease( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data const &Command ); static void OnCommand_mastercontrollerdecrease( TTrain *Train, command_data const &Command ); @@ -372,6 +373,7 @@ public: // reszta może by?publiczna TGauge ggWater1TempB; // McZapkie: definicje regulatorow + TGauge ggJointCtrl; TGauge ggMainCtrl; TGauge ggMainCtrlAct; TGauge ggScndCtrl; diff --git a/command.cpp b/command.cpp index b4036625..6b49e343 100644 --- a/command.cpp +++ b/command.cpp @@ -22,6 +22,7 @@ commanddescription_sequence Commands_descriptions = { { "aidriverenable", command_target::vehicle }, { "aidriverdisable", command_target::vehicle }, + { "jointcontrollerset", command_target::vehicle }, { "mastercontrollerincrease", command_target::vehicle }, { "mastercontrollerincreasefast", command_target::vehicle }, { "mastercontrollerdecrease", command_target::vehicle }, diff --git a/command.h b/command.h index c873cdee..3cdd6bd0 100644 --- a/command.h +++ b/command.h @@ -16,6 +16,7 @@ enum class user_command { aidriverenable, aidriverdisable, + jointcontrollerset, mastercontrollerincrease, mastercontrollerincreasefast, mastercontrollerdecrease, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 80225887..0ece6a48 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -27,6 +27,7 @@ driverkeyboard_input::default_bindings() { m_bindingsetups = { { user_command::aidriverenable, GLFW_KEY_Q | keymodifier::shift }, { user_command::aidriverdisable, GLFW_KEY_Q }, + // jointcontrollerset, { user_command::mastercontrollerincrease, GLFW_KEY_KP_ADD }, { user_command::mastercontrollerincreasefast, GLFW_KEY_KP_ADD | keymodifier::shift }, { user_command::mastercontrollerdecrease, GLFW_KEY_KP_SUBTRACT }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index 6237935c..a8e04c07 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -21,6 +21,8 @@ http://mozilla.org/MPL/2.0/. #include "uilayer.h" #include "Logs.h" +auto const EU07_CONTROLLER_MOUSESLIDERSIZE{ 0.65 }; + void mouse_slider::bind( user_command const &Command ) { @@ -29,6 +31,7 @@ mouse_slider::bind( user_command const &Command ) { auto const *train { simulation::Train }; TMoverParameters const *vehicle { nullptr }; switch( m_command ) { + case user_command::jointcontrollerset: case user_command::mastercontrollerset: case user_command::secondcontrollerset: { vehicle = ( train ? train->Controlled() : nullptr ); @@ -47,6 +50,29 @@ mouse_slider::bind( user_command const &Command ) { // calculate initial value and accepted range switch( m_command ) { + case user_command::jointcontrollerset: { + // NOTE: special case, merges two separate controls + auto const *occupied { train ? train->Occupied() : nullptr }; + if( occupied == nullptr ) { return; } + + auto const powerrange { static_cast( + vehicle->CoupledCtrl ? + vehicle->MainCtrlPosNo + vehicle->ScndCtrlPosNo : + vehicle->MainCtrlPosNo ) }; + // for simplicity upper half of the range controls power, lower controls brakes + auto const brakerangemultiplier { powerrange / LocalBrakePosNo }; + + m_valuerange = 1.0; + m_value = + 0.5 + + 0.5 * ( vehicle->CoupledCtrl ? + vehicle->MainCtrlPos + vehicle->ScndCtrlPos : + vehicle->MainCtrlPos ) / powerrange + - 0.5 * occupied->LocalBrakePosA; + m_analogue = true; + m_invertrange = false; + break; + } case user_command::mastercontrollerset: { m_valuerange = ( vehicle->CoupledCtrl ? @@ -57,24 +83,28 @@ mouse_slider::bind( user_command const &Command ) { vehicle->MainCtrlPos + vehicle->ScndCtrlPos : vehicle->MainCtrlPos ); m_analogue = false; + m_invertrange = false; break; } case user_command::secondcontrollerset: { m_valuerange = vehicle->ScndCtrlPosNo; m_value = vehicle->ScndCtrlPos; m_analogue = false; + m_invertrange = true; break; } case user_command::trainbrakeset: { m_valuerange = 1.0; m_value = ( vehicle->fBrakeCtrlPos - vehicle->Handle->GetPos( bh_MIN ) ) / ( vehicle->Handle->GetPos( bh_MAX ) - vehicle->Handle->GetPos( bh_MIN ) ); m_analogue = true; + m_invertrange = true; break; } case user_command::independentbrakeset: { m_valuerange = 1.0; m_value = vehicle->LocalBrakePosA; m_analogue = true; + m_invertrange = true; break; } default: { @@ -86,14 +116,18 @@ mouse_slider::bind( user_command const &Command ) { Application.get_cursor_pos( m_cursorposition.x, m_cursorposition.y ); Application.set_cursor( GLFW_CURSOR_DISABLED ); - auto const controlsize { Global.iWindowHeight * 0.75 }; + auto const controlsize { Global.iWindowHeight * EU07_CONTROLLER_MOUSESLIDERSIZE }; auto const controledge { Global.iWindowHeight * 0.5 + controlsize * 0.5 }; auto const stepsize { controlsize / m_valuerange }; + if( m_invertrange ) { + m_value = ( m_analogue ? 1.0 : m_valuerange ) - m_value; + } + Application.set_cursor_pos( Global.iWindowWidth * 0.5, ( m_analogue ? - controledge - ( 1.0 - m_value ) * controlsize : + controledge - m_value * controlsize : controledge - m_value * stepsize - 0.5 * stepsize ) ); } @@ -108,15 +142,17 @@ mouse_slider::release() { void mouse_slider::on_move( double const Mousex, double const Mousey ) { - auto const controlsize { Global.iWindowHeight * 0.75 }; + auto const controlsize { Global.iWindowHeight * EU07_CONTROLLER_MOUSESLIDERSIZE }; auto const controledge { Global.iWindowHeight * 0.5 + controlsize * 0.5 }; auto const stepsize { controlsize / m_valuerange }; auto mousey = clamp( Mousey, controledge - controlsize, controledge ); m_value = ( m_analogue ? - 1.0 - ( ( controledge - mousey ) / controlsize ) : + ( controledge - mousey ) / controlsize : std::floor( ( controledge - mousey ) / stepsize ) ); + if( m_invertrange ) { + m_value = ( m_analogue ? 1.0 : m_valuerange ) - m_value; } } @@ -370,6 +406,7 @@ drivermouse_input::button( int const Button, int const Action ) { m_varyingpollrate = true; break; } + case user_command::jointcontrollerset: case user_command::mastercontrollerset: case user_command::secondcontrollerset: case user_command::trainbrakeset: @@ -445,6 +482,9 @@ void drivermouse_input::default_bindings() { m_buttonbindings = { + { "jointctrl:", { + user_command::jointcontrollerset, + user_command::none } }, { "mainctrl:", { user_command::mastercontrollerset, user_command::none } }, diff --git a/drivermouseinput.h b/drivermouseinput.h index b8b40a4e..2932a722 100644 --- a/drivermouseinput.h +++ b/drivermouseinput.h @@ -39,6 +39,7 @@ private: double m_value { 0.0 }; double m_valuerange { 0.0 }; bool m_analogue { false }; + bool m_invertrange { false }; glm::dvec2 m_cursorposition { 0.0 }; }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 5957935d..0098a6fa 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -696,7 +696,9 @@ debug_panel::update_section_ai( std::vector &Output ) { + ", braking: " + to_string( mechanik.fBrakeDist, 0 ); if( mechanik.Obstacle.distance < 5000 ) { - textline += "\n obstacle: " + to_string( mechanik.Obstacle.distance, 0 ); + textline += + "\n obstacle: " + to_string( mechanik.Obstacle.distance, 0 ) + + " (" + mechanik.Obstacle.vehicle->asName + ")"; } Output.emplace_back( textline, Global.UITextColor ); diff --git a/scenenode.cpp b/scenenode.cpp index eeb2ae98..df5c432d 100644 --- a/scenenode.cpp +++ b/scenenode.cpp @@ -49,10 +49,12 @@ bounding_area::serialize( std::ostream &Output ) const { // restores content of the struct from provided input stream void -bounding_area::deserialize( std::istream &Input ) { +bounding_area::deserialize( std::istream &Input, bool const Preserveradius ) { center = sn_utils::d_dvec3( Input ); - radius = sn_utils::ld_float32( Input ); + radius = ( Preserveradius ? + std::max( radius, sn_utils::ld_float32( Input ) ) : + sn_utils::ld_float32( Input ) ); } diff --git a/scenenode.h b/scenenode.h index 05431fec..06b59356 100644 --- a/scenenode.h +++ b/scenenode.h @@ -59,9 +59,9 @@ struct bounding_area { // stores content of the struct in provided output stream void serialize( std::ostream &Output ) const; - // restores content of the struct from provided input stream + // restores content of the struct from provided input stream. void - deserialize( std::istream &Input ); + deserialize( std::istream &Input, bool const Preserveradius = true ); }; //using group_handle = std::size_t; diff --git a/translation.cpp b/translation.cpp index 854cbfdf..a774082c 100644 --- a/translation.cpp +++ b/translation.cpp @@ -62,6 +62,7 @@ init() { " pantograph: %.2f%cMT", "Forces:\n tractive: %.1f, brake: %.1f, friction: %.2f%s\nAcceleration:\n tangential: %.2f, normal: %.2f (path radius: %s)\nVelocity: %.2f, distance traveled: %.2f\nPosition: [%.2f, %.2f, %.2f]", + "master controller", "master controller", "second controller", "shunt mode power", @@ -206,6 +207,7 @@ init() { " pantograf: %.2f%cZG", "Sily:\n napedna: %.1f, hamowania: %.1f, tarcie: %.2f%s\nPrzyspieszenia:\n styczne: %.2f, normalne: %.2f (promien: %s)\nPredkosc: %.2f, pokonana odleglosc: %.2f\nPozycja: [%.2f, %.2f, %.2f]", + "nastawnik jazdy", "nastawnik jazdy", "nastawnik dodatkowy", "sterowanie analogowe", @@ -322,6 +324,7 @@ init() { { std::vector cabcontrols = { "mainctrl:", + "jointctrl:", "scndctrl:", "shuntmodepower:", "dirkey:", diff --git a/translation.h b/translation.h index d991a771..8a7a056d 100644 --- a/translation.h +++ b/translation.h @@ -52,6 +52,7 @@ enum string { debug_vehicle_forcesaccelerationvelocityposition, cab_mainctrl, + cab_jointctrl, cab_scndctrl, cab_shuntmodepower, cab_dirkey, diff --git a/version.h b/version.h index e1d32d9f..a9aa97a6 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 223 +#define VERSION_MINOR 227 #define VERSION_REVISION 0