LCOV - code coverage report
Current view: top level - src/microsim - MSVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.3 % 3218 3099
Test Date: 2024-10-24 15:46:30 Functions: 95.1 % 223 212

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSVehicle.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Bjoern Hendriks
      18              : /// @author  Daniel Krajzewicz
      19              : /// @author  Thimor Bohn
      20              : /// @author  Friedemann Wesner
      21              : /// @author  Laura Bieker
      22              : /// @author  Clemens Honomichl
      23              : /// @author  Michael Behrisch
      24              : /// @author  Axel Wegener
      25              : /// @author  Christoph Sommer
      26              : /// @author  Leonhard Luecken
      27              : /// @author  Lara Codeca
      28              : /// @author  Mirko Barthauer
      29              : /// @date    Mon, 05 Mar 2001
      30              : ///
      31              : // Representation of a vehicle in the micro simulation
      32              : /****************************************************************************/
      33              : #include <config.h>
      34              : 
      35              : #include <iostream>
      36              : #include <cassert>
      37              : #include <cmath>
      38              : #include <cstdlib>
      39              : #include <algorithm>
      40              : #include <map>
      41              : #include <memory>
      42              : #include <utils/common/ToString.h>
      43              : #include <utils/common/FileHelpers.h>
      44              : #include <utils/router/DijkstraRouter.h>
      45              : #include <utils/common/MsgHandler.h>
      46              : #include <utils/common/RandHelper.h>
      47              : #include <utils/common/StringUtils.h>
      48              : #include <utils/common/StdDefs.h>
      49              : #include <utils/geom/GeomHelper.h>
      50              : #include <utils/iodevices/OutputDevice.h>
      51              : #include <utils/xml/SUMOSAXAttributes.h>
      52              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      53              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      54              : #include <microsim/transportables/MSPerson.h>
      55              : #include <microsim/transportables/MSPModel.h>
      56              : #include <microsim/devices/MSDevice_Transportable.h>
      57              : #include <microsim/devices/MSDevice_DriverState.h>
      58              : #include <microsim/devices/MSDevice_Friction.h>
      59              : #include <microsim/devices/MSDevice_Taxi.h>
      60              : #include <microsim/devices/MSDevice_Vehroutes.h>
      61              : #include <microsim/devices/MSDevice_ElecHybrid.h>
      62              : #include <microsim/devices/MSDevice_GLOSA.h>
      63              : #include <microsim/output/MSStopOut.h>
      64              : #include <microsim/trigger/MSChargingStation.h>
      65              : #include <microsim/trigger/MSOverheadWire.h>
      66              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      67              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      68              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      69              : #include <microsim/transportables/MSTransportableControl.h>
      70              : #include <microsim/devices/MSDevice_Transportable.h>
      71              : #include "MSEdgeControl.h"
      72              : #include "MSVehicleControl.h"
      73              : #include "MSInsertionControl.h"
      74              : #include "MSVehicleTransfer.h"
      75              : #include "MSGlobals.h"
      76              : #include "MSJunctionLogic.h"
      77              : #include "MSStop.h"
      78              : #include "MSStoppingPlace.h"
      79              : #include "MSParkingArea.h"
      80              : #include "MSMoveReminder.h"
      81              : #include "MSLane.h"
      82              : #include "MSJunction.h"
      83              : #include "MSEdge.h"
      84              : #include "MSVehicleType.h"
      85              : #include "MSNet.h"
      86              : #include "MSRoute.h"
      87              : #include "MSLeaderInfo.h"
      88              : #include "MSDriverState.h"
      89              : #include "MSVehicle.h"
      90              : 
      91              : 
      92              : //#define DEBUG_PLAN_MOVE
      93              : //#define DEBUG_PLAN_MOVE_LEADERINFO
      94              : //#define DEBUG_CHECKREWINDLINKLANES
      95              : //#define DEBUG_EXEC_MOVE
      96              : //#define DEBUG_FURTHER
      97              : //#define DEBUG_SETFURTHER
      98              : //#define DEBUG_TARGET_LANE
      99              : //#define DEBUG_STOPS
     100              : //#define DEBUG_BESTLANES
     101              : //#define DEBUG_IGNORE_RED
     102              : //#define DEBUG_ACTIONSTEPS
     103              : //#define DEBUG_NEXT_TURN
     104              : //#define DEBUG_TRACI
     105              : //#define DEBUG_REVERSE_BIDI
     106              : //#define DEBUG_EXTRAPOLATE_DEPARTPOS
     107              : //#define DEBUG_REMOTECONTROL
     108              : //#define DEBUG_MOVEREMINDERS
     109              : //#define DEBUG_COND (getID() == "ego")
     110              : //#define DEBUG_COND (true)
     111              : #define DEBUG_COND (isSelected())
     112              : //#define DEBUG_COND2(obj) (obj->getID() == "ego")
     113              : #define DEBUG_COND2(obj) (obj->isSelected())
     114              : 
     115              : //#define PARALLEL_STOPWATCH
     116              : 
     117              : 
     118              : #define STOPPING_PLACE_OFFSET 0.5
     119              : 
     120              : #define CRLL_LOOK_AHEAD 5
     121              : 
     122              : #define JUNCTION_BLOCKAGE_TIME 5 // s
     123              : 
     124              : // @todo Calibrate with real-world values / make configurable
     125              : #define DIST_TO_STOPLINE_EXPECT_PRIORITY 1.0
     126              : 
     127              : #define NUMERICAL_EPS_SPEED (0.1 * NUMERICAL_EPS * TS)
     128              : 
     129              : // ===========================================================================
     130              : // static value definitions
     131              : // ===========================================================================
     132              : std::vector<MSLane*> MSVehicle::myEmptyLaneVector;
     133              : 
     134              : 
     135              : // ===========================================================================
     136              : // method definitions
     137              : // ===========================================================================
     138              : /* -------------------------------------------------------------------------
     139              :  * methods of MSVehicle::State
     140              :  * ----------------------------------------------------------------------- */
     141            0 : MSVehicle::State::State(const State& state) {
     142            0 :     myPos = state.myPos;
     143            0 :     mySpeed = state.mySpeed;
     144            0 :     myPosLat = state.myPosLat;
     145            0 :     myBackPos = state.myBackPos;
     146            0 :     myPreviousSpeed = state.myPreviousSpeed;
     147            0 :     myLastCoveredDist = state.myLastCoveredDist;
     148            0 : }
     149              : 
     150              : 
     151              : MSVehicle::State&
     152      2702359 : MSVehicle::State::operator=(const State& state) {
     153      2702359 :     myPos   = state.myPos;
     154      2702359 :     mySpeed = state.mySpeed;
     155      2702359 :     myPosLat   = state.myPosLat;
     156      2702359 :     myBackPos = state.myBackPos;
     157      2702359 :     myPreviousSpeed = state.myPreviousSpeed;
     158      2702359 :     myLastCoveredDist = state.myLastCoveredDist;
     159      2702359 :     return *this;
     160              : }
     161              : 
     162              : 
     163              : bool
     164            0 : MSVehicle::State::operator!=(const State& state) {
     165            0 :     return (myPos    != state.myPos ||
     166            0 :             mySpeed  != state.mySpeed ||
     167            0 :             myPosLat != state.myPosLat ||
     168            0 :             myLastCoveredDist != state.myLastCoveredDist ||
     169            0 :             myPreviousSpeed != state.myPreviousSpeed ||
     170            0 :             myBackPos != state.myBackPos);
     171              : }
     172              : 
     173              : 
     174      6595026 : MSVehicle::State::State(double pos, double speed, double posLat, double backPos, double previousSpeed) :
     175      6595026 :     myPos(pos), mySpeed(speed), myPosLat(posLat), myBackPos(backPos), myPreviousSpeed(previousSpeed), myLastCoveredDist(SPEED2DIST(speed)) {}
     176              : 
     177              : 
     178              : 
     179              : /* -------------------------------------------------------------------------
     180              :  * methods of MSVehicle::WaitingTimeCollector
     181              :  * ----------------------------------------------------------------------- */
     182      3892667 : MSVehicle::WaitingTimeCollector::WaitingTimeCollector(SUMOTime memory) : myMemorySize(memory) {}
     183              : 
     184              : 
     185              : SUMOTime
     186      1361805 : MSVehicle::WaitingTimeCollector::cumulatedWaitingTime(SUMOTime memorySpan) const {
     187              :     assert(memorySpan <= myMemorySize);
     188      1361805 :     if (memorySpan == -1) {
     189            0 :         memorySpan = myMemorySize;
     190              :     }
     191              :     SUMOTime totalWaitingTime = 0;
     192      5798127 :     for (const auto& interval : myWaitingIntervals) {
     193      4436322 :         if (interval.second >= memorySpan) {
     194       646410 :             if (interval.first >= memorySpan) {
     195              :                 break;
     196              :             } else {
     197       646410 :                 totalWaitingTime += memorySpan - interval.first;
     198              :             }
     199              :         } else {
     200      3789912 :             totalWaitingTime += interval.second - interval.first;
     201              :         }
     202              :     }
     203      1361805 :     return totalWaitingTime;
     204              : }
     205              : 
     206              : 
     207              : void
     208    540547878 : MSVehicle::WaitingTimeCollector::passTime(SUMOTime dt, bool waiting) {
     209              :     auto i = myWaitingIntervals.begin();
     210              :     const auto end = myWaitingIntervals.end();
     211    540547878 :     const bool startNewInterval = i == end || (i->first != 0);
     212    954897772 :     while (i != end) {
     213    416448942 :         i->first += dt;
     214    416448942 :         if (i->first >= myMemorySize) {
     215              :             break;
     216              :         }
     217    414349894 :         i->second += dt;
     218              :         i++;
     219              :     }
     220              : 
     221              :     // remove intervals beyond memorySize
     222              :     auto d = std::distance(i, end);
     223    542646926 :     while (d > 0) {
     224      2099048 :         myWaitingIntervals.pop_back();
     225      2099048 :         d--;
     226              :     }
     227              : 
     228    540547878 :     if (!waiting) {
     229              :         return;
     230     78126840 :     } else if (!startNewInterval) {
     231     74851692 :         myWaitingIntervals.begin()->first = 0;
     232              :     } else {
     233      6550296 :         myWaitingIntervals.push_front(std::make_pair(0, dt));
     234              :     }
     235              :     return;
     236              : }
     237              : 
     238              : 
     239              : const std::string
     240         2159 : MSVehicle::WaitingTimeCollector::getState() const {
     241         2159 :     std::ostringstream state;
     242         2159 :     state << myMemorySize << " " << myWaitingIntervals.size();
     243         2963 :     for (const auto& interval : myWaitingIntervals) {
     244         1608 :         state << " " << interval.first << " " << interval.second;
     245              :     }
     246         2159 :     return state.str();
     247         2159 : }
     248              : 
     249              : 
     250              : void
     251         3867 : MSVehicle::WaitingTimeCollector::setState(const std::string& state) {
     252         3867 :     std::istringstream is(state);
     253              :     int numIntervals;
     254              :     SUMOTime begin, end;
     255         3867 :     is >> myMemorySize >> numIntervals;
     256         6506 :     while (numIntervals-- > 0) {
     257              :         is >> begin >> end;
     258         2639 :         myWaitingIntervals.emplace_back(begin, end);
     259              :     }
     260         3867 : }
     261              : 
     262              : 
     263              : /* -------------------------------------------------------------------------
     264              :  * methods of MSVehicle::Influencer::GapControlState
     265              :  * ----------------------------------------------------------------------- */
     266              : void
     267     10842136 : MSVehicle::Influencer::GapControlVehStateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
     268              : //    std::cout << "GapControlVehStateListener::vehicleStateChanged() vehicle=" << vehicle->getID() << ", to=" << to << std::endl;
     269     10842136 :     switch (to) {
     270      2547389 :         case MSNet::VehicleState::STARTING_TELEPORT:
     271              :         case MSNet::VehicleState::ARRIVED:
     272              :         case MSNet::VehicleState::STARTING_PARKING: {
     273              :             // Vehicle left road
     274              : //         Look up reference vehicle in refVehMap and in case deactivate corresponding gap control
     275      2547389 :             const MSVehicle* msVeh = static_cast<const MSVehicle*>(vehicle);
     276              : //        std::cout << "GapControlVehStateListener::vehicleStateChanged() vehicle=" << vehicle->getID() << " left the road." << std::endl;
     277      2547389 :             if (GapControlState::refVehMap.find(msVeh) != end(GapControlState::refVehMap)) {
     278              : //            std::cout << "GapControlVehStateListener::deactivating ref vehicle=" << vehicle->getID() << std::endl;
     279            5 :                 GapControlState::refVehMap[msVeh]->deactivate();
     280              :             }
     281              :         }
     282      2547389 :         break;
     283     10842136 :         default:
     284              :         {};
     285              :             // do nothing, vehicle still on road
     286              :     }
     287     10842136 : }
     288              : 
     289              : std::map<const MSVehicle*, MSVehicle::Influencer::GapControlState*>
     290              : MSVehicle::Influencer::GapControlState::refVehMap;
     291              : 
     292              : MSVehicle::Influencer::GapControlVehStateListener
     293              : MSVehicle::Influencer::GapControlState::vehStateListener;
     294              : 
     295           58 : MSVehicle::Influencer::GapControlState::GapControlState() :
     296           58 :     tauOriginal(-1), tauCurrent(-1), tauTarget(-1), addGapCurrent(-1), addGapTarget(-1),
     297           58 :     remainingDuration(-1), changeRate(-1), maxDecel(-1), referenceVeh(nullptr), active(false), gapAttained(false), prevLeader(nullptr),
     298           58 :     lastUpdate(-1), timeHeadwayIncrement(0.0), spaceHeadwayIncrement(0.0) {}
     299              : 
     300              : 
     301           58 : MSVehicle::Influencer::GapControlState::~GapControlState() {
     302           58 :     deactivate();
     303           58 : }
     304              : 
     305              : void
     306        37375 : MSVehicle::Influencer::GapControlState::init() {
     307              : //    std::cout << "GapControlState::init()" << std::endl;
     308        37375 :     if (MSNet::hasInstance()) {
     309              :         MSNet::VehicleStateListener* vsl = dynamic_cast<MSNet::VehicleStateListener*>(&vehStateListener);
     310        37375 :         MSNet::getInstance()->addVehicleStateListener(vsl);
     311              :     } else {
     312            0 :         WRITE_ERROR("MSVehicle::Influencer::GapControlState::init(): No MSNet instance found!")
     313              :     }
     314        37375 : }
     315              : 
     316              : void
     317        34511 : MSVehicle::Influencer::GapControlState::cleanup() {
     318              :     MSNet::VehicleStateListener* vsl = dynamic_cast<MSNet::VehicleStateListener*>(&vehStateListener);
     319        34511 :     MSNet::getInstance()->removeVehicleStateListener(vsl);
     320        34511 : }
     321              : 
     322              : void
     323           58 : MSVehicle::Influencer::GapControlState::activate(double tauOrig, double tauNew, double additionalGap, double dur, double rate, double decel, const MSVehicle* refVeh) {
     324           58 :     if (MSGlobals::gUseMesoSim) {
     325            0 :         WRITE_ERROR(TL("No gap control available for meso."))
     326              :     } else {
     327              :         // always deactivate control before activating (triggers clean-up of refVehMap)
     328              : //        std::cout << "activate gap control with refVeh=" << (refVeh==nullptr? "NULL" : refVeh->getID()) << std::endl;
     329           58 :         tauOriginal = tauOrig;
     330           58 :         tauCurrent = tauOrig;
     331           58 :         tauTarget = tauNew;
     332           58 :         addGapCurrent = 0.0;
     333           58 :         addGapTarget = additionalGap;
     334           58 :         remainingDuration = dur;
     335           58 :         changeRate = rate;
     336           58 :         maxDecel = decel;
     337           58 :         referenceVeh = refVeh;
     338           58 :         active = true;
     339           58 :         gapAttained = false;
     340           58 :         prevLeader = nullptr;
     341           58 :         lastUpdate = SIMSTEP - DELTA_T;
     342           58 :         timeHeadwayIncrement = changeRate * TS * (tauTarget - tauOriginal);
     343           58 :         spaceHeadwayIncrement = changeRate * TS * addGapTarget;
     344              : 
     345           58 :         if (referenceVeh != nullptr) {
     346              :             // Add refVeh to refVehMap
     347           13 :             GapControlState::refVehMap[referenceVeh] = this;
     348              :         }
     349              :     }
     350           58 : }
     351              : 
     352              : void
     353          116 : MSVehicle::Influencer::GapControlState::deactivate() {
     354          116 :     active = false;
     355          116 :     if (referenceVeh != nullptr) {
     356              :         // Remove corresponding refVehMapEntry if appropriate
     357           13 :         GapControlState::refVehMap.erase(referenceVeh);
     358           13 :         referenceVeh = nullptr;
     359              :     }
     360          116 : }
     361              : 
     362              : 
     363              : /* -------------------------------------------------------------------------
     364              :  * methods of MSVehicle::Influencer
     365              :  * ----------------------------------------------------------------------- */
     366         3419 : MSVehicle::Influencer::Influencer() :
     367              :     myGapControlState(nullptr),
     368         3419 :     myOriginalSpeed(-1),
     369         3419 :     myLatDist(0),
     370         3419 :     mySpeedAdaptationStarted(true),
     371         3419 :     myConsiderSafeVelocity(true),
     372         3419 :     myConsiderMaxAcceleration(true),
     373         3419 :     myConsiderMaxDeceleration(true),
     374         3419 :     myRespectJunctionPriority(true),
     375         3419 :     myEmergencyBrakeRedLight(true),
     376         3419 :     myRespectJunctionLeaderPriority(true),
     377         3419 :     myLastRemoteAccess(-TIME2STEPS(20)),
     378         3419 :     myStrategicLC(LC_NOCONFLICT),
     379         3419 :     myCooperativeLC(LC_NOCONFLICT),
     380         3419 :     mySpeedGainLC(LC_NOCONFLICT),
     381         3419 :     myRightDriveLC(LC_NOCONFLICT),
     382         3419 :     mySublaneLC(LC_NOCONFLICT),
     383         3419 :     myTraciLaneChangePriority(LCP_URGENT),
     384         3419 :     myTraCISignals(-1)
     385         3419 : {}
     386              : 
     387              : 
     388        10257 : MSVehicle::Influencer::~Influencer() {}
     389              : 
     390              : void
     391        37375 : MSVehicle::Influencer::init() {
     392        37375 :     GapControlState::init();
     393        37375 : }
     394              : 
     395              : void
     396        34511 : MSVehicle::Influencer::cleanup() {
     397        34511 :     GapControlState::cleanup();
     398        34511 : }
     399              : 
     400              : void
     401        28893 : MSVehicle::Influencer::setSpeedTimeLine(const std::vector<std::pair<SUMOTime, double> >& speedTimeLine) {
     402        28893 :     mySpeedAdaptationStarted = true;
     403        28893 :     mySpeedTimeLine = speedTimeLine;
     404        28893 : }
     405              : 
     406              : void
     407           58 : MSVehicle::Influencer::activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, MSVehicle* refVeh) {
     408           58 :     if (myGapControlState == nullptr) {
     409           58 :         myGapControlState = std::make_shared<GapControlState>();
     410              :     }
     411           58 :     myGapControlState->activate(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel, refVeh);
     412           58 : }
     413              : 
     414              : void
     415           10 : MSVehicle::Influencer::deactivateGapController() {
     416           10 :     if (myGapControlState != nullptr && myGapControlState->active) {
     417           10 :         myGapControlState->deactivate();
     418              :     }
     419           10 : }
     420              : 
     421              : void
     422         7978 : MSVehicle::Influencer::setLaneTimeLine(const std::vector<std::pair<SUMOTime, int> >& laneTimeLine) {
     423         7978 :     myLaneTimeLine = laneTimeLine;
     424         7978 : }
     425              : 
     426              : 
     427              : void
     428         8936 : MSVehicle::Influencer::adaptLaneTimeLine(int indexShift) {
     429        19162 :     for (auto& item : myLaneTimeLine) {
     430        10226 :         item.second += indexShift;
     431              :     }
     432         8936 : }
     433              : 
     434              : 
     435              : void
     436         1487 : MSVehicle::Influencer::setSublaneChange(double latDist) {
     437         1487 :     myLatDist = latDist;
     438         1487 : }
     439              : 
     440              : int
     441           62 : MSVehicle::Influencer::getSpeedMode() const {
     442           62 :     return (1 * myConsiderSafeVelocity +
     443           62 :             2 * myConsiderMaxAcceleration +
     444           62 :             4 * myConsiderMaxDeceleration +
     445           62 :             8 * myRespectJunctionPriority +
     446           62 :             16 * myEmergencyBrakeRedLight +
     447           62 :             32 * !myRespectJunctionLeaderPriority // inverted!
     448           62 :            );
     449              : }
     450              : 
     451              : 
     452              : int
     453         1468 : MSVehicle::Influencer::getLaneChangeMode() const {
     454         1468 :     return (1 * myStrategicLC +
     455         1468 :             4 * myCooperativeLC +
     456         1468 :             16 * mySpeedGainLC +
     457         1468 :             64 * myRightDriveLC +
     458         1468 :             256 * myTraciLaneChangePriority +
     459         1468 :             1024 * mySublaneLC);
     460              : }
     461              : 
     462              : SUMOTime
     463           71 : MSVehicle::Influencer::getLaneTimeLineDuration() {
     464              :     SUMOTime duration = -1;
     465          213 :     for (std::vector<std::pair<SUMOTime, int>>::iterator i = myLaneTimeLine.begin(); i != myLaneTimeLine.end(); ++i) {
     466          142 :         if (duration < 0) {
     467           71 :             duration = i->first;
     468              :         } else {
     469           71 :             duration -=  i->first;
     470              :         }
     471              :     }
     472           71 :     return -duration;
     473              : }
     474              : 
     475              : SUMOTime
     476            0 : MSVehicle::Influencer::getLaneTimeLineEnd() {
     477            0 :     if (!myLaneTimeLine.empty()) {
     478            0 :         return myLaneTimeLine.back().first;
     479              :     } else {
     480              :         return -1;
     481              :     }
     482              : }
     483              : 
     484              : 
     485              : double
     486       927572 : MSVehicle::Influencer::influenceSpeed(SUMOTime currentTime, double speed, double vSafe, double vMin, double vMax) {
     487              :     // remove leading commands which are no longer valid
     488       932268 :     while (mySpeedTimeLine.size() == 1 || (mySpeedTimeLine.size() > 1 && currentTime > mySpeedTimeLine[1].first)) {
     489              :         mySpeedTimeLine.erase(mySpeedTimeLine.begin());
     490              :     }
     491              : 
     492       927572 :     if (!(mySpeedTimeLine.size() < 2 || currentTime < mySpeedTimeLine[0].first)) {
     493              :         // Speed advice is active -> compute new speed according to speedTimeLine
     494        41488 :         if (!mySpeedAdaptationStarted) {
     495            0 :             mySpeedTimeLine[0].second = speed;
     496            0 :             mySpeedAdaptationStarted = true;
     497              :         }
     498        41488 :         currentTime += DELTA_T;
     499        41488 :         const double td = STEPS2TIME(currentTime - mySpeedTimeLine[0].first) / STEPS2TIME(mySpeedTimeLine[1].first + DELTA_T - mySpeedTimeLine[0].first);
     500        41488 :         speed = mySpeedTimeLine[0].second - (mySpeedTimeLine[0].second - mySpeedTimeLine[1].second) * td;
     501        41488 :         if (myConsiderSafeVelocity) {
     502              :             speed = MIN2(speed, vSafe);
     503              :         }
     504        41488 :         if (myConsiderMaxAcceleration) {
     505              :             speed = MIN2(speed, vMax);
     506              :         }
     507        41488 :         if (myConsiderMaxDeceleration) {
     508              :             speed = MAX2(speed, vMin);
     509              :         }
     510              :     }
     511       927572 :     return speed;
     512              : }
     513              : 
     514              : double
     515       460523 : MSVehicle::Influencer::gapControlSpeed(SUMOTime currentTime, const SUMOVehicle* veh, double speed, double vSafe, double vMin, double vMax) {
     516              : #ifdef DEBUG_TRACI
     517              :     if DEBUG_COND2(veh) {
     518              :         std::cout << currentTime << " Influencer::gapControlSpeed(): speed=" << speed
     519              :                   << ", vSafe=" << vSafe
     520              :                   << ", vMin=" << vMin
     521              :                   << ", vMax=" << vMax
     522              :                   << std::endl;
     523              :     }
     524              : #endif
     525              :     double gapControlSpeed = speed;
     526       460523 :     if (myGapControlState != nullptr && myGapControlState->active) {
     527              :         // Determine leader and the speed that would be chosen by the gap controller
     528         7750 :         const double currentSpeed = veh->getSpeed();
     529         7750 :         const MSVehicle* msVeh = dynamic_cast<const MSVehicle*>(veh);
     530              :         assert(msVeh != nullptr);
     531         7750 :         const double desiredTargetTimeSpacing = myGapControlState->tauTarget * currentSpeed;
     532              :         std::pair<const MSVehicle*, double> leaderInfo;
     533         7750 :         if (myGapControlState->referenceVeh == nullptr) {
     534              :             // No reference vehicle specified -> use current leader as reference
     535         7312 :             const double brakeGap = msVeh->getBrakeGap(true);
     536        14624 :             leaderInfo = msVeh->getLeader(MAX2(desiredTargetTimeSpacing, myGapControlState->addGapCurrent)  + MAX2(brakeGap, 20.0));
     537              : #ifdef DEBUG_TRACI
     538              :             if DEBUG_COND2(veh) {
     539              :                 std::cout <<  "  ---   no refVeh; myGapControlState->addGapCurrent: " << myGapControlState->addGapCurrent << ", brakeGap: " << brakeGap << " in simstep: " << SIMSTEP << std::endl;
     540              :             }
     541              : #endif
     542              :         } else {
     543              :             // Control gap wrt reference vehicle
     544              :             const MSVehicle* leader = myGapControlState->referenceVeh;
     545          438 :             double dist = msVeh->getDistanceToPosition(leader->getPositionOnLane(), leader->getLane()) - leader->getLength();
     546          438 :             if (dist > 100000) {
     547              :                 // Reference vehicle was not found downstream the ego's route
     548              :                 // Maybe, it is behind the ego vehicle
     549           42 :                 dist = - leader->getDistanceToPosition(msVeh->getPositionOnLane(), msVeh->getLane()) - leader->getLength();
     550              : #ifdef DEBUG_TRACI
     551              :                 if DEBUG_COND2(veh) {
     552              :                     if (dist < -100000) {
     553              :                         // also the ego vehicle is not ahead of the reference vehicle -> no CF-relation
     554              :                         std::cout <<  " Ego and reference vehicle are not in CF relation..." << std::endl;
     555              :                     } else {
     556              :                         std::cout <<  " Reference vehicle is behind ego..." << std::endl;
     557              :                     }
     558              :                 }
     559              : #endif
     560              :             }
     561          438 :             leaderInfo = std::make_pair(leader, dist - msVeh->getVehicleType().getMinGap());
     562              :         }
     563         7750 :         const double fakeDist = MAX2(0.0, leaderInfo.second - myGapControlState->addGapCurrent);
     564              : #ifdef DEBUG_TRACI
     565              :         if DEBUG_COND2(veh) {
     566              :             const double desiredCurrentSpacing = myGapControlState->tauCurrent * currentSpeed;
     567              :             std::cout <<  " Gap control active:"
     568              :                       << " currentSpeed=" << currentSpeed
     569              :                       << ", desiredTargetTimeSpacing=" << desiredTargetTimeSpacing
     570              :                       << ", desiredCurrentSpacing=" << desiredCurrentSpacing
     571              :                       << ", leader=" << (leaderInfo.first == nullptr ? "NULL" : leaderInfo.first->getID())
     572              :                       << ", dist=" << leaderInfo.second
     573              :                       << ", fakeDist=" << fakeDist
     574              :                       << ",\n tauOriginal=" << myGapControlState->tauOriginal
     575              :                       << ", tauTarget=" << myGapControlState->tauTarget
     576              :                       << ", tauCurrent=" << myGapControlState->tauCurrent
     577              :                       << std::endl;
     578              :         }
     579              : #endif
     580         7750 :         if (leaderInfo.first != nullptr) {
     581              :             if (myGapControlState->prevLeader != nullptr && myGapControlState->prevLeader != leaderInfo.first) {
     582              :                 // TODO: The leader changed. What to do?
     583              :             }
     584              :             // Remember leader
     585         7750 :             myGapControlState->prevLeader = leaderInfo.first;
     586              : 
     587              :             // Calculate desired following speed assuming the alternative headway time
     588         7750 :             MSCFModel* cfm = (MSCFModel*) & (msVeh->getVehicleType().getCarFollowModel());
     589         7750 :             const double origTau = cfm->getHeadwayTime();
     590         7750 :             cfm->setHeadwayTime(myGapControlState->tauCurrent);
     591         7750 :             gapControlSpeed = MIN2(gapControlSpeed,
     592         7750 :                                    cfm->followSpeed(msVeh, currentSpeed, fakeDist, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first));
     593         7750 :             cfm->setHeadwayTime(origTau);
     594              : #ifdef DEBUG_TRACI
     595              :             if DEBUG_COND2(veh) {
     596              :                 std::cout << " -> gapControlSpeed=" << gapControlSpeed;
     597              :                 if (myGapControlState->maxDecel > 0) {
     598              :                     std::cout << ", with maxDecel bound: " << MAX2(gapControlSpeed, currentSpeed - TS * myGapControlState->maxDecel);
     599              :                 }
     600              :                 std::cout << std::endl;
     601              :             }
     602              : #endif
     603         7750 :             if (myGapControlState->maxDecel > 0) {
     604         2540 :                 gapControlSpeed = MAX2(gapControlSpeed, currentSpeed - TS * myGapControlState->maxDecel);
     605              :             }
     606              :         }
     607              : 
     608              :         // Update gap controller
     609              :         // Check (1) if the gap control has established the desired gap,
     610              :         // and (2) if it has maintained active for the given duration afterwards
     611         7750 :         if (myGapControlState->lastUpdate < currentTime) {
     612              : #ifdef DEBUG_TRACI
     613              :             if DEBUG_COND2(veh) {
     614              :                 std::cout << " Updating GapControlState." << std::endl;
     615              :             }
     616              : #endif
     617         7750 :             if (myGapControlState->tauCurrent == myGapControlState->tauTarget && myGapControlState->addGapCurrent == myGapControlState->addGapTarget) {
     618         2968 :                 if (!myGapControlState->gapAttained) {
     619              :                     // Check if the desired gap was established (add the POSITION_EPS to avoid infinite asymptotic behavior without having established the gap)
     620         4151 :                     myGapControlState->gapAttained = leaderInfo.first == nullptr ||  leaderInfo.second > MAX2(desiredTargetTimeSpacing, myGapControlState->addGapTarget) - POSITION_EPS;
     621              : #ifdef DEBUG_TRACI
     622              :                     if DEBUG_COND2(veh) {
     623              :                         if (myGapControlState->gapAttained) {
     624              :                             std::cout << "   Target gap was established." << std::endl;
     625              :                         }
     626              :                     }
     627              : #endif
     628              :                 } else {
     629              :                     // Count down remaining time if desired gap was established
     630          914 :                     myGapControlState->remainingDuration -= TS;
     631              : #ifdef DEBUG_TRACI
     632              :                     if DEBUG_COND2(veh) {
     633              :                         std::cout << "   Gap control remaining duration: " << myGapControlState->remainingDuration << std::endl;
     634              :                     }
     635              : #endif
     636          914 :                     if (myGapControlState->remainingDuration <= 0) {
     637              : #ifdef DEBUG_TRACI
     638              :                         if DEBUG_COND2(veh) {
     639              :                             std::cout << "   Gap control duration expired, deactivating control." << std::endl;
     640              :                         }
     641              : #endif
     642              :                         // switch off gap control
     643           43 :                         myGapControlState->deactivate();
     644              :                     }
     645              :                 }
     646              :             } else {
     647              :                 // Adjust current headway values
     648         4782 :                 myGapControlState->tauCurrent = MIN2(myGapControlState->tauCurrent + myGapControlState->timeHeadwayIncrement, myGapControlState->tauTarget);
     649         5160 :                 myGapControlState->addGapCurrent = MIN2(myGapControlState->addGapCurrent + myGapControlState->spaceHeadwayIncrement, myGapControlState->addGapTarget);
     650              :             }
     651              :         }
     652         7750 :         if (myConsiderSafeVelocity) {
     653              :             gapControlSpeed = MIN2(gapControlSpeed, vSafe);
     654              :         }
     655         7750 :         if (myConsiderMaxAcceleration) {
     656              :             gapControlSpeed = MIN2(gapControlSpeed, vMax);
     657              :         }
     658         7750 :         if (myConsiderMaxDeceleration) {
     659              :             gapControlSpeed = MAX2(gapControlSpeed, vMin);
     660              :         }
     661              :         return MIN2(speed, gapControlSpeed);
     662              :     } else {
     663              :         return speed;
     664              :     }
     665              : }
     666              : 
     667              : double
     668         3531 : MSVehicle::Influencer::getOriginalSpeed() const {
     669         3531 :     return myOriginalSpeed;
     670              : }
     671              : 
     672              : void
     673       467049 : MSVehicle::Influencer::setOriginalSpeed(double speed) {
     674       467049 :     myOriginalSpeed = speed;
     675       467049 : }
     676              : 
     677              : 
     678              : int
     679      2295816 : MSVehicle::Influencer::influenceChangeDecision(const SUMOTime currentTime, const MSEdge& currentEdge, const int currentLaneIndex, int state) {
     680              :     // remove leading commands which are no longer valid
     681      2296118 :     while (myLaneTimeLine.size() == 1 || (myLaneTimeLine.size() > 1 && currentTime > myLaneTimeLine[1].first)) {
     682              :         myLaneTimeLine.erase(myLaneTimeLine.begin());
     683              :     }
     684              :     ChangeRequest changeRequest = REQUEST_NONE;
     685              :     // do nothing if the time line does not apply for the current time
     686      2295816 :     if (myLaneTimeLine.size() >= 2 && currentTime >= myLaneTimeLine[0].first) {
     687       176921 :         const int destinationLaneIndex = myLaneTimeLine[1].second;
     688       176921 :         if (destinationLaneIndex < (int)currentEdge.getLanes().size()) {
     689       176590 :             if (currentLaneIndex > destinationLaneIndex) {
     690              :                 changeRequest = REQUEST_RIGHT;
     691       175587 :             } else if (currentLaneIndex < destinationLaneIndex) {
     692              :                 changeRequest = REQUEST_LEFT;
     693              :             } else {
     694              :                 changeRequest = REQUEST_HOLD;
     695              :             }
     696          331 :         } else if (currentEdge.getLanes().back()->getOpposite() != nullptr) { // change to opposite direction driving
     697              :             changeRequest = REQUEST_LEFT;
     698          331 :             state = state | LCA_TRACI;
     699              :         }
     700              :     }
     701              :     // check whether the current reason shall be canceled / overridden
     702      2295816 :     if ((state & LCA_WANTS_LANECHANGE_OR_STAY) != 0) {
     703              :         // flags for the current reason
     704              :         LaneChangeMode mode = LC_NEVER;
     705      1487047 :         if ((state & LCA_TRACI) != 0 && myLatDist != 0) {
     706              :             // security checks
     707         2877 :             if ((myTraciLaneChangePriority == LCP_ALWAYS)
     708          692 :                     || (myTraciLaneChangePriority == LCP_NOOVERLAP && (state & LCA_OVERLAPPING) == 0)) {
     709         2720 :                 state &= ~(LCA_BLOCKED | LCA_OVERLAPPING);
     710              :             }
     711              :             // continue sublane change manoeuvre
     712         2877 :             return state;
     713      1484170 :         } else if ((state & LCA_STRATEGIC) != 0) {
     714       477856 :             mode = myStrategicLC;
     715      1006314 :         } else if ((state & LCA_COOPERATIVE) != 0) {
     716           36 :             mode = myCooperativeLC;
     717      1006278 :         } else if ((state & LCA_SPEEDGAIN) != 0) {
     718        25202 :             mode = mySpeedGainLC;
     719       981076 :         } else if ((state & LCA_KEEPRIGHT) != 0) {
     720        10116 :             mode = myRightDriveLC;
     721       970960 :         } else if ((state & LCA_SUBLANE) != 0) {
     722       970958 :             mode = mySublaneLC;
     723            2 :         } else if ((state & LCA_TRACI) != 0) {
     724              :             mode = LC_NEVER;
     725              :         } else {
     726            0 :             WRITE_WARNINGF(TL("Lane change model did not provide a reason for changing (state=%, time=%\n"), toString(state), time2string(currentTime));
     727              :         }
     728      1484168 :         if (mode == LC_NEVER) {
     729              :             // cancel all lcModel requests
     730              :             state &= ~LCA_WANTS_LANECHANGE_OR_STAY;
     731        31459 :             state &= ~LCA_URGENT;
     732      1452711 :         } else if (mode == LC_NOCONFLICT && changeRequest != REQUEST_NONE) {
     733         9015 :             if (
     734         9015 :                 ((state & LCA_LEFT) != 0 && changeRequest != REQUEST_LEFT) ||
     735         7929 :                 ((state & LCA_RIGHT) != 0 && changeRequest != REQUEST_RIGHT) ||
     736         6598 :                 ((state & LCA_STAY) != 0 && changeRequest != REQUEST_HOLD)) {
     737              :                 // cancel conflicting lcModel request
     738              :                 state &= ~LCA_WANTS_LANECHANGE_OR_STAY;
     739         2581 :                 state &= ~LCA_URGENT;
     740              :             }
     741      1443696 :         } else if (mode == LC_ALWAYS) {
     742              :             // ignore any TraCI requests
     743              :             return state;
     744              :         }
     745              :     }
     746              :     // apply traci requests
     747      2286579 :     if (changeRequest == REQUEST_NONE) {
     748      2116526 :         return state;
     749              :     } else {
     750       176403 :         state |= LCA_TRACI;
     751              :         // security checks
     752       176403 :         if ((myTraciLaneChangePriority == LCP_ALWAYS)
     753       174329 :                 || (myTraciLaneChangePriority == LCP_NOOVERLAP && (state & LCA_OVERLAPPING) == 0)) {
     754         2541 :             state &= ~(LCA_BLOCKED | LCA_OVERLAPPING);
     755              :         }
     756       176403 :         if (changeRequest != REQUEST_HOLD && myTraciLaneChangePriority != LCP_OPPORTUNISTIC) {
     757         2294 :             state |= LCA_URGENT;
     758              :         }
     759         2323 :         switch (changeRequest) {
     760              :             case REQUEST_HOLD:
     761       174080 :                 return state | LCA_STAY;
     762         1420 :             case REQUEST_LEFT:
     763         1420 :                 return state | LCA_LEFT;
     764          903 :             case REQUEST_RIGHT:
     765          903 :                 return state | LCA_RIGHT;
     766              :             default:
     767              :                 throw ProcessError(TL("should not happen"));
     768              :         }
     769              :     }
     770              : }
     771              : 
     772              : 
     773              : double
     774          442 : MSVehicle::Influencer::changeRequestRemainingSeconds(const SUMOTime currentTime) const {
     775              :     assert(myLaneTimeLine.size() >= 2);
     776              :     assert(currentTime >= myLaneTimeLine[0].first);
     777          442 :     return STEPS2TIME(myLaneTimeLine[1].first - currentTime);
     778              : }
     779              : 
     780              : 
     781              : void
     782        60338 : MSVehicle::Influencer::setSpeedMode(int speedMode) {
     783        60338 :     myConsiderSafeVelocity = ((speedMode & 1) != 0);
     784        60338 :     myConsiderMaxAcceleration = ((speedMode & 2) != 0);
     785        60338 :     myConsiderMaxDeceleration = ((speedMode & 4) != 0);
     786        60338 :     myRespectJunctionPriority = ((speedMode & 8) != 0);
     787        60338 :     myEmergencyBrakeRedLight = ((speedMode & 16) != 0);
     788        60338 :     myRespectJunctionLeaderPriority = ((speedMode & 32) == 0); // inverted!
     789        60338 : }
     790              : 
     791              : 
     792              : void
     793        15895 : MSVehicle::Influencer::setLaneChangeMode(int value) {
     794        15895 :     myStrategicLC = (LaneChangeMode)(value & (1 + 2));
     795        15895 :     myCooperativeLC = (LaneChangeMode)((value & (4 + 8)) >> 2);
     796        15895 :     mySpeedGainLC = (LaneChangeMode)((value & (16 + 32)) >> 4);
     797        15895 :     myRightDriveLC = (LaneChangeMode)((value & (64 + 128)) >> 6);
     798        15895 :     myTraciLaneChangePriority = (TraciLaneChangePriority)((value & (256 + 512)) >> 8);
     799        15895 :     mySublaneLC = (LaneChangeMode)((value & (1024 + 2048)) >> 10);
     800        15895 : }
     801              : 
     802              : 
     803              : void
     804         7783 : MSVehicle::Influencer::setRemoteControlled(Position xyPos, MSLane* l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector& route, SUMOTime t) {
     805         7783 :     myRemoteXYPos = xyPos;
     806         7783 :     myRemoteLane = l;
     807         7783 :     myRemotePos = pos;
     808         7783 :     myRemotePosLat = posLat;
     809         7783 :     myRemoteAngle = angle;
     810         7783 :     myRemoteEdgeOffset = edgeOffset;
     811         7783 :     myRemoteRoute = route;
     812         7783 :     myLastRemoteAccess = t;
     813         7783 : }
     814              : 
     815              : 
     816              : bool
     817       956298 : MSVehicle::Influencer::isRemoteControlled() const {
     818       956298 :     return myLastRemoteAccess == MSNet::getInstance()->getCurrentTimeStep();
     819              : }
     820              : 
     821              : 
     822              : bool
     823       503946 : MSVehicle::Influencer::isRemoteAffected(SUMOTime t) const {
     824       503946 :     return myLastRemoteAccess >= t - TIME2STEPS(10);
     825              : }
     826              : 
     827              : 
     828              : void
     829       460523 : MSVehicle::Influencer::updateRemoteControlRoute(MSVehicle* v) {
     830       460523 :     if (myRemoteRoute.size() != 0 && myRemoteRoute != v->getRoute().getEdges()) {
     831              :         // only replace route at this time if the vehicle is moving with the flow
     832           62 :         const bool isForward = v->getLane() != 0 && &v->getLane()->getEdge() == myRemoteRoute[0];
     833              : #ifdef DEBUG_REMOTECONTROL
     834              :         std::cout << SIMSTEP << " updateRemoteControlRoute veh=" << v->getID() << " old=" << toString(v->getRoute().getEdges()) << " new=" << toString(myRemoteRoute) << " fwd=" << isForward << "\n";
     835              : #endif
     836              :         if (isForward) {
     837           10 :             v->replaceRouteEdges(myRemoteRoute, -1, 0, "traci:moveToXY", true);
     838           10 :             v->updateBestLanes();
     839              :         }
     840              :     }
     841       460523 : }
     842              : 
     843              : 
     844              : void
     845         7758 : MSVehicle::Influencer::postProcessRemoteControl(MSVehicle* v) {
     846         7758 :     const bool wasOnRoad = v->isOnRoad();
     847         7758 :     const bool withinLane = myRemoteLane != nullptr && fabs(myRemotePosLat) < 0.5 * (myRemoteLane->getWidth() + v->getVehicleType().getWidth());
     848         7758 :     const bool keepLane = wasOnRoad && v->getLane() == myRemoteLane;
     849         7758 :     if (v->isOnRoad() && !(keepLane && withinLane)) {
     850          149 :         if (myRemoteLane != nullptr && &v->getLane()->getEdge() == &myRemoteLane->getEdge()) {
     851              :             // correct odometer which gets incremented via onRemovalFromNet->leaveLane
     852           71 :             v->myOdometer -= v->getLane()->getLength();
     853              :         }
     854          149 :         v->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
     855          149 :         v->getMutableLane()->removeVehicle(v, MSMoveReminder::NOTIFICATION_TELEPORT, false);
     856              :     }
     857         7758 :     if (myRemoteRoute.size() != 0 && myRemoteRoute != v->getRoute().getEdges()) {
     858              :         // needed for the insertion step
     859              : #ifdef DEBUG_REMOTECONTROL
     860              :         std::cout << SIMSTEP << " postProcessRemoteControl veh=" << v->getID()
     861              :                   << "\n  oldLane=" << Named::getIDSecure(v->getLane())
     862              :                   << " oldRoute=" << toString(v->getRoute().getEdges())
     863              :                   << "\n  newLane=" << Named::getIDSecure(myRemoteLane)
     864              :                   << " newRoute=" << toString(myRemoteRoute)
     865              :                   << " newRouteEdge=" << myRemoteRoute[myRemoteEdgeOffset]->getID()
     866              :                   << "\n";
     867              : #endif
     868              :         // clear any prior stops because they cannot apply to the new route
     869           67 :         const_cast<SUMOVehicleParameter&>(v->getParameter()).stops.clear();
     870          134 :         v->replaceRouteEdges(myRemoteRoute, -1, 0, "traci:moveToXY", true);
     871              :         myRemoteRoute.clear();
     872              :     }
     873         7758 :     v->myCurrEdge = v->getRoute().begin() + myRemoteEdgeOffset;
     874         7758 :     if (myRemoteLane != nullptr && myRemotePos > myRemoteLane->getLength()) {
     875            0 :         myRemotePos = myRemoteLane->getLength();
     876              :     }
     877         7758 :     if (myRemoteLane != nullptr && withinLane) {
     878         7586 :         if (keepLane) {
     879              :             // TODO this handles only the case when the new vehicle is completely on the edge
     880         7413 :             const bool needFurtherUpdate = v->myState.myPos < v->getVehicleType().getLength() && myRemotePos >= v->getVehicleType().getLength();
     881         7413 :             v->myState.myPos = myRemotePos;
     882         7413 :             v->myState.myPosLat = myRemotePosLat;
     883         7413 :             if (needFurtherUpdate) {
     884            5 :                 v->myState.myBackPos = v->updateFurtherLanes(v->myFurtherLanes, v->myFurtherLanesPosLat, std::vector<MSLane*>());
     885              :             }
     886              :         } else {
     887          173 :             MSMoveReminder::Notification notify = v->getDeparture() == NOT_YET_DEPARTED
     888          173 :                                                   ? MSMoveReminder::NOTIFICATION_DEPARTED
     889              :                                                   : MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
     890          173 :             if (!v->isOnRoad()) {
     891          173 :                 MSVehicleTransfer::getInstance()->remove(v);  // TODO may need optimization, this is linear in the number of vehicles in transfer
     892              :             }
     893          173 :             myRemoteLane->forceVehicleInsertion(v, myRemotePos, notify, myRemotePosLat);
     894          173 :             v->updateBestLanes();
     895              :         }
     896         7586 :         if (!wasOnRoad) {
     897           61 :             v->drawOutsideNetwork(false);
     898              :         }
     899              :         //std::cout << "on road network p=" << myRemoteXYPos << " a=" << myRemoteAngle << " l=" << Named::getIDSecure(myRemoteLane) << " pos=" << myRemotePos << " posLat=" << myRemotePosLat << "\n";
     900         7586 :         myRemoteLane->requireCollisionCheck();
     901              :     } else {
     902          172 :         if (v->getDeparture() == NOT_YET_DEPARTED) {
     903            5 :             v->onDepart();
     904              :         }
     905          172 :         v->drawOutsideNetwork(true);
     906              :         // see updateState
     907          172 :         double vNext = v->processTraCISpeedControl(
     908          172 :                            v->getMaxSpeed(), v->getSpeed());
     909          172 :         v->setBrakingSignals(vNext);
     910          172 :         v->myState.myPreviousSpeed = v->getSpeed();
     911          172 :         v->myAcceleration = SPEED2ACCEL(vNext - v->getSpeed());
     912          172 :         v->myState.mySpeed = vNext;
     913          172 :         v->updateWaitingTime(vNext);
     914              :         //std::cout << "outside network p=" << myRemoteXYPos << " a=" << myRemoteAngle << " l=" << Named::getIDSecure(myRemoteLane) << "\n";
     915              :     }
     916              :     // ensure that the position is correct (i.e. when the lanePosition is ambiguous at corners)
     917         7758 :     v->setRemoteState(myRemoteXYPos);
     918         7758 :     v->setAngle(GeomHelper::fromNaviDegree(myRemoteAngle));
     919         7758 : }
     920              : 
     921              : 
     922              : double
     923         7734 : MSVehicle::Influencer::implicitSpeedRemote(const MSVehicle* veh, double oldSpeed) {
     924         7734 :     if (veh->getPosition() == Position::INVALID) {
     925            5 :         return oldSpeed;
     926              :     }
     927         7729 :     double dist = veh->getPosition().distanceTo2D(myRemoteXYPos);
     928         7729 :     if (myRemoteLane != nullptr) {
     929              :         // if the vehicles is frequently placed on a new edge, the route may
     930              :         // consist only of a single edge. In this case the new edge may not be
     931              :         // on the route so distAlongRoute will be double::max.
     932              :         // In this case we still want a sensible speed value
     933         7587 :         const double distAlongRoute = veh->getDistanceToPosition(myRemotePos, myRemoteLane);
     934         7587 :         if (distAlongRoute != std::numeric_limits<double>::max()) {
     935              :             dist = distAlongRoute;
     936              :         }
     937              :     }
     938              :     //std::cout << SIMTIME << " veh=" << veh->getID() << " oldPos=" << veh->getPosition() << " traciPos=" << myRemoteXYPos << " dist=" << dist << "\n";
     939         7729 :     const double minSpeed = myConsiderMaxDeceleration ?
     940         5021 :                             veh->getCarFollowModel().minNextSpeedEmergency(oldSpeed, veh) : 0;
     941         7729 :     const double maxSpeed = (myRemoteLane != nullptr
     942         7729 :                              ? myRemoteLane->getVehicleMaxSpeed(veh)
     943          142 :                              : (veh->getLane() != nullptr
     944          142 :                                 ? veh->getLane()->getVehicleMaxSpeed(veh)
     945            5 :                                 : veh->getMaxSpeed()));
     946         7729 :     return MIN2(maxSpeed, MAX2(minSpeed, DIST2SPEED(dist)));
     947              : }
     948              : 
     949              : 
     950              : double
     951         7562 : MSVehicle::Influencer::implicitDeltaPosRemote(const MSVehicle* veh) {
     952              :     double dist = 0;
     953         7562 :     if (myRemoteLane == nullptr) {
     954            6 :         dist = veh->getPosition().distanceTo2D(myRemoteXYPos);
     955              :     } else {
     956              :         // if the vehicles is frequently placed on a new edge, the route may
     957              :         // consist only of a single edge. In this case the new edge may not be
     958              :         // on the route so getDistanceToPosition will return double::max.
     959              :         // In this case we would rather not move the vehicle in executeMove
     960              :         // (updateState) as it would result in emergency braking
     961         7556 :         dist = veh->getDistanceToPosition(myRemotePos, myRemoteLane);
     962              :     }
     963         7562 :     if (dist == std::numeric_limits<double>::max()) {
     964              :         return 0;
     965              :     } else {
     966         7332 :         if (DIST2SPEED(dist) > veh->getMaxSpeed() * 1.1) {
     967           33 :             WRITE_WARNINGF(TL("Vehicle '%' moved by TraCI from % to % (dist %) with implied speed of % (exceeding maximum speed %). time=%."),
     968              :                            veh->getID(), veh->getPosition(), myRemoteXYPos, dist, DIST2SPEED(dist), veh->getMaxSpeed(), time2string(SIMSTEP));
     969              :             // some sanity check here
     970           11 :             dist = MIN2(dist, SPEED2DIST(veh->getMaxSpeed() * 2));
     971              :         }
     972         7332 :         return dist;
     973              :     }
     974              : }
     975              : 
     976              : 
     977              : /* -------------------------------------------------------------------------
     978              :  * MSVehicle-methods
     979              :  * ----------------------------------------------------------------------- */
     980      3892667 : MSVehicle::MSVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
     981      3892667 :                      MSVehicleType* type, const double speedFactor) :
     982              :     MSBaseVehicle(pars, route, type, speedFactor),
     983      3892667 :     myWaitingTime(0),
     984      3892667 :     myWaitingTimeCollector(),
     985      3892667 :     myTimeLoss(0),
     986      3892667 :     myState(0, 0, 0, 0, 0),
     987      3892667 :     myDriverState(nullptr),
     988      3892667 :     myActionStep(true),
     989      3892667 :     myLastActionTime(0),
     990      3892667 :     myLane(nullptr),
     991      3892667 :     myLaneChangeModel(nullptr),
     992      3892667 :     myLastBestLanesEdge(nullptr),
     993      3892667 :     myLastBestLanesInternalLane(nullptr),
     994      3892667 :     myAcceleration(0),
     995              :     myNextTurn(0., nullptr),
     996      3892667 :     mySignals(0),
     997      3892667 :     myAmOnNet(false),
     998      3892667 :     myAmIdling(false),
     999      3892667 :     myHaveToWaitOnNextLink(false),
    1000      3892667 :     myAngle(0),
    1001      3892667 :     myStopDist(std::numeric_limits<double>::max()),
    1002      3892667 :     myCollisionImmunity(-1),
    1003      3892667 :     myCachedPosition(Position::INVALID),
    1004      3892667 :     myJunctionEntryTime(SUMOTime_MAX),
    1005      3892667 :     myJunctionEntryTimeNeverYield(SUMOTime_MAX),
    1006      3892667 :     myJunctionConflictEntryTime(SUMOTime_MAX),
    1007      3892667 :     myTimeSinceStartup(TIME2STEPS(3600 * 24)),
    1008     11678001 :     myInfluencer(nullptr) {
    1009      3892667 :     myCFVariables = type->getCarFollowModel().createVehicleVariables();
    1010      3892667 :     myNextDriveItem = myLFLinkLanes.begin();
    1011      3892667 : }
    1012              : 
    1013              : 
    1014      7311123 : MSVehicle::~MSVehicle() {
    1015      3892595 :     cleanupFurtherLanes();
    1016      3892595 :     delete myLaneChangeModel;
    1017      3892595 :     if (myType->isVehicleSpecific()) {
    1018          292 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    1019              :     }
    1020      3892595 :     delete myInfluencer;
    1021      3892595 :     delete myCFVariables;
    1022     11203718 : }
    1023              : 
    1024              : 
    1025              : void
    1026      3893157 : MSVehicle::cleanupFurtherLanes() {
    1027      3895875 :     for (MSLane* further : myFurtherLanes) {
    1028         2718 :         further->resetPartialOccupation(this);
    1029         2718 :         if (further->getBidiLane() != nullptr
    1030         2718 :                 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    1031            0 :             further->getBidiLane()->resetPartialOccupation(this);
    1032              :         }
    1033              :     }
    1034      3893157 :     if (myLaneChangeModel != nullptr) {
    1035      3893123 :         removeApproachingInformation(myLFLinkLanes);
    1036      3893123 :         myLaneChangeModel->cleanupShadowLane();
    1037      3893123 :         myLaneChangeModel->cleanupTargetLane();
    1038              :         // still needed when calling resetPartialOccupation (getShadowLane) and when removing
    1039              :         // approach information from parallel links
    1040              :     }
    1041              :     myFurtherLanes.clear();
    1042              :     myFurtherLanesPosLat.clear();
    1043      3893157 : }
    1044              : 
    1045              : 
    1046              : void
    1047      2544996 : MSVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
    1048              : #ifdef DEBUG_ACTIONSTEPS
    1049              :     if (DEBUG_COND) {
    1050              :         std::cout << SIMTIME << " Removing vehicle '" << getID() << "' (reason: " << toString(reason) << ")" << std::endl;
    1051              :     }
    1052              : #endif
    1053      2544996 :     MSVehicleTransfer::getInstance()->remove(this);
    1054      2544996 :     removeApproachingInformation(myLFLinkLanes);
    1055      2544996 :     leaveLane(reason);
    1056      2544996 :     if (reason == MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION) {
    1057          562 :         cleanupFurtherLanes();
    1058              :     }
    1059      2544996 : }
    1060              : 
    1061              : 
    1062              : void
    1063      3892667 : MSVehicle::initDevices() {
    1064      3892667 :     MSBaseVehicle::initDevices();
    1065      3892655 :     myLaneChangeModel = MSAbstractLaneChangeModel::build(myType->getLaneChangeModel(), *this);
    1066      3892633 :     myDriverState = static_cast<MSDevice_DriverState*>(getDevice(typeid(MSDevice_DriverState)));
    1067      3892633 :     myFrictionDevice = static_cast<MSDevice_Friction*>(getDevice(typeid(MSDevice_Friction)));
    1068      3892633 : }
    1069              : 
    1070              : 
    1071              : // ------------ interaction with the route
    1072              : bool
    1073   2266616223 : MSVehicle::hasValidRouteStart(std::string& msg) {
    1074              :     // note: not a const method because getDepartLane may call updateBestLanes
    1075   2266616223 :     if (!(*myCurrEdge)->isTazConnector()) {
    1076   2266187024 :         if (myParameter->departLaneProcedure == DepartLaneDefinition::GIVEN) {
    1077     50111438 :             if ((*myCurrEdge)->getDepartLane(*this) == nullptr) {
    1078          124 :                 msg = "Invalid departlane definition for vehicle '" + getID() + "'.";
    1079           62 :                 if (myParameter->departLane >= (int)(*myCurrEdge)->getLanes().size()) {
    1080           11 :                     myRouteValidity |= ROUTE_START_INVALID_LANE;
    1081              :                 } else {
    1082           51 :                     myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
    1083              :                 }
    1084           62 :                 return false;
    1085              :             }
    1086              :         } else {
    1087   2216075586 :             if ((*myCurrEdge)->allowedLanes(getVClass()) == nullptr) {
    1088          146 :                 msg = "Vehicle '" + getID() + "' is not allowed to depart on any lane of edge '" + (*myCurrEdge)->getID() + "'.";
    1089           73 :                 myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
    1090           73 :                 return false;
    1091              :             }
    1092              :         }
    1093   2266186889 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
    1094           38 :             msg = "Departure speed for vehicle '" + getID() + "' is too high for the vehicle type '" + myType->getID() + "'.";
    1095           19 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
    1096           19 :             return false;
    1097              :         }
    1098              :     }
    1099   2266616069 :     myRouteValidity &= ~(ROUTE_START_INVALID_LANE | ROUTE_START_INVALID_PERMISSIONS);
    1100   2266616069 :     return true;
    1101              : }
    1102              : 
    1103              : 
    1104              : bool
    1105    548693688 : MSVehicle::hasArrived() const {
    1106    548693688 :     return hasArrivedInternal(false);
    1107              : }
    1108              : 
    1109              : 
    1110              : bool
    1111   1108335965 : MSVehicle::hasArrivedInternal(bool oppositeTransformed) const {
    1112   1925315097 :     return ((myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge))
    1113    291390189 :             && (myStops.empty() || myStops.front().edge != myCurrEdge || myStops.front().getSpeed() > 0)
    1114    260936847 :             && ((myLaneChangeModel->isOpposite() && !oppositeTransformed) ? myLane->getLength() - myState.myPos : myState.myPos) > myArrivalPos - POSITION_EPS
    1115   1116137520 :             && !isRemoteControlled());
    1116              : }
    1117              : 
    1118              : 
    1119              : bool
    1120      1634750 : MSVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
    1121      3269500 :     if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
    1122              :         // update best lanes (after stops were added)
    1123      1634742 :         myLastBestLanesEdge = nullptr;
    1124      1634742 :         myLastBestLanesInternalLane = nullptr;
    1125      1634742 :         updateBestLanes(true, onInit ? (*myCurrEdge)->getLanes().front() : 0);
    1126              :         assert(!removeStops || haveValidStopEdges());
    1127      1634742 :         if (myStops.size() == 0) {
    1128      1608040 :             myStopDist = std::numeric_limits<double>::max();
    1129              :         }
    1130      1634742 :         return true;
    1131              :     }
    1132              :     return false;
    1133              : }
    1134              : 
    1135              : 
    1136              : // ------------ Interaction with move reminders
    1137              : void
    1138    540558405 : MSVehicle::workOnMoveReminders(double oldPos, double newPos, double newSpeed) {
    1139              :     // This erasure-idiom works for all stl-sequence-containers
    1140              :     // See Meyers: Effective STL, Item 9
    1141   1561806801 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
    1142              :         // XXX: calling notifyMove with newSpeed seems not the best choice. For the ballistic update, the average speed is calculated and used
    1143              :         //      although a higher order quadrature-formula might be more adequate.
    1144              :         //      For the euler case (where the speed is considered constant for each time step) it is conceivable that
    1145              :         //      the current calculations may lead to systematic errors for large time steps (compared to reality). Refs. #2579
    1146   2042496792 :         if (!rem->first->notifyMove(*this, oldPos + rem->second, newPos + rem->second, MAX2(0., newSpeed))) {
    1147              : #ifdef _DEBUG
    1148              :             if (myTraceMoveReminders) {
    1149              :                 traceMoveReminder("notifyMove", rem->first, rem->second, false);
    1150              :             }
    1151              : #endif
    1152              :             rem = myMoveReminders.erase(rem);
    1153              :         } else {
    1154              : #ifdef _DEBUG
    1155              :             if (myTraceMoveReminders) {
    1156              :                 traceMoveReminder("notifyMove", rem->first, rem->second, true);
    1157              :             }
    1158              : #endif
    1159              :             ++rem;
    1160              :         }
    1161              :     }
    1162    540558405 :     if (myEnergyParams != nullptr) {
    1163              :         // TODO make the vehicle energy params a derived class which is a move reminder
    1164    121414162 :         const double duration = myEnergyParams->getDouble(SUMO_ATTR_DURATION);
    1165    121414162 :         if (isStopped()) {
    1166      3369508 :             if (duration < 0) {
    1167         9176 :                 myEnergyParams->setDouble(SUMO_ATTR_DURATION, STEPS2TIME(getNextStop().duration));
    1168        17064 :                 myEnergyParams->setDouble(SUMO_ATTR_PARKING, isParking() ? 1. : 0.);
    1169              :             }
    1170              :         } else {
    1171    118044654 :             if (duration >= 0) {
    1172         5984 :                 myEnergyParams->setDouble(SUMO_ATTR_DURATION, -1.);
    1173              :             }
    1174              :         }
    1175    121414162 :         myEnergyParams->setDouble(SUMO_ATTR_WAITINGTIME, getWaitingSeconds());
    1176              :     }
    1177    540558405 : }
    1178              : 
    1179              : 
    1180              : void
    1181        74417 : MSVehicle::workOnIdleReminders() {
    1182        74417 :     updateWaitingTime(0.);   // cf issue 2233
    1183              : 
    1184              :     // vehicle move reminders
    1185        81215 :     for (const auto& rem : myMoveReminders) {
    1186         6798 :         rem.first->notifyIdle(*this);
    1187              :     }
    1188              : 
    1189              :     // lane move reminders - for aggregated values
    1190       195105 :     for (MSMoveReminder* rem : getLane()->getMoveReminders()) {
    1191       120688 :         rem->notifyIdle(*this);
    1192              :     }
    1193        74417 : }
    1194              : 
    1195              : // XXX: consider renaming...
    1196              : void
    1197     16834255 : MSVehicle::adaptLaneEntering2MoveReminder(const MSLane& enteredLane) {
    1198              :     // save the old work reminders, patching the position information
    1199              :     //  add the information about the new offset to the old lane reminders
    1200     16834255 :     const double oldLaneLength = myLane->getLength();
    1201     44352035 :     for (auto& rem : myMoveReminders) {
    1202     27517780 :         rem.second += oldLaneLength;
    1203              : #ifdef _DEBUG
    1204              : //        if (rem->first==0) std::cout << "Null reminder (?!)" << std::endl;
    1205              : //        std::cout << "Adapted MoveReminder on lane " << ((rem->first->getLane()==0) ? "NULL" : rem->first->getLane()->getID()) <<" position to " << rem->second << std::endl;
    1206              :         if (myTraceMoveReminders) {
    1207              :             traceMoveReminder("adaptedPos", rem.first, rem.second, true);
    1208              :         }
    1209              : #endif
    1210              :     }
    1211     25137495 :     for (MSMoveReminder* const rem : enteredLane.getMoveReminders()) {
    1212      8303240 :         addReminder(rem);
    1213              :     }
    1214     16834255 : }
    1215              : 
    1216              : 
    1217              : // ------------ Other getter methods
    1218              : double
    1219    151364628 : MSVehicle::getSlope() const {
    1220    151364628 :     if (isParking() && getStops().begin()->parkingarea != nullptr) {
    1221         3621 :         return getStops().begin()->parkingarea->getVehicleSlope(*this);
    1222              :     }
    1223    151361007 :     if (myLane == nullptr) {
    1224              :         return 0;
    1225              :     }
    1226    151361007 :     const double posLat = myState.myPosLat; // @todo get rid of the '-'
    1227    151361007 :     Position p1 = getPosition();
    1228    151361007 :     Position p2 = getBackPosition();
    1229              :     if (p2 == Position::INVALID) {
    1230              :         // Handle special case of vehicle's back reaching out of the network
    1231            7 :         if (myFurtherLanes.size() > 0) {
    1232            7 :             p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
    1233              :             if (p2 == Position::INVALID) {
    1234              :                 // unsuitable lane geometry
    1235            1 :                 p2 = myLane->geometryPositionAtOffset(0, posLat);
    1236              :             }
    1237              :         } else {
    1238            0 :             p2 = myLane->geometryPositionAtOffset(0, posLat);
    1239              :         }
    1240              :     }
    1241    151361007 :     return (p1 != p2 ? RAD2DEG(p2.slopeTo2D(p1)) : myLane->getShape().slopeDegreeAtOffset(myLane->interpolateLanePosToGeometryPos(getPositionOnLane())));
    1242              : }
    1243              : 
    1244              : 
    1245              : Position
    1246    744360420 : MSVehicle::getPosition(const double offset) const {
    1247    744360420 :     if (myLane == nullptr) {
    1248              :         // when called in the context of GUI-Drawing, the simulation step is already incremented
    1249          175 :         if (myInfluencer != nullptr && myInfluencer->isRemoteAffected(MSNet::getInstance()->getCurrentTimeStep())) {
    1250           50 :             return myCachedPosition;
    1251              :         } else {
    1252          125 :             return Position::INVALID;
    1253              :         }
    1254              :     }
    1255    744360245 :     if (isParking()) {
    1256        20802 :         if (myStops.begin()->parkingarea != nullptr) {
    1257        14432 :             return myStops.begin()->parkingarea->getVehiclePosition(*this);
    1258              :         } else {
    1259              :             // position beside the road
    1260         6370 :             PositionVector shp = myLane->getEdge().getLanes()[0]->getShape();
    1261        12620 :             shp.move2side(SUMO_const_laneWidth * (MSGlobals::gLefthand ? -1 : 1));
    1262         6370 :             return shp.positionAtOffset(myLane->interpolateLanePosToGeometryPos(getPositionOnLane() + offset));
    1263         6370 :         }
    1264              :     }
    1265    744339443 :     const bool changingLanes = myLaneChangeModel->isChangingLanes();
    1266   1478595211 :     const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
    1267    744339443 :     if (offset == 0. && !changingLanes) {
    1268              :         if (myCachedPosition == Position::INVALID) {
    1269    544806734 :             myCachedPosition = validatePosition(myLane->geometryPositionAtOffset(myState.myPos, posLat));
    1270    544806734 :             if (MSNet::getInstance()->hasElevation() && MSGlobals::gSublane) {
    1271        63344 :                 interpolateLateralZ(myCachedPosition, myState.myPos, posLat);
    1272              :             }
    1273              :         }
    1274    738267743 :         return myCachedPosition;
    1275              :     }
    1276      6071700 :     Position result = validatePosition(myLane->geometryPositionAtOffset(getPositionOnLane() + offset, posLat), offset);
    1277      6071700 :     interpolateLateralZ(result, getPositionOnLane() + offset, posLat);
    1278      6071700 :     return result;
    1279              : }
    1280              : 
    1281              : 
    1282              : void
    1283      6420076 : MSVehicle::interpolateLateralZ(Position& pos, double offset, double posLat) const {
    1284      6420076 :     const MSLane* shadow = myLaneChangeModel->getShadowLane();
    1285      6420076 :     if (shadow != nullptr && pos != Position::INVALID) {
    1286              :         // ignore negative offset
    1287              :         const Position shadowPos = shadow->geometryPositionAtOffset(MAX2(0.0, offset));
    1288        51736 :         if (shadowPos != Position::INVALID && pos.z() != shadowPos.z()) {
    1289         1141 :             const double centerDist = (myLane->getWidth() + shadow->getWidth()) * 0.5;
    1290         1141 :             double relOffset = fabs(posLat) / centerDist;
    1291         1141 :             double newZ = (1 - relOffset) * pos.z() + relOffset * shadowPos.z();
    1292              :             pos.setz(newZ);
    1293              :         }
    1294              :     }
    1295      6420076 : }
    1296              : 
    1297              : 
    1298              : double
    1299        89330 : MSVehicle::getDistanceToLeaveJunction() const {
    1300        89330 :     double result = getLength() - getPositionOnLane();
    1301        89330 :     if (myLane->isNormal()) {
    1302              :         return MAX2(0.0, result);
    1303              :     }
    1304          403 :     const MSLane* lane = myLane;
    1305          806 :     while (lane->isInternal()) {
    1306          403 :         result += lane->getLength();
    1307          403 :         lane = lane->getCanonicalSuccessorLane();
    1308              :     }
    1309              :     return result;
    1310              : }
    1311              : 
    1312              : 
    1313              : Position
    1314        12216 : MSVehicle::getPositionAlongBestLanes(double offset) const {
    1315              :     assert(MSGlobals::gUsingInternalLanes);
    1316        12216 :     if (!isOnRoad()) {
    1317            0 :         return Position::INVALID;
    1318              :     }
    1319        12216 :     const std::vector<MSLane*>& bestLanes = getBestLanesContinuation();
    1320              :     auto nextBestLane = bestLanes.begin();
    1321        12216 :     const bool opposite = myLaneChangeModel->isOpposite();
    1322        12216 :     double pos = opposite ? myLane->getLength() - myState.myPos : myState.myPos;
    1323        12216 :     const MSLane* lane = opposite ? myLane->getParallelOpposite() : getLane();
    1324              :     assert(lane != 0);
    1325              :     bool success = true;
    1326              : 
    1327        32709 :     while (offset > 0) {
    1328              :         // take into account lengths along internal lanes
    1329        35983 :         while (lane->isInternal() && offset > 0) {
    1330        15490 :             if (offset > lane->getLength() - pos) {
    1331         3509 :                 offset -= lane->getLength() - pos;
    1332         3509 :                 lane = lane->getLinkCont()[0]->getViaLaneOrLane();
    1333              :                 pos = 0.;
    1334         3509 :                 if (lane == nullptr) {
    1335              :                     success = false;
    1336              :                     offset = 0.;
    1337              :                 }
    1338              :             } else {
    1339        11981 :                 pos += offset;
    1340              :                 offset = 0;
    1341              :             }
    1342              :         }
    1343              :         // set nextBestLane to next non-internal lane
    1344        24672 :         while (nextBestLane != bestLanes.end() && *nextBestLane == nullptr) {
    1345              :             ++nextBestLane;
    1346              :         }
    1347        20493 :         if (offset > 0) {
    1348              :             assert(!lane->isInternal());
    1349              :             assert(lane == *nextBestLane);
    1350         8512 :             if (offset > lane->getLength() - pos) {
    1351         8329 :                 offset -= lane->getLength() - pos;
    1352              :                 ++nextBestLane;
    1353              :                 assert(nextBestLane == bestLanes.end() || *nextBestLane != 0);
    1354         8329 :                 if (nextBestLane == bestLanes.end()) {
    1355              :                     success = false;
    1356              :                     offset = 0.;
    1357              :                 } else {
    1358         8277 :                     const MSLink* link = lane->getLinkTo(*nextBestLane);
    1359              :                     assert(link != nullptr);
    1360              :                     lane = link->getViaLaneOrLane();
    1361              :                     pos = 0.;
    1362              :                 }
    1363              :             } else {
    1364          183 :                 pos += offset;
    1365              :                 offset = 0;
    1366              :             }
    1367              :         }
    1368              : 
    1369              :     }
    1370              : 
    1371        12216 :     if (success) {
    1372        12164 :         return lane->geometryPositionAtOffset(pos, -getLateralPositionOnLane());
    1373              :     } else {
    1374           52 :         return Position::INVALID;
    1375              :     }
    1376              : }
    1377              : 
    1378              : 
    1379              : double
    1380       405737 : MSVehicle::getMaxSpeedOnLane() const {
    1381       405737 :     if (myLane != nullptr) {
    1382       405737 :         return myLane->getVehicleMaxSpeed(this);
    1383              :     }
    1384            0 :     return myType->getMaxSpeed();
    1385              : }
    1386              : 
    1387              : 
    1388              : Position
    1389    550878434 : MSVehicle::validatePosition(Position result, double offset) const {
    1390              :     int furtherIndex = 0;
    1391    550878434 :     double lastLength = getPositionOnLane();
    1392    550878434 :     while (result == Position::INVALID) {
    1393       169130 :         if (furtherIndex >= (int)myFurtherLanes.size()) {
    1394              :             //WRITE_WARNINGF(TL("Could not compute position for vehicle '%', time=%."), getID(), time2string(MSNet::getInstance()->getCurrentTimeStep()));
    1395              :             break;
    1396              :         }
    1397              :         //std::cout << SIMTIME << " veh=" << getID() << " lane=" << myLane->getID() << " pos=" << getPositionOnLane() << " posLat=" << getLateralPositionOnLane() << " offset=" << offset << " result=" << result << " i=" << furtherIndex << " further=" << myFurtherLanes.size() << "\n";
    1398       162426 :         MSLane* further = myFurtherLanes[furtherIndex];
    1399       162426 :         offset += lastLength;
    1400       162426 :         result = further->geometryPositionAtOffset(further->getLength() + offset, -getLateralPositionOnLane());
    1401              :         lastLength = further->getLength();
    1402       162426 :         furtherIndex++;
    1403              :         //std::cout << SIMTIME << "   newResult=" << result << "\n";
    1404              :     }
    1405    550878434 :     return result;
    1406              : }
    1407              : 
    1408              : 
    1409              : ConstMSEdgeVector::const_iterator
    1410      3016455 : MSVehicle::getRerouteOrigin() const {
    1411              :     // too close to the next junction, so avoid an emergency brake here
    1412      3016455 :     if (myLane != nullptr && (myCurrEdge + 1) != myRoute->end()) {
    1413      1062266 :         if (myLane->isInternal()) {
    1414              :             return myCurrEdge + 1;
    1415              :         }
    1416      1052969 :         if (myState.myPos > myLane->getLength() - getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)) {
    1417              :             return myCurrEdge + 1;
    1418              :         }
    1419      1040834 :         if (myLane->getEdge().hasChangeProhibitions(getVClass(), myLane->getIndex())) {
    1420              :             return myCurrEdge + 1;
    1421              :         }
    1422              :     }
    1423      2994799 :     return myCurrEdge;
    1424              : }
    1425              : 
    1426              : void
    1427      4810948 : MSVehicle::setAngle(double angle, bool straightenFurther) {
    1428              : #ifdef DEBUG_FURTHER
    1429              :     if (DEBUG_COND) {
    1430              :         std::cout << SIMTIME << " veh '" << getID() << " setAngle(" << angle <<  ") straightenFurther=" << straightenFurther << std::endl;
    1431              :     }
    1432              : #endif
    1433      4810948 :     myAngle = angle;
    1434      4810948 :     MSLane* next = myLane;
    1435      4810948 :     if (straightenFurther && myFurtherLanesPosLat.size() > 0) {
    1436       189226 :         for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
    1437        96968 :             MSLane* further = myFurtherLanes[i];
    1438        96968 :             const MSLink* link = further->getLinkTo(next);
    1439        96968 :             if (link  != nullptr) {
    1440        96668 :                 myFurtherLanesPosLat[i] = getLateralPositionOnLane() - link->getLateralShift();
    1441              :                 next = further;
    1442              :             } else {
    1443              :                 break;
    1444              :             }
    1445              :         }
    1446              :     }
    1447      4810948 : }
    1448              : 
    1449              : 
    1450              : void
    1451       256666 : MSVehicle::setActionStepLength(double actionStepLength, bool resetOffset) {
    1452       256666 :     SUMOTime actionStepLengthMillisecs = SUMOVehicleParserHelper::processActionStepLength(actionStepLength);
    1453              :     SUMOTime previousActionStepLength = getActionStepLength();
    1454              :     const bool newActionStepLength = actionStepLengthMillisecs != previousActionStepLength;
    1455       256666 :     if (newActionStepLength) {
    1456            7 :         getSingularType().setActionStepLength(actionStepLengthMillisecs, resetOffset);
    1457            7 :         if (!resetOffset) {
    1458            1 :             updateActionOffset(previousActionStepLength, actionStepLengthMillisecs);
    1459              :         }
    1460              :     }
    1461       256660 :     if (resetOffset) {
    1462            6 :         resetActionOffset();
    1463              :     }
    1464       256666 : }
    1465              : 
    1466              : 
    1467              : bool
    1468    145488107 : MSVehicle::congested() const {
    1469    145488107 :     return myState.mySpeed < (60.0 / 3.6) || myLane->getSpeedLimit() < (60.1 / 3.6);
    1470              : }
    1471              : 
    1472              : 
    1473              : double
    1474    547344996 : MSVehicle::computeAngle() const {
    1475              :     Position p1;
    1476    547344996 :     const double posLat = -myState.myPosLat; // @todo get rid of the '-'
    1477    547344996 :     const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
    1478              : 
    1479              :     // if parking manoeuvre is happening then rotate vehicle on each step
    1480    547344996 :     if (MSGlobals::gModelParkingManoeuver && !manoeuvreIsComplete()) {
    1481          450 :         return getAngle() + myManoeuvre.getGUIIncrement();
    1482              :     }
    1483              : 
    1484    547344546 :     if (isParking()) {
    1485        21642 :         if (myStops.begin()->parkingarea != nullptr) {
    1486        12635 :             return myStops.begin()->parkingarea->getVehicleAngle(*this);
    1487              :         } else {
    1488         9007 :             return myLane->getShape().rotationAtOffset(myLane->interpolateLanePosToGeometryPos(getPositionOnLane()));
    1489              :         }
    1490              :     }
    1491    547322904 :     if (myLaneChangeModel->isChangingLanes()) {
    1492              :         // cannot use getPosition() because it already includes the offset to the side and thus messes up the angle
    1493      1098385 :         p1 = myLane->geometryPositionAtOffset(myState.myPos, lefthandSign * posLat);
    1494           12 :         if (p1 == Position::INVALID && myLane->getShape().length2D() == 0. && myLane->isInternal()) {
    1495              :             // workaround: extrapolate the preceding lane shape
    1496           12 :             MSLane* predecessorLane = myLane->getCanonicalPredecessorLane();
    1497           12 :             p1 = predecessorLane->geometryPositionAtOffset(predecessorLane->getLength() + myState.myPos, lefthandSign * posLat);
    1498              :         }
    1499              :     } else {
    1500    546224519 :         p1 = getPosition();
    1501              :     }
    1502              : 
    1503              :     Position p2;
    1504    547322904 :     if (getVehicleType().getParameter().locomotiveLength > 0) {
    1505              :         // articulated vehicle should use the heading of the first part
    1506      1416207 :         const double locoLength = MIN2(getVehicleType().getParameter().locomotiveLength, getLength());
    1507      1416207 :         p2 = getPosition(-locoLength);
    1508              :     } else {
    1509    545906697 :         p2 = getBackPosition();
    1510              :     }
    1511              :     if (p2 == Position::INVALID) {
    1512              :         // Handle special case of vehicle's back reaching out of the network
    1513          739 :         if (myFurtherLanes.size() > 0) {
    1514          123 :             p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
    1515              :             if (p2 == Position::INVALID) {
    1516              :                 // unsuitable lane geometry
    1517           72 :                 p2 = myLane->geometryPositionAtOffset(0, posLat);
    1518              :             }
    1519              :         } else {
    1520          616 :             p2 = myLane->geometryPositionAtOffset(0, posLat);
    1521              :         }
    1522              :     }
    1523              :     double result = (p1 != p2 ? p2.angleTo2D(p1) :
    1524        85897 :                      myLane->getShape().rotationAtOffset(myLane->interpolateLanePosToGeometryPos(getPositionOnLane())));
    1525              : 
    1526    547322904 :     result += lefthandSign * myLaneChangeModel->calcAngleOffset();
    1527              : 
    1528              : #ifdef DEBUG_FURTHER
    1529              :     if (DEBUG_COND) {
    1530              :         std::cout << SIMTIME << " computeAngle veh=" << getID() << " p1=" << p1 << " p2=" << p2 << " angle=" << RAD2DEG(result) << " naviDegree=" << GeomHelper::naviDegree(result) << "\n";
    1531              :     }
    1532              : #endif
    1533              :     return result;
    1534              : }
    1535              : 
    1536              : 
    1537              : const Position
    1538    703272994 : MSVehicle::getBackPosition() const {
    1539    703272994 :     const double posLat = MSGlobals::gLefthand ? myState.myPosLat : -myState.myPosLat;
    1540              :     Position result;
    1541    703272994 :     if (myState.myPos >= myType->getLength()) {
    1542              :         // vehicle is fully on the new lane
    1543    688875991 :         result = myLane->geometryPositionAtOffset(myState.myPos - myType->getLength(), posLat);
    1544              :     } else {
    1545     14397003 :         if (myLaneChangeModel->isChangingLanes() && myFurtherLanes.size() > 0 && myLaneChangeModel->getShadowLane(myFurtherLanes.back()) == nullptr) {
    1546              :             // special case where the target lane has no predecessor
    1547              : #ifdef DEBUG_FURTHER
    1548              :             if (DEBUG_COND) {
    1549              :                 std::cout << "    getBackPosition veh=" << getID() << " specialCase using myLane=" << myLane->getID() << " pos=0 posLat=" << myState.myPosLat << " result=" << myLane->geometryPositionAtOffset(0, posLat) << "\n";
    1550              :             }
    1551              : #endif
    1552         1635 :             result = myLane->geometryPositionAtOffset(0, posLat);
    1553              :         } else {
    1554              : #ifdef DEBUG_FURTHER
    1555              :             if (DEBUG_COND) {
    1556              :                 std::cout << "    getBackPosition veh=" << getID() << " myLane=" << myLane->getID() << " further=" << toString(myFurtherLanes) << " myFurtherLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
    1557              :             }
    1558              : #endif
    1559     14395368 :             if (myFurtherLanes.size() > 0 && !myLaneChangeModel->isChangingLanes()) {
    1560              :                 // truncate to 0 if vehicle starts on an edge that is shorter than its length
    1561     14126227 :                 const double backPos = MAX2(0.0, getBackPositionOnLane(myFurtherLanes.back()));
    1562     27954449 :                 result = myFurtherLanes.back()->geometryPositionAtOffset(backPos, -myFurtherLanesPosLat.back() * (MSGlobals::gLefthand ? -1 : 1));
    1563              :             } else {
    1564       269141 :                 result = myLane->geometryPositionAtOffset(0, posLat);
    1565              :             }
    1566              :         }
    1567              :     }
    1568    703272994 :     if (MSNet::getInstance()->hasElevation() && MSGlobals::gSublane) {
    1569       285032 :         interpolateLateralZ(result, myState.myPos - myType->getLength(), posLat);
    1570              :     }
    1571    703272994 :     return result;
    1572              : }
    1573              : 
    1574              : 
    1575              : bool
    1576       446893 : MSVehicle::willStop() const {
    1577       446893 :     return !isStopped() && !myStops.empty() && myLane != nullptr && &myStops.front().lane->getEdge() == &myLane->getEdge();
    1578              : }
    1579              : 
    1580              : bool
    1581    230487746 : MSVehicle::isStoppedOnLane() const {
    1582    230487746 :     return isStopped() && myStops.front().lane == myLane;
    1583              : }
    1584              : 
    1585              : bool
    1586     28857277 : MSVehicle::keepStopping(bool afterProcessing) const {
    1587     28857277 :     if (isStopped()) {
    1588              :         // when coming out of vehicleTransfer we must shift the time forward
    1589     33998150 :         return (myStops.front().duration - (afterProcessing ? DELTA_T : 0) > 0 || isStoppedTriggered() || myStops.front().pars.collision
    1590     28622355 :                 || myStops.front().pars.breakDown || (myStops.front().getSpeed() > 0
    1591        39439 :                         && (myState.myPos < MIN2(myStops.front().pars.endPos, myStops.front().lane->getLength() - POSITION_EPS))
    1592        33767 :                         && (myStops.front().pars.parking == ParkingType::ONROAD || getSpeed() >= SUMO_const_haltingSpeed)));
    1593              :     } else {
    1594              :         return false;
    1595              :     }
    1596              : }
    1597              : 
    1598              : 
    1599              : SUMOTime
    1600        13316 : MSVehicle::remainingStopDuration() const {
    1601        13316 :     if (isStopped()) {
    1602        13316 :         return myStops.front().duration;
    1603              :     }
    1604              :     return 0;
    1605              : }
    1606              : 
    1607              : 
    1608              : SUMOTime
    1609    523734864 : MSVehicle::collisionStopTime() const {
    1610    523734864 :     return (myStops.empty() || !myStops.front().pars.collision) ? myCollisionImmunity : MAX2((SUMOTime)0, myStops.front().duration);
    1611              : }
    1612              : 
    1613              : 
    1614              : bool
    1615    523600267 : MSVehicle::brokeDown() const {
    1616    523600267 :     return isStopped() && !myStops.empty() && myStops.front().pars.breakDown;
    1617              : }
    1618              : 
    1619              : 
    1620              : bool
    1621       152480 : MSVehicle::ignoreCollision() const {
    1622       152480 :     return myCollisionImmunity > 0;
    1623              : }
    1624              : 
    1625              : 
    1626              : double
    1627    475776470 : MSVehicle::processNextStop(double currentVelocity) {
    1628    475776470 :     if (myStops.empty()) {
    1629              :         // no stops; pass
    1630              :         return currentVelocity;
    1631              :     }
    1632              : 
    1633              : #ifdef DEBUG_STOPS
    1634              :     if (DEBUG_COND) {
    1635              :         std::cout << "\nPROCESS_NEXT_STOP\n" << SIMTIME << " vehicle '" << getID() << "'" << std::endl;
    1636              :     }
    1637              : #endif
    1638              : 
    1639              :     MSStop& stop = myStops.front();
    1640     31804980 :     const SUMOTime time = MSNet::getInstance()->getCurrentTimeStep();
    1641     31804980 :     if (stop.reached) {
    1642     20837318 :         stop.duration -= getActionStepLength();
    1643              : 
    1644              : #ifdef DEBUG_STOPS
    1645              :         if (DEBUG_COND) {
    1646              :             std::cout << SIMTIME << " vehicle '" << getID() << "' reached stop.\n"
    1647              :                       << "Remaining duration: " << STEPS2TIME(stop.duration) << std::endl;
    1648              :             if (stop.getSpeed() > 0) {
    1649              :                 std::cout << " waypointSpeed=" << stop.getSpeed() << " vehPos=" << myState.myPos << " endPos=" << stop.pars.endPos << "\n";
    1650              :             }
    1651              :         }
    1652              : #endif
    1653     20837318 :         if (stop.duration <= 0 && stop.pars.join != "") {
    1654              :             // join this train (part) to another one
    1655        63758 :             MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
    1656          969 :             if (joinVeh && joinVeh->hasDeparted() && (joinVeh->joinTrainPart(this) || joinVeh->joinTrainPartFront(this))) {
    1657           36 :                 stop.joinTriggered = false;
    1658           36 :                 if (myAmRegisteredAsWaiting) {
    1659           21 :                     MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1660           21 :                     myAmRegisteredAsWaiting = false;
    1661              :                 }
    1662              :                 // avoid collision warning before this vehicle is removed (joinVeh was already made longer)
    1663           36 :                 myCollisionImmunity = TIME2STEPS(100);
    1664              :                 // mark this vehicle as arrived
    1665           36 :                 myArrivalPos = getPositionOnLane();
    1666           36 :                 const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = getRoutePosition();
    1667              :                 // handle transportables that want to continue in the other vehicle
    1668           36 :                 if (myPersonDevice != nullptr) {
    1669            3 :                     myPersonDevice->transferAtSplitOrJoin(joinVeh);
    1670              :                 }
    1671           36 :                 if (myContainerDevice != nullptr) {
    1672            3 :                     myContainerDevice->transferAtSplitOrJoin(joinVeh);
    1673              :                 }
    1674              :             }
    1675              :         }
    1676     20837318 :         boardTransportables(stop);
    1677     20837318 :         if (!keepStopping() && isOnRoad()) {
    1678              : #ifdef DEBUG_STOPS
    1679              :             if (DEBUG_COND) {
    1680              :                 std::cout << SIMTIME << " vehicle '" << getID() << "' resumes from stopping." << std::endl;
    1681              :             }
    1682              : #endif
    1683        43362 :             resumeFromStopping();
    1684        43362 :             if (isRailway(getVClass())
    1685        43362 :                     && hasStops()) {
    1686              :                 // stay on the current lane in case of a double stop
    1687         2090 :                 const MSStop& nextStop = getNextStop();
    1688         2090 :                 if (nextStop.edge == myCurrEdge) {
    1689          847 :                     const double stopSpeed = getCarFollowModel().stopSpeed(this, getSpeed(), nextStop.pars.endPos - myState.myPos);
    1690              :                     //std::cout << SIMTIME << " veh=" << getID() << " resumedFromStopping currentVelocity=" << currentVelocity << " stopSpeed=" << stopSpeed << "\n";
    1691          847 :                     return stopSpeed;
    1692              :                 }
    1693              :             }
    1694              :         } else {
    1695     20793956 :             if (stop.triggered) {
    1696      2618704 :                 if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
    1697           30 :                     WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
    1698           10 :                     stop.triggered = false;
    1699      2618694 :                 } else if (!myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
    1700              :                     // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
    1701         3016 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
    1702         3016 :                     myAmRegisteredAsWaiting = true;
    1703              : #ifdef DEBUG_STOPS
    1704              :                     if (DEBUG_COND) {
    1705              :                         std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for person." << std::endl;
    1706              :                     }
    1707              : #endif
    1708              :                 }
    1709              :             }
    1710     20793956 :             if (stop.containerTriggered) {
    1711        39454 :                 if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
    1712         1194 :                     WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
    1713          398 :                     stop.containerTriggered = false;
    1714        39056 :                 } else if (stop.containerTriggered && !myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
    1715              :                     // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
    1716           92 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
    1717           92 :                     myAmRegisteredAsWaiting = true;
    1718              : #ifdef DEBUG_STOPS
    1719              :                     if (DEBUG_COND) {
    1720              :                         std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for container." << std::endl;
    1721              :                     }
    1722              : #endif
    1723              :                 }
    1724              :             }
    1725              :             // joining only takes place after stop duration is over
    1726     20793956 :             if (stop.joinTriggered && !myAmRegisteredAsWaiting
    1727         6603 :                     && stop.duration <= (stop.pars.extension >= 0 ? -stop.pars.extension : 0)) {
    1728           93 :                 if (stop.pars.extension >= 0) {
    1729           84 :                     WRITE_WARNINGF(TL("Vehicle '%' aborts joining after extension of %s at time %."), getID(), STEPS2TIME(stop.pars.extension), time2string(SIMSTEP));
    1730           28 :                     stop.joinTriggered = false;
    1731              :                 } else {
    1732              :                     // keep stopping indefinitely but ensure that simulation terminates
    1733           65 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
    1734           65 :                     myAmRegisteredAsWaiting = true;
    1735              :                 }
    1736              :             }
    1737     20793956 :             if (stop.getSpeed() > 0) {
    1738              :                 //waypoint mode
    1739       244079 :                 if (stop.duration == 0) {
    1740          174 :                     return stop.getSpeed();
    1741              :                 } else {
    1742              :                     // stop for 'until' (computed in planMove)
    1743              :                     return currentVelocity;
    1744              :                 }
    1745              :             } else {
    1746              :                 // brake
    1747     20549877 :                 if (MSGlobals::gSemiImplicitEulerUpdate || stop.getSpeed() > 0) {
    1748     20301178 :                     return 0;
    1749              :                 } else {
    1750              :                     // ballistic:
    1751       248699 :                     return getSpeed() - getCarFollowModel().getMaxDecel();
    1752              :                 }
    1753              :             }
    1754              :         }
    1755              :     } else {
    1756              : 
    1757              : #ifdef DEBUG_STOPS
    1758              :         if (DEBUG_COND) {
    1759              :             std::cout << SIMTIME << " vehicle '" << getID() << "' hasn't reached next stop." << std::endl;
    1760              :         }
    1761              : #endif
    1762              :         //std::cout << SIMTIME <<  " myStopDist=" << myStopDist << " bGap=" << getBrakeGap(myLane->getVehicleMaxSpeed(this)) << "\n";
    1763     11023420 :         if (stop.pars.onDemand && !stop.skipOnDemand && myStopDist <= getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this))) {
    1764          562 :             MSNet* const net = MSNet::getInstance();
    1765           44 :             const bool noExits = ((myPersonDevice == nullptr || !myPersonDevice->anyLeavingAtStop(stop))
    1766          572 :                                   && (myContainerDevice == nullptr || !myContainerDevice->anyLeavingAtStop(stop)));
    1767           83 :             const bool noEntries = ((!net->hasPersons() || !net->getPersonControl().hasAnyWaiting(stop.getEdge(), this))
    1768          611 :                                     && (!net->hasContainers() || !net->getContainerControl().hasAnyWaiting(stop.getEdge(), this)));
    1769          562 :             if (noExits && noEntries) {
    1770              :                 //std::cout << " skipOnDemand\n";
    1771          494 :                 stop.skipOnDemand = true;
    1772              :             }
    1773              :         }
    1774              :         // is the next stop on the current lane?
    1775     10967662 :         if (stop.edge == myCurrEdge) {
    1776              :             // get the stopping position
    1777      3719011 :             bool useStoppingPlace = stop.busstop != nullptr || stop.containerstop != nullptr || stop.parkingarea != nullptr;
    1778              :             bool fitsOnStoppingPlace = true;
    1779      3719011 :             if (!stop.skipOnDemand) {  // no need to check available space if we skip it anyway
    1780      3717083 :                 if (stop.busstop != nullptr) {
    1781       478050 :                     fitsOnStoppingPlace &= stop.busstop->fits(myState.myPos, *this);
    1782              :                 }
    1783      3717083 :                 if (stop.containerstop != nullptr) {
    1784        16921 :                     fitsOnStoppingPlace &= stop.containerstop->fits(myState.myPos, *this);
    1785              :                 }
    1786              :                 // if the stop is a parking area we check if there is a free position on the area
    1787      3717083 :                 if (stop.parkingarea != nullptr) {
    1788       187794 :                     fitsOnStoppingPlace &= myState.myPos > stop.parkingarea->getBeginLanePosition();
    1789       187794 :                     if (stop.parkingarea->getOccupancy() >= stop.parkingarea->getCapacity()) {
    1790              :                         fitsOnStoppingPlace = false;
    1791              :                         // trigger potential parkingZoneReroute
    1792        48316 :                         MSParkingArea* oldParkingArea = stop.parkingarea;
    1793        51352 :                         for (MSMoveReminder* rem : myLane->getMoveReminders()) {
    1794         3036 :                             if (rem->isParkingRerouter()) {
    1795         2916 :                                 rem->notifyEnter(*this, MSMoveReminder::NOTIFICATION_PARKING_REROUTE, myLane);
    1796              :                             }
    1797              :                         }
    1798        48316 :                         if (myStops.empty() || myStops.front().parkingarea != oldParkingArea) {
    1799              :                             // rerouted, keep driving
    1800              :                             return currentVelocity;
    1801              :                         }
    1802       139478 :                     } else if (stop.parkingarea->getOccupancyIncludingBlocked() >= stop.parkingarea->getCapacity()) {
    1803              :                         fitsOnStoppingPlace = false;
    1804       119566 :                     } else if (stop.parkingarea->parkOnRoad() && stop.parkingarea->getLotIndex(this) < 0) {
    1805              :                         fitsOnStoppingPlace = false;
    1806              :                     }
    1807              :                 }
    1808              :             }
    1809      3718093 :             const double targetPos = myState.myPos + myStopDist + (stop.getSpeed() > 0 ? (stop.pars.startPos - stop.pars.endPos) : 0);
    1810      3718093 :             const double reachedThreshold = (useStoppingPlace ? targetPos - STOPPING_PLACE_OFFSET : stop.getReachedThreshold()) - NUMERICAL_EPS;
    1811              : #ifdef DEBUG_STOPS
    1812              :             if (DEBUG_COND) {
    1813              :                 std::cout <<  "   pos=" << myState.pos() << " speed=" << currentVelocity << " targetPos=" << targetPos << " fits=" << fitsOnStoppingPlace
    1814              :                           << " reachedThresh=" << reachedThreshold
    1815              :                           << " myLane=" << Named::getIDSecure(myLane)
    1816              :                           << " stopLane=" << Named::getIDSecure(stop.lane)
    1817              :                           << "\n";
    1818              :             }
    1819              : #endif
    1820       563208 :             if (myState.pos() >= reachedThreshold && fitsOnStoppingPlace && currentVelocity <= stop.getSpeed() + SUMO_const_haltingSpeed && myLane == stop.lane
    1821      3772090 :                     && (!MSGlobals::gModelParkingManoeuver || myManoeuvre.entryManoeuvreIsComplete(this))) {
    1822              :                 // ok, we may stop (have reached the stop)  and either we are not modelling maneuvering or have completed entry
    1823        53807 :                 stop.reached = true;
    1824        53807 :                 if (!stop.startedFromState) {
    1825        53611 :                     stop.pars.started = time;
    1826              :                 }
    1827              : #ifdef DEBUG_STOPS
    1828              :                 if (DEBUG_COND) {
    1829              :                     std::cout << SIMTIME << " vehicle '" << getID() << "' reached next stop." << std::endl;
    1830              :                 }
    1831              : #endif
    1832        53807 :                 if (MSStopOut::active()) {
    1833         4138 :                     MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), time);
    1834              :                 }
    1835        53807 :                 myLane->getEdge().addWaiting(this);
    1836        53807 :                 MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::STARTING_STOP);
    1837        53807 :                 MSNet::getInstance()->getVehicleControl().registerStopStarted();
    1838              :                 // compute stopping time
    1839        53807 :                 stop.duration = stop.getMinDuration(time);
    1840        53807 :                 stop.endBoarding = stop.pars.extension >= 0 ? time + stop.duration + stop.pars.extension : SUMOTime_MAX;
    1841        53807 :                 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
    1842         2316 :                 if (taxiDevice != nullptr && stop.pars.extension >= 0) {
    1843              :                     // earliestPickupTime is set with waitUntil
    1844           84 :                     stop.endBoarding = MAX2(time, stop.pars.waitUntil) + stop.pars.extension;
    1845              :                 }
    1846        53807 :                 if (stop.getSpeed() > 0) {
    1847              :                     // ignore duration parameter in waypoint mode unless 'until' or 'ended' are set
    1848         3182 :                     if (stop.getUntil() > time) {
    1849          234 :                         stop.duration = stop.getUntil() - time;
    1850              :                     } else {
    1851         2948 :                         stop.duration = 0;
    1852              :                     }
    1853              :                 }
    1854        53807 :                 if (stop.busstop != nullptr) {
    1855              :                     // let the bus stop know the vehicle
    1856        15427 :                     stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    1857              :                 }
    1858        53807 :                 if (stop.containerstop != nullptr) {
    1859              :                     // let the container stop know the vehicle
    1860          360 :                     stop.containerstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    1861              :                 }
    1862        53807 :                 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
    1863              :                     // let the parking area know the vehicle
    1864         7362 :                     stop.parkingarea->enter(this);
    1865              :                 }
    1866        53807 :                 if (stop.chargingStation != nullptr) {
    1867              :                     // let the container stop know the vehicle
    1868         3239 :                     stop.chargingStation->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    1869              :                 }
    1870              : 
    1871        53807 :                 if (stop.pars.tripId != "") {
    1872         2520 :                     ((SUMOVehicleParameter&)getParameter()).setParameter("tripId", stop.pars.tripId);
    1873              :                 }
    1874        53807 :                 if (stop.pars.line != "") {
    1875         1278 :                     ((SUMOVehicleParameter&)getParameter()).line = stop.pars.line;
    1876              :                 }
    1877        53807 :                 if (stop.pars.split != "") {
    1878              :                     // split the train
    1879          655 :                     MSVehicle* splitVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.split));
    1880           24 :                     if (splitVeh == nullptr) {
    1881         1893 :                         WRITE_WARNINGF(TL("Vehicle '%' to split from vehicle '%' is not known. time=%."), stop.pars.split, getID(), SIMTIME)
    1882              :                     } else {
    1883           24 :                         MSNet::getInstance()->getInsertionControl().add(splitVeh);
    1884           24 :                         splitVeh->getRoute().getEdges()[0]->removeWaiting(splitVeh);
    1885           24 :                         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1886           24 :                         const double newLength = MAX2(myType->getLength() - splitVeh->getVehicleType().getLength(),
    1887           24 :                                                       myType->getParameter().locomotiveLength);
    1888           24 :                         getSingularType().setLength(newLength);
    1889              :                         // handle transportables that want to continue in the split part
    1890           24 :                         if (myPersonDevice != nullptr) {
    1891            0 :                             myPersonDevice->transferAtSplitOrJoin(splitVeh);
    1892              :                         }
    1893           24 :                         if (myContainerDevice != nullptr) {
    1894            6 :                             myContainerDevice->transferAtSplitOrJoin(splitVeh);
    1895              :                         }
    1896           24 :                         if (splitVeh->getParameter().departPosProcedure == DepartPosDefinition::SPLIT_FRONT) {
    1897            3 :                             const double backShift = splitVeh->getLength() + getVehicleType().getMinGap();
    1898            3 :                             myState.myPos -= backShift;
    1899            3 :                             myState.myBackPos -= backShift;
    1900              :                         }
    1901              :                     }
    1902              :                 }
    1903              : 
    1904        53807 :                 boardTransportables(stop);
    1905        53807 :                 if (stop.pars.posLat != INVALID_DOUBLE) {
    1906          218 :                     myState.myPosLat = stop.pars.posLat;
    1907              :                 }
    1908              :             }
    1909              :         }
    1910              :     }
    1911              :     return currentVelocity;
    1912              : }
    1913              : 
    1914              : 
    1915              : void
    1916     20891125 : MSVehicle::boardTransportables(MSStop& stop) {
    1917     20891125 :     if (stop.skipOnDemand) {
    1918              :         return;
    1919              :     }
    1920              :     // we have reached the stop
    1921              :     // any waiting persons may board now
    1922     20664074 :     const SUMOTime time = MSNet::getInstance()->getCurrentTimeStep();
    1923     20664074 :     MSNet* const net = MSNet::getInstance();
    1924     20664074 :     const bool boarded = (time <= stop.endBoarding
    1925     20661929 :                           && net->hasPersons()
    1926       751550 :                           && net->getPersonControl().loadAnyWaiting(&myLane->getEdge(), this, stop.timeToBoardNextPerson, stop.duration)
    1927     20668505 :                           && stop.numExpectedPerson == 0);
    1928              :     // load containers
    1929     20664074 :     const bool loaded = (time <= stop.endBoarding
    1930     20661929 :                          && net->hasContainers()
    1931       100978 :                          && net->getContainerControl().loadAnyWaiting(&myLane->getEdge(), this, stop.timeToLoadNextContainer, stop.duration)
    1932     20664521 :                          && stop.numExpectedContainer == 0);
    1933              : 
    1934              :     bool unregister = false;
    1935     20664074 :     if (time > stop.endBoarding) {
    1936              :         // for taxi: cancel customers
    1937         2145 :         MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
    1938              :         if (taxiDevice != nullptr) {
    1939          104 :             taxiDevice->cancelCurrentCustomers();
    1940              :         }
    1941              : 
    1942         2145 :         stop.triggered = false;
    1943         2145 :         stop.containerTriggered = false;
    1944         2145 :         if (myAmRegisteredAsWaiting) {
    1945              :             unregister = true;
    1946          304 :             myAmRegisteredAsWaiting = false;
    1947              :         }
    1948              :     }
    1949     20664074 :     if (boarded) {
    1950              :         // the triggering condition has been fulfilled. Maybe we want to wait a bit longer for additional riders (car pooling)
    1951         4303 :         if (myAmRegisteredAsWaiting) {
    1952              :             unregister = true;
    1953              :         }
    1954         4303 :         stop.triggered = false;
    1955         4303 :         myAmRegisteredAsWaiting = false;
    1956              :     }
    1957     20664074 :     if (loaded) {
    1958              :         // the triggering condition has been fulfilled
    1959          427 :         if (myAmRegisteredAsWaiting) {
    1960              :             unregister = true;
    1961              :         }
    1962          427 :         stop.containerTriggered = false;
    1963          427 :         myAmRegisteredAsWaiting = false;
    1964              :     }
    1965              : 
    1966     20664074 :     if (unregister) {
    1967          388 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1968              : #ifdef DEBUG_STOPS
    1969              :         if (DEBUG_COND) {
    1970              :             std::cout << SIMTIME << " vehicle '" << getID() << "' unregisters as waiting for transportable." << std::endl;
    1971              :         }
    1972              : #endif
    1973              :     }
    1974              : }
    1975              : 
    1976              : bool
    1977          921 : MSVehicle::joinTrainPart(MSVehicle* veh) {
    1978              :     // check if veh is close enough to be joined to the rear of this vehicle
    1979          921 :     MSLane* backLane = myFurtherLanes.size() == 0 ? myLane : myFurtherLanes.back();
    1980          921 :     double gap = getBackPositionOnLane() - veh->getPositionOnLane();
    1981         1143 :     if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == veh->getLane()
    1982          951 :             && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
    1983           15 :         const double newLength = myType->getLength() + veh->getVehicleType().getLength();
    1984           15 :         getSingularType().setLength(newLength);
    1985           15 :         myStops.begin()->joinTriggered = false;
    1986           15 :         if (myAmRegisteredAsWaiting) {
    1987            0 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1988            0 :             myAmRegisteredAsWaiting = false;
    1989              :         }
    1990              :         return true;
    1991              :     } else {
    1992          906 :         return false;
    1993              :     }
    1994              : }
    1995              : 
    1996              : 
    1997              : bool
    1998          906 : MSVehicle::joinTrainPartFront(MSVehicle* veh) {
    1999              :     // check if veh is close enough to be joined to the front of this vehicle
    2000          906 :     MSLane* backLane = veh->myFurtherLanes.size() == 0 ? veh->myLane : veh->myFurtherLanes.back();
    2001          906 :     double gap = veh->getBackPositionOnLane(backLane) - getPositionOnLane();
    2002         1113 :     if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == getLane()
    2003          930 :             && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
    2004              :         double skippedLaneLengths = 0;
    2005           24 :         if (veh->myFurtherLanes.size() > 0) {
    2006            9 :             skippedLaneLengths += getLane()->getLength();
    2007              :             // this vehicle must be moved to the lane of veh
    2008              :             // ensure that lane and furtherLanes of veh match our route
    2009            9 :             int routeIndex = getRoutePosition();
    2010            9 :             if (myLane->isInternal()) {
    2011            0 :                 routeIndex++;
    2012              :             }
    2013           27 :             for (int i = (int)veh->myFurtherLanes.size() - 1; i >= 0; i--) {
    2014           18 :                 MSEdge* edge = &veh->myFurtherLanes[i]->getEdge();
    2015           18 :                 if (edge->isInternal()) {
    2016            9 :                     continue;
    2017              :                 }
    2018            9 :                 if (!edge->isInternal() && edge != myRoute->getEdges()[routeIndex]) {
    2019            0 :                     std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
    2020            0 :                     WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
    2021              :                     return false;
    2022              :                 }
    2023            9 :                 routeIndex++;
    2024              :             }
    2025            9 :             if (veh->getCurrentEdge()->getNormalSuccessor() != myRoute->getEdges()[routeIndex]) {
    2026            3 :                 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
    2027            9 :                 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
    2028              :                 return false;
    2029              :             }
    2030           12 :             for (int i = (int)veh->myFurtherLanes.size() - 2; i >= 0; i--) {
    2031            6 :                 skippedLaneLengths += veh->myFurtherLanes[i]->getLength();
    2032              :             }
    2033              :         }
    2034              : 
    2035           21 :         const double newLength = myType->getLength() + veh->getVehicleType().getLength();
    2036           21 :         getSingularType().setLength(newLength);
    2037              :         // lane will be advanced just as for regular movement
    2038           21 :         myState.myPos = skippedLaneLengths + veh->getPositionOnLane();
    2039           21 :         myStops.begin()->joinTriggered = false;
    2040           21 :         if (myAmRegisteredAsWaiting) {
    2041            8 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    2042            8 :             myAmRegisteredAsWaiting = false;
    2043              :         }
    2044           21 :         return true;
    2045              :     } else {
    2046          882 :         return false;
    2047              :     }
    2048              : }
    2049              : 
    2050              : double
    2051      5612385 : MSVehicle::getBrakeGap(bool delayed) const {
    2052      5612385 :     return getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), delayed ? getCarFollowModel().getHeadwayTime() : 0);
    2053              : }
    2054              : 
    2055              : 
    2056              : bool
    2057   1080946624 : MSVehicle::checkActionStep(const SUMOTime t) {
    2058   1080946624 :     myActionStep = isActionStep(t);
    2059   1080946624 :     if (myActionStep) {
    2060    936503366 :         myLastActionTime = t;
    2061              :     }
    2062   1080946624 :     return myActionStep;
    2063              : }
    2064              : 
    2065              : 
    2066              : void
    2067         1427 : MSVehicle::resetActionOffset(const SUMOTime timeUntilNextAction) {
    2068         1427 :     myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + timeUntilNextAction;
    2069         1427 : }
    2070              : 
    2071              : 
    2072              : void
    2073            1 : MSVehicle::updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength) {
    2074            1 :     SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
    2075            1 :     SUMOTime timeSinceLastAction = now - myLastActionTime;
    2076            1 :     if (timeSinceLastAction == 0) {
    2077              :         // Action was scheduled now, may be delayed be new action step length
    2078              :         timeSinceLastAction = oldActionStepLength;
    2079              :     }
    2080            1 :     if (timeSinceLastAction >= newActionStepLength) {
    2081              :         // Action point required in this step
    2082            0 :         myLastActionTime = now;
    2083              :     } else {
    2084            1 :         SUMOTime timeUntilNextAction = newActionStepLength - timeSinceLastAction;
    2085            1 :         resetActionOffset(timeUntilNextAction);
    2086              :     }
    2087            1 : }
    2088              : 
    2089              : 
    2090              : 
    2091              : void
    2092    540473312 : MSVehicle::planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront) {
    2093              : #ifdef DEBUG_PLAN_MOVE
    2094              :     if (DEBUG_COND) {
    2095              :         std::cout
    2096              :                 << "\nPLAN_MOVE\n"
    2097              :                 << SIMTIME
    2098              :                 << std::setprecision(gPrecision)
    2099              :                 << " veh=" << getID()
    2100              :                 << " lane=" << myLane->getID()
    2101              :                 << " pos=" << getPositionOnLane()
    2102              :                 << " posLat=" << getLateralPositionOnLane()
    2103              :                 << " speed=" << getSpeed()
    2104              :                 << "\n";
    2105              :     }
    2106              : #endif
    2107              :     // Update the driver state
    2108    540473312 :     if (hasDriverState()) {
    2109       256652 :         myDriverState->update();
    2110       513304 :         setActionStepLength(myDriverState->getDriverState()->getActionStepLength(), false);
    2111              :     }
    2112              : 
    2113    540473312 :     if (!checkActionStep(t)) {
    2114              : #ifdef DEBUG_ACTIONSTEPS
    2115              :         if (DEBUG_COND) {
    2116              :             std::cout << STEPS2TIME(t) << " vehicle '" << getID() << "' skips action." << std::endl;
    2117              :         }
    2118              : #endif
    2119              :         // During non-action passed drive items still need to be removed
    2120              :         // @todo rather work with updating myCurrentDriveItem (refs #3714)
    2121     72221629 :         removePassedDriveItems();
    2122     72221629 :         return;
    2123              :     } else {
    2124              : #ifdef DEBUG_ACTIONSTEPS
    2125              :         if (DEBUG_COND) {
    2126              :             std::cout << STEPS2TIME(t) << " vehicle = '" << getID() << "' takes action." << std::endl;
    2127              :         }
    2128              : #endif
    2129    468251683 :         myLFLinkLanesPrev = myLFLinkLanes;
    2130    468251683 :         if (myInfluencer != nullptr) {
    2131       460523 :             myInfluencer->updateRemoteControlRoute(this);
    2132              :         }
    2133    468251683 :         planMoveInternal(t, ahead, myLFLinkLanes, myStopDist, myNextTurn);
    2134              : #ifdef DEBUG_PLAN_MOVE
    2135              :         if (DEBUG_COND) {
    2136              :             DriveItemVector::iterator i;
    2137              :             for (i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
    2138              :                 std::cout
    2139              :                         << " vPass=" << (*i).myVLinkPass
    2140              :                         << " vWait=" << (*i).myVLinkWait
    2141              :                         << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
    2142              :                         << " request=" << (*i).mySetRequest
    2143              :                         << "\n";
    2144              :             }
    2145              :         }
    2146              : #endif
    2147    468251683 :         checkRewindLinkLanes(lengthsInFront, myLFLinkLanes);
    2148    468251683 :         myNextDriveItem = myLFLinkLanes.begin();
    2149              :         // ideally would only do this with the call inside planMoveInternal - but that needs a const method
    2150              :         //   so this is a kludge here - nuisance as it adds an extra check in a busy loop
    2151    468251683 :         if (MSGlobals::gModelParkingManoeuver) {
    2152         2971 :             if (getManoeuvreType() == MSVehicle::MANOEUVRE_EXIT && manoeuvreIsComplete()) {
    2153           30 :                 setManoeuvreType(MSVehicle::MANOEUVRE_NONE);
    2154              :             }
    2155              :         }
    2156              :     }
    2157    468251683 :     myLaneChangeModel->resetChanged();
    2158              : }
    2159              : 
    2160              : 
    2161              : bool
    2162    157310261 : MSVehicle::brakeForOverlap(const MSLink* link, const MSLane* lane) const {
    2163              :     // @review needed
    2164              :     //const double futurePosLat = getLateralPositionOnLane() + link->getLateralShift();
    2165              :     //const double overlap = getLateralOverlap(futurePosLat, link->getViaLaneOrLane());
    2166              :     //const double edgeWidth = link->getViaLaneOrLane()->getEdge().getWidth();
    2167    157310261 :     const double futurePosLat = getLateralPositionOnLane() + (
    2168    157310261 :                                     lane != myLane && lane->isInternal() ? lane->getIncomingLanes()[0].viaLink->getLateralShift() : 0);
    2169    157310261 :     const double overlap = getLateralOverlap(futurePosLat, lane);
    2170              :     const double edgeWidth = lane->getEdge().getWidth();
    2171              :     const bool result = (overlap > POSITION_EPS
    2172              :                          // do not get stuck on narrow edges
    2173      2718438 :                          && getVehicleType().getWidth() <= edgeWidth
    2174      2714153 :                          && link->getViaLane() == nullptr
    2175              :                          // this is the exit link of a junction. The normal edge should support the shadow
    2176      1342461 :                          && ((myLaneChangeModel->getShadowLane(link->getLane()) == nullptr)
    2177              :                              // the internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
    2178       987685 :                              || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
    2179              :                          // ignore situations where the shadow lane is part of a double-connection with the current lane
    2180    157686606 :                          && (myLaneChangeModel->getShadowLane() == nullptr
    2181       221980 :                              || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
    2182       206954 :                              || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != link->getLane()));
    2183              : 
    2184              : #ifdef DEBUG_PLAN_MOVE
    2185              :     if (DEBUG_COND) {
    2186              :         std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getDescription() << " lane=" << lane->getID()
    2187              :                   << " shift=" << link->getLateralShift()
    2188              :                   << " fpLat=" << futurePosLat << " overlap=" << overlap << " w=" << getVehicleType().getWidth() << " result=" << result << "\n";
    2189              :     }
    2190              : #endif
    2191    157310261 :     return result;
    2192              : }
    2193              : 
    2194              : 
    2195              : 
    2196              : void
    2197    468251683 : MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, std::pair<double, const MSLink*>& nextTurn) const {
    2198              :     lfLinks.clear();
    2199    468251683 :     newStopDist = std::numeric_limits<double>::max();
    2200              :     //
    2201              :     const MSCFModel& cfModel = getCarFollowModel();
    2202    468251683 :     const double vehicleLength = getVehicleType().getLength();
    2203    468251683 :     const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
    2204    468251683 :     const bool opposite = myLaneChangeModel->isOpposite();
    2205    468251683 :     double laneMaxV = myLane->getVehicleMaxSpeed(this);
    2206    468251683 :     const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
    2207              :     double lateralShift = 0;
    2208    468251683 :     if (isRailway((SVCPermissions)getVehicleType().getVehicleClass())) {
    2209              :         // speed limits must hold for the whole length of the train
    2210      1204388 :         for (MSLane* l : myFurtherLanes) {
    2211       289490 :             laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this));
    2212              : #ifdef DEBUG_PLAN_MOVE
    2213              :             if (DEBUG_COND) {
    2214              :                 std::cout << "   laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
    2215              :             }
    2216              : #endif
    2217              :         }
    2218              :     }
    2219              :     //  speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
    2220              :     laneMaxV = MAX2(laneMaxV, vMinComfortable);
    2221    468251683 :     if (myInfluencer && !myInfluencer->considerSafeVelocity()) {
    2222              :         laneMaxV = std::numeric_limits<double>::max();
    2223              :     }
    2224              :     // v is the initial maximum velocity of this vehicle in this step
    2225    468251683 :     double v = cfModel.maximumLaneSpeedCF(this, maxV, laneMaxV);
    2226              :     // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
    2227              :     //   in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
    2228    468251683 :     if (MSGlobals::gModelParkingManoeuver && !manoeuvreIsComplete()) {
    2229          420 :         v = NUMERICAL_EPS_SPEED;
    2230              :     }
    2231              : 
    2232    468251683 :     if (myInfluencer != nullptr) {
    2233       460523 :         const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
    2234              : #ifdef DEBUG_TRACI
    2235              :         if (DEBUG_COND) {
    2236              :             std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
    2237              :         }
    2238              : #endif
    2239       460523 :         v = myInfluencer->influenceSpeed(t, v, v, vMin, maxV);
    2240              : #ifdef DEBUG_TRACI
    2241              :         if (DEBUG_COND) {
    2242              :             std::cout << " influencedSpeed=" << v;
    2243              :         }
    2244              : #endif
    2245       460523 :         v = myInfluencer->gapControlSpeed(t, this, v, v, vMin, maxV);
    2246              : #ifdef DEBUG_TRACI
    2247              :         if (DEBUG_COND) {
    2248              :             std::cout << " gapControlSpeed=" << v << "\n";
    2249              :         }
    2250              : #endif
    2251              :     }
    2252              :     // all links within dist are taken into account (potentially)
    2253    468251683 :     const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
    2254              : 
    2255    468251683 :     const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
    2256              : #ifdef DEBUG_PLAN_MOVE
    2257              :     if (DEBUG_COND) {
    2258              :         std::cout << "   dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
    2259              :                   << "\n   maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
    2260              :     }
    2261              : #endif
    2262              :     assert(bestLaneConts.size() > 0);
    2263              :     bool hadNonInternal = false;
    2264              :     // the distance already "seen"; in the following always up to the end of the current "lane"
    2265    468251683 :     double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
    2266    468251683 :     nextTurn.first = seen;
    2267    468251683 :     nextTurn.second = nullptr;
    2268    468251683 :     bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
    2269              :     double seenNonInternal = 0;
    2270    468251683 :     double seenInternal = myLane->isInternal() ? seen : 0;
    2271    468251683 :     double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
    2272              :     int view = 0;
    2273              :     DriveProcessItem* lastLink = nullptr;
    2274              :     bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
    2275              :     double mustSeeBeforeReversal = 0;
    2276              :     // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
    2277    468251683 :     const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
    2278              :     assert(lane != 0);
    2279    468251683 :     const MSLane* leaderLane = myLane;
    2280    468251683 :     bool foundRailSignal = !isRailway(getVClass());
    2281              :     bool planningToStop = false;
    2282              : #ifdef PARALLEL_STOPWATCH
    2283              :     myLane->getStopWatch()[0].start();
    2284              : #endif
    2285              : 
    2286              :     // optionally slow down to match arrival time
    2287    468251683 :     const double sfp = getVehicleType().getParameter().speedFactorPremature;
    2288    468241076 :     if (v > vMinComfortable && hasStops() && myStops.front().pars.arrival >= 0 && sfp > 0
    2289         4279 :             && v > myLane->getSpeedLimit() * sfp
    2290    468254719 :             && !myStops.front().reached) {
    2291         2786 :         const double vSlowDown = slowDownForSchedule(vMinComfortable);
    2292         5403 :         v = MIN2(v, vSlowDown);
    2293              :     }
    2294              :     auto stopIt = myStops.begin();
    2295              :     while (true) {
    2296              :         // check leader on lane
    2297              :         //  leader is given for the first edge only
    2298    981215272 :         if (opposite &&
    2299              :                 (leaderLane->getVehicleNumberWithPartials() > 1
    2300       100846 :                  || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
    2301       401697 :             ahead.clear();
    2302              :             // find opposite-driving leader that must be respected on the currently looked at lane
    2303              :             // (only looking at one lane at a time)
    2304       401697 :             const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
    2305       401697 :             const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
    2306       401697 :             const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
    2307       401697 :             MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
    2308       401697 :             const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 *  myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
    2309      1072313 :             for (int i = 0; i < cands.numSublanes(); i++) {
    2310       670616 :                 CLeaderDist cand = cands[i];
    2311       670616 :                 if (cand.first != 0) {
    2312       569491 :                     if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
    2313       569962 :                             || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
    2314              :                         // respect leaders that also drive in the opposite direction (fully or with some overlap)
    2315       359545 :                         oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
    2316              :                     } else {
    2317              :                         // avoid frontal collision
    2318       385987 :                         const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
    2319       209946 :                         const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
    2320       209946 :                         if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
    2321        47670 :                             oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
    2322              :                         }
    2323              :                     }
    2324              :                 }
    2325              :             }
    2326              : #ifdef DEBUG_PLAN_MOVE
    2327              :             if (DEBUG_COND) {
    2328              :                 std::cout <<  " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
    2329              :                           << " cands=" << cands.toString() << " oppositeLeaders=" <<  oppositeLeaders.toString() << "\n";
    2330              :             }
    2331              : #endif
    2332       401697 :             adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
    2333       401697 :         } else {
    2334    980813575 :             if (MSGlobals::gLateralResolution > 0 && myLaneChangeModel->getShadowLane() == nullptr) {
    2335    176496956 :                 const double rightOL = getRightSideOnLane(lane) + lateralShift;
    2336    176496956 :                 const double leftOL = getLeftSideOnLane(lane) + lateralShift;
    2337              :                 const bool outsideLeft = leftOL > lane->getWidth();
    2338              : #ifdef DEBUG_PLAN_MOVE
    2339              :                 if (DEBUG_COND) {
    2340              :                     std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
    2341              :                 }
    2342              : #endif
    2343    176496956 :                 if (rightOL < 0 || outsideLeft) {
    2344      1158926 :                     MSLeaderInfo outsideLeaders(lane->getWidth());
    2345              :                     // if ego is driving outside lane bounds we must consider
    2346              :                     // potential leaders that are also outside bounds
    2347              :                     int sublaneOffset = 0;
    2348      1158926 :                     if (outsideLeft) {
    2349       515974 :                         sublaneOffset = MIN2(-1, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution));
    2350              :                     } else {
    2351       642952 :                         sublaneOffset = MAX2(1, (int)ceil(-rightOL / MSGlobals::gLateralResolution));
    2352              :                     }
    2353      1158926 :                     outsideLeaders.setSublaneOffset(sublaneOffset);
    2354              : #ifdef DEBUG_PLAN_MOVE
    2355              :                     if (DEBUG_COND) {
    2356              :                         std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
    2357              :                     }
    2358              : #endif
    2359      5332453 :                     for (const MSVehicle* cand : lane->getVehiclesSecure()) {
    2360      1808628 :                         if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
    2361      4944049 :                                 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
    2362      3135193 :                                     || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
    2363       220979 :                             outsideLeaders.addLeader(cand, true);
    2364              : #ifdef DEBUG_PLAN_MOVE
    2365              :                             if (DEBUG_COND) {
    2366              :                                 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << outsideLeaders.toString() << "\n";
    2367              :                             }
    2368              : #endif
    2369              :                         }
    2370              :                     }
    2371      1158926 :                     lane->releaseVehicles();
    2372      1158926 :                     if (outsideLeaders.hasVehicles()) {
    2373        36627 :                         adaptToLeaders(outsideLeaders, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
    2374              :                     }
    2375      1158926 :                 }
    2376              :             }
    2377    980813575 :             adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
    2378              :         }
    2379    981215272 :         if (lastLink != nullptr) {
    2380    961994569 :             lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
    2381              :         }
    2382              : #ifdef DEBUG_PLAN_MOVE
    2383              :         if (DEBUG_COND) {
    2384              :             std::cout << "\nv = " << v << "\n";
    2385              : 
    2386              :         }
    2387              : #endif
    2388              :         // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
    2389    981215272 :         if (myLaneChangeModel->getShadowLane() != nullptr) {
    2390              :             // also slow down for leaders on the shadowLane relative to the current lane
    2391      4563809 :             const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
    2392              :             if (shadowLane != nullptr
    2393      4563809 :                     && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
    2394              :                         // continous lane change cannot be stopped so we must adapt to the leader on the target lane
    2395       187916 :                         || myLaneChangeModel->getLaneChangeCompletion() < 0.5)) {
    2396      4043321 :                 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
    2397      4003029 :                     double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
    2398      4003029 :                     if (myLaneChangeModel->isOpposite()) {
    2399              :                         // ego posLat is added when retrieving sublanes but it
    2400              :                         // should be negated (subtract twice to compensate)
    2401       143352 :                         latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
    2402       143352 :                                      - 2 * getLateralPositionOnLane());
    2403              : 
    2404              :                     }
    2405      4003029 :                     MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
    2406              : #ifdef DEBUG_PLAN_MOVE
    2407              :                     if (DEBUG_COND && myLaneChangeModel->isOpposite()) {
    2408              :                         std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
    2409              :                     }
    2410              : #endif
    2411      4003029 :                     if (myLaneChangeModel->isOpposite()) {
    2412              :                         // ignore oncoming vehicles on the shadow lane
    2413       143352 :                         shadowLeaders.removeOpposite(shadowLane);
    2414              :                     }
    2415      4003029 :                     const double turningDifference = MAX2(0.0, leaderLane->getLength() - shadowLane->getLength());
    2416      4003029 :                     adaptToLeaders(shadowLeaders, latOffset, seen - turningDifference, lastLink, shadowLane, v, vLinkPass);
    2417      4043321 :                 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
    2418              :                     // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
    2419              :                     // (and thus in the same direction as ego)
    2420        30311 :                     MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
    2421              :                     const double latOffset = 0;
    2422              : #ifdef DEBUG_PLAN_MOVE
    2423              :                     if (DEBUG_COND) {
    2424              :                         std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
    2425              :                                   << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
    2426              :                     }
    2427              : #endif
    2428        30311 :                     shadowLeaders.fixOppositeGaps(true);
    2429              : #ifdef DEBUG_PLAN_MOVE
    2430              :                     if (DEBUG_COND) {
    2431              :                         std::cout << "   shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
    2432              :                     }
    2433              : #endif
    2434        30311 :                     adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
    2435        30311 :                 }
    2436              :             }
    2437              :         }
    2438              :         // adapt to pedestrians on the same lane
    2439    981215272 :         if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
    2440       188644 :             const double relativePos = lane->getLength() - seen;
    2441              : #ifdef DEBUG_PLAN_MOVE
    2442              :             if (DEBUG_COND) {
    2443              :                 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
    2444              :             }
    2445              : #endif
    2446       188644 :             const double stopTime = MAX2(1.0, ceil(getSpeed() / cfModel.getMaxDecel()));
    2447       188644 :             PersonDist leader = lane->nextBlocking(relativePos,
    2448       188644 :                                                    getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
    2449       188644 :             if (leader.first != 0) {
    2450        19711 :                 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
    2451        28056 :                 v = MIN2(v, stopSpeed);
    2452              : #ifdef DEBUG_PLAN_MOVE
    2453              :                 if (DEBUG_COND) {
    2454              :                     std::cout << SIMTIME << "    pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
    2455              :                 }
    2456              : #endif
    2457              :             }
    2458              :         }
    2459    981215272 :         if (lane->getBidiLane() != nullptr) {
    2460              :             // adapt to pedestrians on the bidi lane
    2461      1697870 :             const MSLane* bidiLane = lane->getBidiLane();
    2462      1697870 :             if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
    2463          982 :                 const double relativePos = seen;
    2464              : #ifdef DEBUG_PLAN_MOVE
    2465              :                 if (DEBUG_COND) {
    2466              :                     std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
    2467              :                 }
    2468              : #endif
    2469          982 :                 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
    2470          982 :                 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
    2471          982 :                 PersonDist leader = bidiLane->nextBlocking(relativePos,
    2472          982 :                                     leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
    2473          982 :                 if (leader.first != 0) {
    2474          267 :                     const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
    2475          516 :                     v = MIN2(v, stopSpeed);
    2476              : #ifdef DEBUG_PLAN_MOVE
    2477              :                     if (DEBUG_COND) {
    2478              :                         std::cout << SIMTIME << "    pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
    2479              :                     }
    2480              : #endif
    2481              :                 }
    2482              :             }
    2483              :         }
    2484              : 
    2485              :         // process all stops and waypoints on the current edge
    2486              :         bool foundRealStop = false;
    2487              :         while (stopIt != myStops.end()
    2488     38985234 :                 && ((&stopIt->lane->getEdge() == &lane->getEdge())
    2489     18331806 :                     || (stopIt->isOpposite && stopIt->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
    2490              :                 // ignore stops that occur later in a looped route
    2491   1015796263 :                 && stopIt->edge == myCurrEdge + view) {
    2492     20610270 :             double stopDist = std::numeric_limits<double>::max();
    2493              :             const MSStop& stop = *stopIt;
    2494              :             const bool isFirstStop = stopIt == myStops.begin();
    2495              :             stopIt++;
    2496     20610270 :             if (!stop.reached || (stop.getSpeed() > 0 && keepStopping())) {
    2497              :                 // we are approaching a stop on the edge; must not drive further
    2498      7310790 :                 bool isWaypoint = stop.getSpeed() > 0;
    2499      7310790 :                 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
    2500      7310790 :                 if (stop.parkingarea != nullptr) {
    2501              :                     // leave enough space so parking vehicles can exit
    2502       732815 :                     const double brakePos = getBrakeGap() + lane->getLength() - seen;
    2503       732815 :                     endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
    2504      6577975 :                 } else if (isWaypoint && !stop.reached) {
    2505       103857 :                     endPos = stop.pars.startPos;
    2506              :                 }
    2507      7310790 :                 stopDist = seen + endPos - lane->getLength();
    2508              : #ifdef DEBUG_STOPS
    2509              :                 if (DEBUG_COND) {
    2510              :                     std::cout << SIMTIME << " veh=" << getID() <<  " stopDist=" << stopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
    2511              :                 }
    2512              : #endif
    2513              :                 // regular stops are not emergencies
    2514              :                 double stopSpeed = laneMaxV;
    2515      7310790 :                 if (isWaypoint) {
    2516              :                     bool waypointWithStop = false;
    2517       119213 :                     if (stop.getUntil() > t) {
    2518              :                         // check if we have to slow down or even stop
    2519              :                         SUMOTime time2end = 0;
    2520         3453 :                         if (stop.reached) {
    2521          678 :                             time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
    2522              :                         } else {
    2523         2971 :                             time2end = TIME2STEPS(
    2524              :                                            // time to reach waypoint start
    2525              :                                            stopDist / ((getSpeed() + stop.getSpeed()) / 2)
    2526              :                                            // time to reach waypoint end
    2527              :                                            + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
    2528              :                         }
    2529         3453 :                         if (stop.getUntil() > t + time2end) {
    2530              :                             // we need to stop
    2531              :                             double distToEnd = stopDist;
    2532         3313 :                             if (!stop.reached) {
    2533         2743 :                                 distToEnd += stop.pars.endPos - stop.pars.startPos;
    2534              :                             }
    2535         3313 :                             stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
    2536              :                             waypointWithStop = true;
    2537              :                         }
    2538              :                     }
    2539       119213 :                     if (stop.reached) {
    2540        14623 :                         stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
    2541        14623 :                         if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
    2542          246 :                             stopDist = std::numeric_limits<double>::max();
    2543              :                         }
    2544              :                     } else {
    2545       104590 :                         stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), stopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
    2546       104590 :                         if (!stop.reached) {
    2547       104590 :                             stopDist += stop.pars.endPos - stop.pars.startPos;
    2548              :                         }
    2549       104590 :                         if (lastLink != nullptr) {
    2550        66339 :                             lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
    2551              :                         }
    2552              :                     }
    2553              :                 } else {
    2554      7191577 :                     stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), stopDist), vMinComfortable);
    2555      7191577 :                     if (lastLink != nullptr) {
    2556      3376182 :                         lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
    2557              :                     }
    2558              :                 }
    2559      7310790 :                 v = MIN2(v, stopSpeed);
    2560      7310790 :                 if (lane->isInternal()) {
    2561         6261 :                     std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
    2562              :                     assert(!lane->isLinkEnd(exitLink));
    2563              :                     bool dummySetRequest;
    2564              :                     double dummyVLinkWait;
    2565         6261 :                     checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
    2566              :                 }
    2567              : 
    2568              : #ifdef DEBUG_PLAN_MOVE
    2569              :                 if (DEBUG_COND) {
    2570              :                     std::cout << "\n" << SIMTIME << " next stop: distance = " << stopDist << " requires stopSpeed = " << stopSpeed << "\n";
    2571              : 
    2572              :                 }
    2573              : #endif
    2574      7310790 :                 if (isFirstStop) {
    2575      7021573 :                     newStopDist = stopDist;
    2576              :                     // if the vehicle is going to stop we don't need to look further
    2577              :                     // (except for trains that make use of further link-approach registration for safety purposes)
    2578      7021573 :                     if (!isWaypoint) {
    2579              :                         planningToStop = true;
    2580      6937446 :                         if (!isRailway(getVClass())) {
    2581      6685865 :                             lfLinks.emplace_back(v, stopDist);
    2582              :                             foundRealStop = true;
    2583      6685865 :                             break;
    2584              :                         }
    2585              :                     }
    2586              :                 }
    2587              :             }
    2588              :         }
    2589              :         if (foundRealStop) {
    2590              :             break;
    2591              :         }
    2592              : 
    2593              :         // move to next lane
    2594              :         //  get the next link used
    2595    974529407 :         std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
    2596              : 
    2597              :         // Check whether this is a turn (to save info about the next upcoming turn)
    2598    974529407 :         if (!encounteredTurn) {
    2599    172553969 :             if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
    2600     16619373 :                 LinkDirection linkDir = (*link)->getDirection();
    2601     16619373 :                 switch (linkDir) {
    2602              :                     case LinkDirection::STRAIGHT:
    2603              :                     case LinkDirection::NODIR:
    2604              :                         break;
    2605      6140535 :                     default:
    2606      6140535 :                         nextTurn.first = seen;
    2607      6140535 :                         nextTurn.second = *link;
    2608              :                         encounteredTurn = true;
    2609              : #ifdef DEBUG_NEXT_TURN
    2610              :                         if (DEBUG_COND) {
    2611              :                             std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(linkDir)
    2612              :                                       << " at " << nextTurn.first << "m." << std::endl;
    2613              :                         }
    2614              : #endif
    2615              :                 }
    2616              :             }
    2617              :         }
    2618              : 
    2619              :         //  check whether the vehicle is on its final edge
    2620   1747970316 :         if (myCurrEdge + view + 1 == myRoute->end()
    2621    974529407 :                 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
    2622    201088498 :             const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
    2623              :                                          myParameter->arrivalSpeed : laneMaxV);
    2624              :             // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
    2625              :             // XXX: This does not work for ballistic update refs #2579
    2626    201088498 :             const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
    2627    201088498 :             const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
    2628    201088498 :             v = MIN2(v, va);
    2629    201088498 :             if (lastLink != nullptr) {
    2630              :                 lastLink->adaptLeaveSpeed(va);
    2631              :             }
    2632    201088498 :             lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
    2633    201088498 :             break;
    2634              :         }
    2635              :         // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
    2636              :         if (lane->isLinkEnd(link)
    2637    766381533 :                 || (MSGlobals::gSublane && brakeForOverlap(*link, lane))
    2638   1539551217 :                 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
    2639       209766 :                     && !myLaneChangeModel->hasBlueLight())) {
    2640      7581851 :             double va = cfModel.stopSpeed(this, getSpeed(), seen);
    2641      7581851 :             if (lastLink != nullptr) {
    2642              :                 lastLink->adaptLeaveSpeed(va);
    2643              :             }
    2644      7581851 :             if (myLaneChangeModel->getCommittedSpeed() > 0) {
    2645       310164 :                 v = MIN2(myLaneChangeModel->getCommittedSpeed(), v);
    2646              :             } else {
    2647     14027383 :                 v = MIN2(va, v);
    2648              :             }
    2649              : #ifdef DEBUG_PLAN_MOVE
    2650              :             if (DEBUG_COND) {
    2651              :                 std::cout << "   braking for link end lane=" << lane->getID() << " seen=" << seen
    2652              :                           << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
    2653              : 
    2654              :             }
    2655              : #endif
    2656      7581851 :             if (lane->isLinkEnd(link)) {
    2657      7059376 :                 lfLinks.emplace_back(v, seen);
    2658              :                 break;
    2659              :             }
    2660              :         }
    2661    766381533 :         lateralShift += (*link)->getLateralShift();
    2662    766381533 :         const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
    2663              :         // We distinguish 3 cases when determining the point at which a vehicle stops:
    2664              :         // - links that require stopping: here the vehicle needs to stop close to the stop line
    2665              :         //   to ensure it gets onto the junction in the next step. Otherwise the vehicle would 'forget'
    2666              :         //   that it already stopped and need to stop again. This is necessary pending implementation of #999
    2667              :         // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
    2668              :         // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
    2669              :         //   to minimize the time window for passing the junction. If the
    2670              :         //   vehicle 'decides' to accelerate and cannot enter the junction in
    2671              :         //   the next step, new foes may appear and cause a collision (see #1096)
    2672              :         // - major links: stopping point is irrelevant
    2673              :         double laneStopOffset;
    2674    766381533 :         const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
    2675              :         // override low desired decel at yellow and red
    2676    766381533 :         const double stopDecel = yellowOrRed && !isRailway(getVClass()) ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
    2677    766381533 :         const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
    2678    766381533 :         const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
    2679    766381533 :         const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
    2680    766381533 :         if (yellowOrRed) {
    2681              :             // Wait at red traffic light with full distance if possible
    2682              :             laneStopOffset = majorStopOffset;
    2683    714370030 :         } else if ((*link)->havePriority()) {
    2684              :             // On priority link, we should never stop below visibility distance
    2685    677287847 :             laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
    2686              :         } else {
    2687              :             // On minor link, we should likewise never stop below visibility distance
    2688     37082183 :             const double minorStopOffset = MAX2(lane->getVehicleStopOffset(this),
    2689     37082183 :                                                 getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
    2690     37082183 :             laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
    2691              :         }
    2692              : #ifdef DEBUG_PLAN_MOVE
    2693              :         if (DEBUG_COND) {
    2694              :             std::cout << SIMTIME << " veh=" << getID() << " desired stopOffset on lane '" << lane->getID() << "' is " << laneStopOffset << "\n";
    2695              :         }
    2696              : #endif
    2697    766381533 :         if (canBrakeBeforeLaneEnd) {
    2698              :             // avoid emergency braking if possible
    2699    740427141 :             laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
    2700              :         }
    2701              :         laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
    2702    766381533 :         double stopDist = MAX2(0., seen - laneStopOffset);
    2703     52011503 :         if (yellowOrRed && getDevice(typeid(MSDevice_GLOSA)) != nullptr
    2704          508 :                 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->getOverrideSafety()
    2705    766381533 :                 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->isSpeedAdviceActive()) {
    2706              :             stopDist = std::numeric_limits<double>::max();
    2707              :         }
    2708    766381533 :         if (newStopDist != std::numeric_limits<double>::max()) {
    2709              :             stopDist = MAX2(stopDist, newStopDist);
    2710              :         }
    2711              : #ifdef DEBUG_PLAN_MOVE
    2712              :         if (DEBUG_COND) {
    2713              :             std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
    2714              :                       << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
    2715              :         }
    2716              : #endif
    2717    766381533 :         if (isRailway(getVClass())
    2718    766381533 :                 && !lane->isInternal()) {
    2719              :             // check for train direction reversal
    2720      1453764 :             if (lane->getBidiLane() != nullptr
    2721      1453764 :                     && (*link)->getLane()->getBidiLane() == lane) {
    2722        19145 :                 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
    2723        19145 :                 if (seen < 1) {
    2724         1815 :                     mustSeeBeforeReversal = 2 * seen + getLength();
    2725              :                 }
    2726        33126 :                 v = MIN2(v, vMustReverse);
    2727              :             }
    2728              :             // signal that is passed in the current step does not count
    2729      2907528 :             foundRailSignal |= ((*link)->getTLLogic() != nullptr
    2730       511157 :                                 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
    2731      1876431 :                                 && seen > SPEED2DIST(v));
    2732              :         }
    2733              : 
    2734    766381533 :         bool canReverseEventually = false;
    2735    766381533 :         const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
    2736    766381533 :         v = MIN2(v, vReverse);
    2737              : #ifdef DEBUG_PLAN_MOVE
    2738              :         if (DEBUG_COND) {
    2739              :             std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
    2740              :         }
    2741              : #endif
    2742              : 
    2743              :         // check whether we need to slow down in order to finish a continuous lane change
    2744    766381533 :         if (myLaneChangeModel->isChangingLanes()) {
    2745              :             if (    // slow down to finish lane change before a turn lane
    2746       159701 :                 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
    2747              :                 // slow down to finish lane change before the shadow lane ends
    2748       136495 :                 (myLaneChangeModel->getShadowLane() != nullptr &&
    2749       136495 :                  (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
    2750              :                 // XXX maybe this is too harsh. Vehicles could cut some corners here
    2751        46393 :                 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
    2752              :                 assert(timeRemaining != 0);
    2753              :                 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
    2754        46393 :                 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
    2755        46393 :                                        (seen - POSITION_EPS) / timeRemaining);
    2756              : #ifdef DEBUG_PLAN_MOVE
    2757              :                 if (DEBUG_COND) {
    2758              :                     std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
    2759              :                               << " link=" << (*link)->getViaLaneOrLane()->getID()
    2760              :                               << " timeRemaining=" << timeRemaining
    2761              :                               << " v=" << v
    2762              :                               << " va=" << va
    2763              :                               << std::endl;
    2764              :                 }
    2765              : #endif
    2766        92585 :                 v = MIN2(va, v);
    2767              :             }
    2768              :         }
    2769              : 
    2770              :         // - always issue a request to leave the intersection we are currently on
    2771    766381533 :         const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
    2772              :         // - do not issue a request to enter an intersection after we already slowed down for an earlier one
    2773    766381533 :         const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
    2774              :         // - even if red, if we cannot break we should issue a request
    2775    766381533 :         bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
    2776              : 
    2777    766381533 :         double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
    2778    766381533 :         double vLinkWait = MIN2(v, stopSpeed);
    2779              : #ifdef DEBUG_PLAN_MOVE
    2780              :         if (DEBUG_COND) {
    2781              :             std::cout
    2782              :                     << " stopDist=" << stopDist
    2783              :                     << " stopDecel=" << stopDecel
    2784              :                     << " vLinkWait=" << vLinkWait
    2785              :                     << " brakeDist=" << brakeDist
    2786              :                     << " seen=" << seen
    2787              :                     << " leaveIntersection=" << leavingCurrentIntersection
    2788              :                     << " setRequest=" << setRequest
    2789              :                     //<< std::setprecision(16)
    2790              :                     //<< " v=" << v
    2791              :                     //<< " speedEps=" << NUMERICAL_EPS_SPEED
    2792              :                     //<< std::setprecision(gPrecision)
    2793              :                     << "\n";
    2794              :         }
    2795              : #endif
    2796              : 
    2797    766381533 :         if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
    2798     51976572 :             if (lane->isInternal()) {
    2799        40952 :                 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
    2800              :             }
    2801              :             // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
    2802     51976572 :             const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
    2803              :             // the vehicle is able to brake in front of a yellow/red traffic light
    2804     51976572 :             lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
    2805              :             //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
    2806     51976572 :             break;
    2807              :         }
    2808              : 
    2809    714404961 :         const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
    2810    714404961 :         if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
    2811              :             // restrict speed when ignoring a red light
    2812        48858 :             const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
    2813        48858 :             const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
    2814        96912 :             v = MIN2(va, v);
    2815              : #ifdef DEBUG_PLAN_MOVE
    2816              :             if (DEBUG_COND) std::cout
    2817              :                         << "   ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
    2818              :                         << " redSpeed=" << redSpeed
    2819              :                         << " va=" << va
    2820              :                         << " v=" << v
    2821              :                         << "\n";
    2822              : #endif
    2823              :         }
    2824              : 
    2825    714404961 :         checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
    2826              : 
    2827    714404961 :         if (lastLink != nullptr) {
    2828              :             lastLink->adaptLeaveSpeed(laneMaxV);
    2829              :         }
    2830    714404961 :         double arrivalSpeed = vLinkPass;
    2831              :         // vehicles should decelerate when approaching a minor link
    2832              :         // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
    2833              :         // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
    2834              : 
    2835              :         // whether the vehicle/driver is close enough to the link to see all possible foes #2123
    2836    714404961 :         const double visibilityDistance = (*link)->getFoeVisibilityDistance();
    2837    714404961 :         const double determinedFoePresence = seen <= visibilityDistance;
    2838              : //        // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
    2839              : //        double foeRecognitionTime = 0.0;
    2840              : //        double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
    2841              : 
    2842              : #ifdef DEBUG_PLAN_MOVE
    2843              :         if (DEBUG_COND) {
    2844              :             std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
    2845              :         }
    2846              : #endif
    2847              : 
    2848    714404961 :         const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
    2849     36685631 :         if (couldBrakeForMinor && !determinedFoePresence) {
    2850              :             // vehicle decelerates just enough to be able to stop if necessary and then accelerates
    2851     34187274 :             double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0., false);
    2852              :             // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
    2853     34187274 :             double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
    2854     34187274 :             arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
    2855              :             slowedDownForMinor = true;
    2856              : #ifdef DEBUG_PLAN_MOVE
    2857              :             if (DEBUG_COND) {
    2858              :                 std::cout << "   slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
    2859              :             }
    2860              : #endif
    2861    680217687 :         } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
    2862              :             // check for deadlock (circular yielding)
    2863              :             //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
    2864         2867 :             std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
    2865              :             //std::cout << "   blocker=" << Named::getIDSecure(blocker.first) << "\n";
    2866              :             int n = 100;
    2867         5696 :             while (blocker.second != nullptr && blocker.second != *link && n > 0) {
    2868         2829 :                 blocker = blocker.second->getFirstApproachingFoe(*link);
    2869         2829 :                 n--;
    2870              :                 //std::cout << "   blocker=" << Named::getIDSecure(blocker.first) << "\n";
    2871              :             }
    2872         2867 :             if (n == 0) {
    2873            0 :                 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
    2874              :             }
    2875              :             //std::cout << "   blockerLink=" << blocker.second << " link=" << *link << "\n";
    2876         2867 :             if (blocker.second == *link) {
    2877          488 :                 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
    2878          488 :                 if (RandHelper::rand(getRNG()) < threshold) {
    2879              :                     //std::cout << "   abort request, threshold=" << threshold << "\n";
    2880          310 :                     setRequest = false;
    2881              :                 }
    2882              :             }
    2883              :         }
    2884              : 
    2885    714404961 :         const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
    2886    714404961 :         if (couldBrakeForMinor && determinedFoePresence && (*link)->getLane()->getEdge().isRoundabout()) {
    2887       831155 :             const bool wasOpened = (*link)->opened(arrivalTime, arrivalSpeed, arrivalSpeed,
    2888       831155 :                                                    getLength(), getImpatience(),
    2889              :                                                    getCarFollowModel().getMaxDecel(),
    2890       831155 :                                                    getWaitingTime(), getLateralPositionOnLane(),
    2891              :                                                    nullptr, false, this);
    2892       831155 :             if (!wasOpened) {
    2893              :                 slowedDownForMinor = true;
    2894              :             }
    2895              : #ifdef DEBUG_PLAN_MOVE
    2896              :             if (DEBUG_COND) {
    2897              :                 std::cout << "   slowedDownForMinor at roundabout=" << (!wasOpened) << "\n";
    2898              :             }
    2899              : #endif
    2900              :         }
    2901              : 
    2902              :         // compute arrival speed and arrival time if vehicle starts braking now
    2903              :         // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
    2904              :         double arrivalSpeedBraking = 0;
    2905    714404961 :         const double bGap = cfModel.brakeGap(v);
    2906    714404961 :         if (seen < bGap && !isStopped() && !planningToStop) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
    2907              :             // vehicle cannot come to a complete stop in time
    2908     51402213 :             if (MSGlobals::gSemiImplicitEulerUpdate) {
    2909     48728138 :                 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
    2910              :                 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
    2911              :                 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
    2912              :             } else {
    2913      2674075 :                 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
    2914              :             }
    2915              :         }
    2916              : 
    2917              :         // estimate leave speed for passing time computation
    2918              :         // l=linkLength, a=accel, t=continuousTime, v=vLeave
    2919              :         // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
    2920   1064499122 :         const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this),
    2921    714404961 :                                                 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
    2922    714404961 :         lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
    2923              :                                            arrivalTime, arrivalSpeed,
    2924              :                                            arrivalSpeedBraking,
    2925              :                                            seen, estimatedLeaveSpeed));
    2926    714404961 :         if ((*link)->getViaLane() == nullptr) {
    2927              :             hadNonInternal = true;
    2928              :             ++view;
    2929              :         }
    2930              : #ifdef DEBUG_PLAN_MOVE
    2931              :         if (DEBUG_COND) {
    2932              :             std::cout << "   checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
    2933              :                       << " seenNonInternal=" << seenNonInternal
    2934              :                       << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
    2935              :         }
    2936              : #endif
    2937              :         // we need to look ahead far enough to see available space for checkRewindLinkLanes
    2938    736033459 :         if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
    2939              :             break;
    2940              :         }
    2941              :         // get the following lane
    2942              :         lane = (*link)->getViaLaneOrLane();
    2943    513171599 :         laneMaxV = lane->getVehicleMaxSpeed(this);
    2944    513171599 :         if (myInfluencer && !myInfluencer->considerSafeVelocity()) {
    2945              :             laneMaxV = std::numeric_limits<double>::max();
    2946              :         }
    2947              :         // the link was passed
    2948              :         // compute the velocity to use when the link is not blocked by other vehicles
    2949              :         //  the vehicle shall be not faster when reaching the next lane than allowed
    2950              :         //  speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
    2951    513171599 :         const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable);
    2952   1017338703 :         v = MIN2(va, v);
    2953              : #ifdef DEBUG_PLAN_MOVE
    2954              :         if (DEBUG_COND) {
    2955              :             std::cout << "   laneMaxV=" << laneMaxV << " freeSpeed=" << va << " v=" << v << "\n";
    2956              :         }
    2957              : #endif
    2958    513171599 :         if (lane->getEdge().isInternal()) {
    2959    220262284 :             seenInternal += lane->getLength();
    2960              :         } else {
    2961    292909315 :             seenNonInternal += lane->getLength();
    2962              :         }
    2963              :         // do not restrict results to the current vehicle to allow caching for the current time step
    2964    513171599 :         leaderLane = opposite ? lane->getParallelOpposite() : lane;
    2965    513171599 :         if (leaderLane == nullptr) {
    2966              : 
    2967              :             break;
    2968              :         }
    2969   1025927178 :         ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
    2970    512963589 :         seen += lane->getLength();
    2971   1025927178 :         vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
    2972              :         lastLink = &lfLinks.back();
    2973    512963589 :     }
    2974              : 
    2975              : //#ifdef DEBUG_PLAN_MOVE
    2976              : //    if(DEBUG_COND){
    2977              : //        std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
    2978              : //    }
    2979              : //#endif
    2980              : 
    2981              : #ifdef PARALLEL_STOPWATCH
    2982              :     myLane->getStopWatch()[0].stop();
    2983              : #endif
    2984    468251683 : }
    2985              : 
    2986              : 
    2987              : double
    2988         2786 : MSVehicle::slowDownForSchedule(double vMinComfortable) const {
    2989         2786 :     const double sfp = getVehicleType().getParameter().speedFactorPremature;
    2990              :     const MSStop& stop = myStops.front();
    2991         2786 :     std::pair<double, double> timeDist = estimateTimeToNextStop();
    2992         2786 :     double arrivalDelay = SIMTIME + timeDist.first - STEPS2TIME(stop.pars.arrival);
    2993         2786 :     double t = STEPS2TIME(stop.pars.arrival - SIMSTEP);
    2994         5572 :     if (stop.pars.hasParameter(toString(SUMO_ATTR_FLEX_ARRIVAL))) {
    2995          150 :         SUMOTime flexStart = string2time(stop.pars.getParameter(toString(SUMO_ATTR_FLEX_ARRIVAL)));
    2996           75 :         arrivalDelay += STEPS2TIME(stop.pars.arrival - flexStart);
    2997           75 :         t = STEPS2TIME(flexStart - SIMSTEP);
    2998         2711 :     } else if (stop.pars.started >= 0 && MSGlobals::gUseStopStarted) {
    2999          200 :         arrivalDelay += STEPS2TIME(stop.pars.arrival - stop.pars.started);
    3000          200 :         t = STEPS2TIME(stop.pars.started - SIMSTEP);
    3001              :     }
    3002         2786 :     if (arrivalDelay < 0 && sfp < getChosenSpeedFactor()) {
    3003              :         // we can slow down to better match the schedule (and increase energy efficiency)
    3004         2721 :         const double vSlowDownMin = MAX2(myLane->getSpeedLimit() * sfp, vMinComfortable);
    3005         2721 :         const double s = timeDist.second;
    3006              :         const double b = getCarFollowModel().getMaxDecel();
    3007              :         // x = speed for arriving in t seconds
    3008              :         // u = time at full speed
    3009              :         // u * x + (t - u) * 0.5 * x = s
    3010              :         // t - u = x / b
    3011              :         // eliminate u, solve x
    3012         2721 :         const double radicand = 4 * t * t * b * b - 8 * s * b;
    3013         2721 :         const double x = radicand >= 0 ? t * b - sqrt(radicand) * 0.5 : vSlowDownMin;
    3014         2721 :         double vSlowDown = x < vSlowDownMin ? vSlowDownMin : x;
    3015              : #ifdef DEBUG_PLAN_MOVE
    3016              :         if (DEBUG_COND) {
    3017              :             std::cout << SIMTIME << " veh=" << getID() << " ad=" << arrivalDelay << " t=" << t << " vsm=" << vSlowDownMin
    3018              :                       << " r=" << radicand << " vs=" << vSlowDown << "\n";
    3019              :         }
    3020              : #endif
    3021         2721 :         return vSlowDown;
    3022           65 :     } else if (arrivalDelay > 0 && sfp > getChosenSpeedFactor()) {
    3023              :         // in principle we could up to catch up with the schedule
    3024              :         // but at this point we can only lower the speed, the
    3025              :         // information would have to be used when computing getVehicleMaxSpeed
    3026              :     }
    3027           65 :     return getMaxSpeed();
    3028              : }
    3029              : 
    3030              : SUMOTime
    3031    766381533 : MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
    3032              :     const MSCFModel& cfModel = getCarFollowModel();
    3033              :     SUMOTime arrivalTime;
    3034    766381533 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
    3035              :         // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
    3036              :         // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
    3037              :         // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
    3038    710244930 :         arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
    3039              :     } else {
    3040     56136603 :         arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
    3041              :     }
    3042    766381533 :     if (isStopped()) {
    3043       545323 :         arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
    3044              :     }
    3045    766381533 :     return arrivalTime;
    3046              : }
    3047              : 
    3048              : 
    3049              : void
    3050    985658507 : MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
    3051              :                           const double seen, DriveProcessItem* const lastLink,
    3052              :                           const MSLane* const lane, double& v, double& vLinkPass) const {
    3053              :     int rightmost;
    3054              :     int leftmost;
    3055    985658507 :     ahead.getSubLanes(this, latOffset, rightmost, leftmost);
    3056              : #ifdef DEBUG_PLAN_MOVE
    3057              :     if (DEBUG_COND) std::cout << SIMTIME
    3058              :                                   << "\nADAPT_TO_LEADERS\nveh=" << getID()
    3059              :                                   << " lane=" << lane->getID()
    3060              :                                   << " latOffset=" << latOffset
    3061              :                                   << " rm=" << rightmost
    3062              :                                   << " lm=" << leftmost
    3063              :                                   << " shift=" << ahead.getSublaneOffset()
    3064              :                                   << " ahead=" << ahead.toString()
    3065              :                                   << "\n";
    3066              : #endif
    3067              :     /*
    3068              :     if (myLaneChangeModel->getCommittedSpeed() > 0) {
    3069              :         v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
    3070              :         vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
    3071              :     #ifdef DEBUG_PLAN_MOVE
    3072              :         if (DEBUG_COND) std::cout << "   hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
    3073              :     #endif
    3074              :         return;
    3075              :     }
    3076              :     */
    3077   2464943117 :     for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
    3078   1479284610 :         const MSVehicle* pred = ahead[sublane];
    3079   1479284610 :         if (pred != nullptr && pred != this) {
    3080              :             // @todo avoid multiple adaptations to the same leader
    3081   1066842462 :             const double predBack = pred->getBackPositionOnLane(lane);
    3082              :             double gap = (lastLink == nullptr
    3083   1564731373 :                           ? predBack - myState.myPos - getVehicleType().getMinGap()
    3084    497888911 :                           : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
    3085              :             bool oncoming = false;
    3086   1066842462 :             if (myLaneChangeModel->isOpposite()) {
    3087        25356 :                 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
    3088              :                     // ego might and leader are driving against lane
    3089              :                     gap = (lastLink == nullptr
    3090            0 :                            ? myState.myPos - predBack - getVehicleType().getMinGap()
    3091            0 :                            : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
    3092              :                 } else {
    3093              :                     // ego and leader are driving in the same direction as lane (shadowlane for ego)
    3094              :                     gap = (lastLink == nullptr
    3095        26012 :                            ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
    3096          656 :                            : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
    3097              :                 }
    3098   1066817106 :             } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
    3099              :                 // must react to stopped / dangerous oncoming vehicles
    3100       190900 :                 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
    3101              :                 // try to avoid collision in the next second
    3102       190900 :                 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
    3103              : #ifdef DEBUG_PLAN_MOVE
    3104              :                 if (DEBUG_COND) {
    3105              :                     std::cout << "    fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
    3106              :                 }
    3107              : #endif
    3108       190900 :                 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
    3109        22844 :                     gap -= predMaxDist;
    3110              :                 }
    3111   1066626206 :             } else if (pred->getLane() == lane->getBidiLane()) {
    3112        44784 :                 gap -= pred->getVehicleType().getLengthWithGap();
    3113              :                 oncoming = true;
    3114              :             }
    3115              : #ifdef DEBUG_PLAN_MOVE
    3116              :             if (DEBUG_COND) {
    3117              :                 std::cout << "     pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << gap << " predBack=" << predBack << " seen=" << seen << " lane=" << lane->getID() << " myLane=" << myLane->getID() << " lastLink=" << (lastLink == nullptr ? "NULL" : lastLink->myLink->getDescription()) << " oncoming=" << oncoming << "\n";
    3118              :             }
    3119              : #endif
    3120        44784 :             if (oncoming && gap >= 0) {
    3121        44784 :                 adaptToOncomingLeader(std::make_pair(pred, gap), lastLink, v, vLinkPass);
    3122              :             } else {
    3123   1066797678 :                 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
    3124              :             }
    3125              :         }
    3126              :     }
    3127    985658507 : }
    3128              : 
    3129              : void
    3130       432008 : MSVehicle::adaptToLeaderDistance(const MSLeaderDistanceInfo& ahead, double latOffset,
    3131              :                                  double seen,
    3132              :                                  DriveProcessItem* const lastLink,
    3133              :                                  double& v, double& vLinkPass) const {
    3134              :     int rightmost;
    3135              :     int leftmost;
    3136       432008 :     ahead.getSubLanes(this, latOffset, rightmost, leftmost);
    3137              : #ifdef DEBUG_PLAN_MOVE
    3138              :     if (DEBUG_COND) std::cout << SIMTIME
    3139              :                                   << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
    3140              :                                   << " latOffset=" << latOffset
    3141              :                                   << " rm=" << rightmost
    3142              :                                   << " lm=" << leftmost
    3143              :                                   << " ahead=" << ahead.toString()
    3144              :                                   << "\n";
    3145              : #endif
    3146      1055978 :     for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
    3147       623970 :         CLeaderDist predDist = ahead[sublane];
    3148       623970 :         const MSVehicle* pred = predDist.first;
    3149       623970 :         if (pred != nullptr && pred != this) {
    3150              : #ifdef DEBUG_PLAN_MOVE
    3151              :             if (DEBUG_COND) {
    3152              :                 std::cout << "     pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
    3153              :             }
    3154              : #endif
    3155       399299 :             adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
    3156              :         }
    3157              :     }
    3158       432008 : }
    3159              : 
    3160              : 
    3161              : void
    3162   1067196977 : MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
    3163              :                          double seen,
    3164              :                          DriveProcessItem* const lastLink,
    3165              :                          double& v, double& vLinkPass) const {
    3166   1067196977 :     if (leaderInfo.first != 0) {
    3167   1067196977 :         if (ignoreFoe(leaderInfo.first)) {
    3168              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3169              :             if (DEBUG_COND) {
    3170              :                 std::cout << "  foe ignored\n";
    3171              :             }
    3172              : #endif
    3173              :             return;
    3174              :         }
    3175              :         const MSCFModel& cfModel = getCarFollowModel();
    3176              :         double vsafeLeader = 0;
    3177   1067196157 :         if (!MSGlobals::gSemiImplicitEulerUpdate) {
    3178              :             vsafeLeader = -std::numeric_limits<double>::max();
    3179              :         }
    3180              :         bool backOnRoute = true;
    3181   1067196157 :         if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
    3182              :             backOnRoute = false;
    3183              :             // this can either be
    3184              :             // a) a merging situation (leader back is is not our route) or
    3185              :             // b) a minGap violation / collision
    3186              :             MSLane* current = lastLink->myLink->getViaLaneOrLane();
    3187       238455 :             if (leaderInfo.first->getBackLane() == current) {
    3188              :                 backOnRoute = true;
    3189              :             } else {
    3190       541245 :                 for (MSLane* lane : getBestLanesContinuation()) {
    3191       493582 :                     if (lane == current) {
    3192              :                         break;
    3193              :                     }
    3194       356999 :                     if (leaderInfo.first->getBackLane() == lane) {
    3195              :                         backOnRoute = true;
    3196              :                     }
    3197              :                 }
    3198              :             }
    3199              : #ifdef DEBUG_PLAN_MOVE
    3200              :             if (DEBUG_COND) {
    3201              :                 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
    3202              :             }
    3203              : #endif
    3204       184246 :             if (!backOnRoute) {
    3205       103782 :                 double stopDist = seen - current->getLength() - POSITION_EPS;
    3206       103782 :                 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
    3207              :                     // do not drive onto the junction conflict area
    3208        87246 :                     stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
    3209              :                 }
    3210       103782 :                 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
    3211              :             }
    3212              :         }
    3213       157991 :         if (backOnRoute) {
    3214   1067092375 :             vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
    3215              :         }
    3216   1067196157 :         if (lastLink != nullptr) {
    3217    497879931 :             const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
    3218              :             lastLink->adaptLeaveSpeed(futureVSafe);
    3219              : #ifdef DEBUG_PLAN_MOVE
    3220              :             if (DEBUG_COND) {
    3221              :                 std::cout << "   vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
    3222              :             }
    3223              : #endif
    3224              :         }
    3225   1067196157 :         v = MIN2(v, vsafeLeader);
    3226   1824587747 :         vLinkPass = MIN2(vLinkPass, vsafeLeader);
    3227              : #ifdef DEBUG_PLAN_MOVE
    3228              :         if (DEBUG_COND) std::cout
    3229              :                     << SIMTIME
    3230              :                     //std::cout << std::setprecision(10);
    3231              :                     << " veh=" << getID()
    3232              :                     << " lead=" << leaderInfo.first->getID()
    3233              :                     << " leadSpeed=" << leaderInfo.first->getSpeed()
    3234              :                     << " gap=" << leaderInfo.second
    3235              :                     << " leadLane=" << leaderInfo.first->getLane()->getID()
    3236              :                     << " predPos=" << leaderInfo.first->getPositionOnLane()
    3237              :                     << " myLane=" << myLane->getID()
    3238              :                     << " v=" << v
    3239              :                     << " vSafeLeader=" << vsafeLeader
    3240              :                     << " vLinkPass=" << vLinkPass
    3241              :                     << "\n";
    3242              : #endif
    3243              :     }
    3244              : }
    3245              : 
    3246              : 
    3247              : void
    3248     15767672 : MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
    3249              :                                  const double seen, DriveProcessItem* const lastLink,
    3250              :                                  const MSLane* const lane, double& v, double& vLinkPass,
    3251              :                                  double distToCrossing) const {
    3252     15767672 :     if (leaderInfo.first != 0) {
    3253     15767672 :         if (ignoreFoe(leaderInfo.first)) {
    3254              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3255              :             if (DEBUG_COND) {
    3256              :                 std::cout << "  junction foe ignored\n";
    3257              :             }
    3258              : #endif
    3259              :             return;
    3260              :         }
    3261              :         const MSCFModel& cfModel = getCarFollowModel();
    3262              :         double vsafeLeader = 0;
    3263     15767636 :         if (!MSGlobals::gSemiImplicitEulerUpdate) {
    3264              :             vsafeLeader = -std::numeric_limits<double>::max();
    3265              :         }
    3266     15767636 :         if (leaderInfo.second >= 0) {
    3267     13310346 :             if (hasDeparted()) {
    3268     13310300 :                 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
    3269              :             } else {
    3270              :                 // called in the context of MSLane::isInsertionSuccess
    3271           46 :                 vsafeLeader = cfModel.insertionFollowSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
    3272              :             }
    3273      2457290 :         } else if (leaderInfo.first != this) {
    3274              :             // the leading, in-lapping vehicle is occupying the complete next lane
    3275              :             // stop before entering this lane
    3276      2003144 :             vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
    3277              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3278              :             if (DEBUG_COND) {
    3279              :                 std::cout << SIMTIME << " veh=" << getID() << "  stopping before junction: lane=" << lane->getID() << " seen=" << seen
    3280              :                           << " laneLength=" << lane->getLength()
    3281              :                           << " stopDist=" << seen - lane->getLength()  - POSITION_EPS
    3282              :                           << " vsafeLeader=" << vsafeLeader
    3283              :                           << " distToCrossing=" << distToCrossing
    3284              :                           << "\n";
    3285              :             }
    3286              : #endif
    3287              :         }
    3288     15767636 :         if (distToCrossing >= 0) {
    3289              :             // can the leader still stop in the way?
    3290      5353533 :             const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
    3291      5353533 :             if (leaderInfo.first == this) {
    3292              :                 // braking for pedestrian
    3293       442437 :                 const double vStopCrossing = cfModel.stopSpeed(this, getSpeed(), distToCrossing);
    3294              :                 vsafeLeader = vStopCrossing;
    3295              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3296              :                 if (DEBUG_COND) {
    3297              :                     std::cout << "  breaking for pedestrian distToCrossing=" << distToCrossing << " vStopCrossing=" << vStopCrossing << "\n";
    3298              :                 }
    3299              : #endif
    3300       442437 :                 if (lastLink != nullptr) {
    3301              :                     lastLink->adaptStopSpeed(vsafeLeader);
    3302              :                 }
    3303      4911096 :             } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
    3304              :                 // drive up to the crossing point and stop
    3305              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3306              :                 if (DEBUG_COND) {
    3307              :                     std::cout << "  stop at crossing point for critical leader vStop=" << vStop << "\n";
    3308              :                 };
    3309              : #endif
    3310              :                 vsafeLeader = MAX2(vsafeLeader, vStop);
    3311              :             } else {
    3312      4868108 :                 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
    3313              :                 // estimate the time at which the leader has gone past the crossing point
    3314      4868108 :                 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
    3315              :                 // reach distToCrossing after that time
    3316              :                 // avgSpeed * leaderPastCPTime = distToCrossing
    3317              :                 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
    3318      4868108 :                 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
    3319      4868108 :                 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
    3320              :                 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
    3321              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3322              :                 if (DEBUG_COND) {
    3323              :                     std::cout << "    driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
    3324              :                               << " leaderPastCPTime=" << leaderPastCPTime
    3325              :                               << " vFinal=" << vFinal
    3326              :                               << " v2=" << v2
    3327              :                               << " vStop=" << vStop
    3328              :                               << " vsafeLeader=" << vsafeLeader << "\n";
    3329              :                 }
    3330              : #endif
    3331              :             }
    3332              :         }
    3333     15325199 :         if (lastLink != nullptr) {
    3334              :             lastLink->adaptLeaveSpeed(vsafeLeader);
    3335              :         }
    3336     15767636 :         v = MIN2(v, vsafeLeader);
    3337     29397869 :         vLinkPass = MIN2(vLinkPass, vsafeLeader);
    3338              : #ifdef DEBUG_PLAN_MOVE
    3339              :         if (DEBUG_COND) std::cout
    3340              :                     << SIMTIME
    3341              :                     //std::cout << std::setprecision(10);
    3342              :                     << " veh=" << getID()
    3343              :                     << " lead=" << leaderInfo.first->getID()
    3344              :                     << " leadSpeed=" << leaderInfo.first->getSpeed()
    3345              :                     << " gap=" << leaderInfo.second
    3346              :                     << " leadLane=" << leaderInfo.first->getLane()->getID()
    3347              :                     << " predPos=" << leaderInfo.first->getPositionOnLane()
    3348              :                     << " seen=" << seen
    3349              :                     << " lane=" << lane->getID()
    3350              :                     << " myLane=" << myLane->getID()
    3351              :                     << " dTC=" << distToCrossing
    3352              :                     << " v=" << v
    3353              :                     << " vSafeLeader=" << vsafeLeader
    3354              :                     << " vLinkPass=" << vLinkPass
    3355              :                     << "\n";
    3356              : #endif
    3357              :     }
    3358              : }
    3359              : 
    3360              : 
    3361              : void
    3362        44784 : MSVehicle::adaptToOncomingLeader(const std::pair<const MSVehicle*, double> leaderInfo,
    3363              :                                  DriveProcessItem* const lastLink,
    3364              :                                  double& v, double& vLinkPass) const {
    3365        44784 :     if (leaderInfo.first != 0) {
    3366        44784 :         if (ignoreFoe(leaderInfo.first)) {
    3367              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3368              :             if (DEBUG_COND) {
    3369              :                 std::cout << "  oncoming foe ignored\n";
    3370              :             }
    3371              : #endif
    3372              :             return;
    3373              :         }
    3374              :         const MSCFModel& cfModel = getCarFollowModel();
    3375              :         const MSVehicle* lead = leaderInfo.first;
    3376              :         const MSCFModel& cfModelL = lead->getCarFollowModel();
    3377              :         // assume the leader reacts symmetrically (neither stopping instantly nor ignoring ego)
    3378        44665 :         const double leaderBrakeGap = cfModelL.brakeGap(lead->getSpeed(), cfModelL.getMaxDecel(), 0);
    3379        44665 :         const double egoBrakeGap = cfModel.brakeGap(getSpeed(), cfModel.getMaxDecel(), 0);
    3380        44665 :         const double gapSum = leaderBrakeGap + egoBrakeGap;
    3381              :         // ensure that both vehicles can leave an intersection if they are currently on it
    3382        44665 :         double egoExit = getDistanceToLeaveJunction();
    3383        44665 :         const double leaderExit = lead->getDistanceToLeaveJunction();
    3384              :         double gap = leaderInfo.second;
    3385        44665 :         if (egoExit + leaderExit < gap) {
    3386        39478 :             gap -= egoExit + leaderExit;
    3387              :         } else {
    3388              :             egoExit = 0;
    3389              :         }
    3390              :         // split any distance in excess of brakeGaps evenly
    3391        44665 :         const double freeGap = MAX2(0.0, gap - gapSum);
    3392              :         const double splitGap = MIN2(gap, gapSum);
    3393              :         // assume remaining distance is allocated in proportion to braking distance
    3394        44665 :         const double gapRatio = gapSum > 0 ? egoBrakeGap / gapSum : 0.5;
    3395        44665 :         const double vsafeLeader = cfModel.stopSpeed(this, getSpeed(), splitGap * gapRatio + egoExit + 0.5 * freeGap);
    3396        44665 :         if (lastLink != nullptr) {
    3397        30695 :             const double futureVSafe = cfModel.stopSpeed(this, lastLink->accelV, leaderInfo.second, MSCFModel::CalcReason::FUTURE);
    3398              :             lastLink->adaptLeaveSpeed(futureVSafe);
    3399              : #ifdef DEBUG_PLAN_MOVE
    3400              :             if (DEBUG_COND) {
    3401              :                 std::cout << "   vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
    3402              :             }
    3403              : #endif
    3404              :         }
    3405        44665 :         v = MIN2(v, vsafeLeader);
    3406        87974 :         vLinkPass = MIN2(vLinkPass, vsafeLeader);
    3407              : #ifdef DEBUG_PLAN_MOVE
    3408              :         if (DEBUG_COND) std::cout
    3409              :                     << SIMTIME
    3410              :                     //std::cout << std::setprecision(10);
    3411              :                     << " veh=" << getID()
    3412              :                     << " oncomingLead=" << lead->getID()
    3413              :                     << " leadSpeed=" << lead->getSpeed()
    3414              :                     << " gap=" << leaderInfo.second
    3415              :                     << " gap2=" << gap
    3416              :                     << " gapRatio=" << gapRatio
    3417              :                     << " leadLane=" << lead->getLane()->getID()
    3418              :                     << " predPos=" << lead->getPositionOnLane()
    3419              :                     << " myLane=" << myLane->getID()
    3420              :                     << " v=" << v
    3421              :                     << " vSafeLeader=" << vsafeLeader
    3422              :                     << " vLinkPass=" << vLinkPass
    3423              :                     << "\n";
    3424              : #endif
    3425              :     }
    3426              : }
    3427              : 
    3428              : 
    3429              : void
    3430    714452174 : MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
    3431              :         DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
    3432    714452174 :     if (MSGlobals::gUsingInternalLanes && (myInfluencer == nullptr || myInfluencer->getRespectJunctionLeaderPriority())) {
    3433              :         // we want to pass the link but need to check for foes on internal lanes
    3434    714348419 :         checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
    3435    714348419 :         if (myLaneChangeModel->getShadowLane() != nullptr) {
    3436      2908125 :             const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
    3437      2908125 :             if (parallelLink != nullptr) {
    3438      2033718 :                 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
    3439              :             }
    3440              :         }
    3441              :     }
    3442              : 
    3443    714452174 : }
    3444              : 
    3445              : void
    3446    716701853 : MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
    3447              :                            DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
    3448              :                            bool isShadowLink) const {
    3449              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3450              :     if (DEBUG_COND) {
    3451              :         gDebugFlag1 = true;    // See MSLink::getLeaderInfo
    3452              :     }
    3453              : #endif
    3454    716701853 :     const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
    3455              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3456              :     if (DEBUG_COND) {
    3457              :         gDebugFlag1 = false;    // See MSLink::getLeaderInfo
    3458              :     }
    3459              : #endif
    3460    733319221 :     for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
    3461              :         // the vehicle to enter the junction first has priority
    3462     16617368 :         const MSVehicle* leader = (*it).vehAndGap.first;
    3463     16617368 :         if (leader == nullptr) {
    3464              :             // leader is a pedestrian. Passing 'this' as a dummy.
    3465              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3466              :             if (DEBUG_COND) {
    3467              :                 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
    3468              :             }
    3469              : #endif
    3470       454920 :             if (getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_JUNCTION_FOE_PROB, 0) > 0
    3471       454920 :                     && getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_JUNCTION_FOE_PROB, 0) >= RandHelper::rand(getRNG())) {
    3472              : #ifdef DEBUG_PLAN_MOVE
    3473              :                 if (DEBUG_COND) {
    3474              :                     std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
    3475              :                 }
    3476              : #endif
    3477          774 :                 continue;
    3478              :             }
    3479       454146 :             adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
    3480              :             // if blocked by a pedestrian for too long we must yield our request
    3481       454146 :             if (v < SUMO_const_haltingSpeed && getWaitingTime() > TIME2STEPS(JUNCTION_BLOCKAGE_TIME)) {
    3482        69935 :                 setRequest = false;
    3483              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3484              :                 if (DEBUG_COND) {
    3485              :                     std::cout << "   aborting request\n";
    3486              :                 }
    3487              : #endif
    3488              :             }
    3489     16162448 :         } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay()) {
    3490     16118382 :             if (getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_JUNCTION_FOE_PROB, 0) > 0
    3491     16118382 :                     && getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_JUNCTION_FOE_PROB, 0) >= RandHelper::rand(getRNG())) {
    3492              : #ifdef DEBUG_PLAN_MOVE
    3493              :                 if (DEBUG_COND) {
    3494              :                     std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
    3495              :                 }
    3496              : #endif
    3497         1747 :                 continue;
    3498              :             }
    3499     21581323 :             if (MSGlobals::gLateralResolution > 0 &&
    3500              :                     // sibling link (XXX: could also be partial occupator where this check fails)
    3501      5464688 :                     &leader->getLane()->getEdge() == &lane->getEdge()) {
    3502              :                 // check for sublane obstruction (trivial for sibling link leaders)
    3503              :                 const MSLane* conflictLane = link->getInternalLaneBefore();
    3504       805276 :                 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
    3505       805276 :                 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
    3506       805276 :                 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
    3507              :                 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
    3508       805276 :                 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
    3509              : #ifdef DEBUG_PLAN_MOVE
    3510              :                 if (DEBUG_COND) {
    3511              :                     std::cout << SIMTIME << " veh=" << getID()
    3512              :                               << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
    3513              :                               << " isShadowLink=" << isShadowLink
    3514              :                               << " lane=" << lane->getID()
    3515              :                               << " foe=" << leader->getID()
    3516              :                               << " foeLane=" << leader->getLane()->getID()
    3517              :                               << " latOffset=" << latOffset
    3518              :                               << " latOffsetFoe=" << leader->getLatOffset(lane)
    3519              :                               << " linkLeadersAhead=" << linkLeadersAhead.toString()
    3520              :                               << "\n";
    3521              :                 }
    3522              : #endif
    3523       805276 :             } else {
    3524              : #ifdef DEBUG_PLAN_MOVE
    3525              :                 if (DEBUG_COND) {
    3526              :                     std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
    3527              :                               << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
    3528              :                               << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
    3529              :                               << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
    3530              :                               << "\n";
    3531              :                 }
    3532              : #endif
    3533     15311359 :                 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
    3534              :             }
    3535     16116635 :             if (lastLink != nullptr) {
    3536              :                 // we are not yet on the junction with this linkLeader.
    3537              :                 // at least we can drive up to the previous link and stop there
    3538     30922240 :                 v = MAX2(v, lastLink->myVLinkWait);
    3539              :             }
    3540              :             // if blocked by a leader from the same or next lane we must yield our request
    3541              :             // also, if blocked by a stopped or blocked leader
    3542     16116635 :             if (v < SUMO_const_haltingSpeed
    3543              :                     //&& leader->getSpeed() < SUMO_const_haltingSpeed
    3544     16116635 :                     && (leader->getLane()->getLogicalPredecessorLane() == myLane->getLogicalPredecessorLane()
    3545      8626702 :                         || leader->getLane()->getLogicalPredecessorLane() == myLane
    3546      7306567 :                         || leader->isStopped()
    3547      7228071 :                         || leader->getWaitingTime() > TIME2STEPS(JUNCTION_BLOCKAGE_TIME))) {
    3548      2732232 :                 setRequest = false;
    3549              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3550              :                 if (DEBUG_COND) {
    3551              :                     std::cout << "   aborting request\n";
    3552              :                 }
    3553              : #endif
    3554      2732232 :                 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
    3555              :                     // we are not yet on the junction so must abort that request as well
    3556              :                     // (or maybe we are already on the junction and the leader is a partial occupator beyond)
    3557      1307076 :                     lastLink->mySetRequest = false;
    3558              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3559              :                     if (DEBUG_COND) {
    3560              :                         std::cout << "      aborting previous request\n";
    3561              :                     }
    3562              : #endif
    3563              :                 }
    3564              :             }
    3565              :         }
    3566              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    3567              :         else {
    3568              :             if (DEBUG_COND) {
    3569              :                 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
    3570              :                           << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
    3571              :                           << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
    3572              :                           << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
    3573              :                           << "\n";
    3574              :             }
    3575              :         }
    3576              : #endif
    3577              :     }
    3578              :     // if this is the link between two internal lanes we may have to slow down for pedestrians
    3579    716701853 :     vLinkWait = MIN2(vLinkWait, v);
    3580    716701853 : }
    3581              : 
    3582              : 
    3583              : double
    3584     99261193 : MSVehicle::getDeltaPos(const double accel) const {
    3585     99261193 :     double vNext = myState.mySpeed + ACCEL2SPEED(accel);
    3586     99261193 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
    3587              :         // apply implicit Euler positional update
    3588            0 :         return SPEED2DIST(MAX2(vNext, 0.));
    3589              :     } else {
    3590              :         // apply ballistic update
    3591     99261193 :         if (vNext >= 0) {
    3592              :             // assume constant acceleration during this time step
    3593     98635193 :             return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
    3594              :         } else {
    3595              :             // negative vNext indicates a stop within the middle of time step
    3596              :             // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
    3597              :             // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
    3598              :             // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
    3599              :             // until the vehicle stops.
    3600       626000 :             return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
    3601              :         }
    3602              :     }
    3603              : }
    3604              : 
    3605              : void
    3606    468251668 : MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
    3607              : 
    3608              :     // Speed limit due to zipper merging
    3609              :     double vSafeZipper = std::numeric_limits<double>::max();
    3610              : 
    3611    468251668 :     myHaveToWaitOnNextLink = false;
    3612              :     bool canBrakeVSafeMin = false;
    3613              : 
    3614              :     // Get safe velocities from DriveProcessItems.
    3615              :     assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
    3616   1035381764 :     for (const DriveProcessItem& dpi : myLFLinkLanes) {
    3617    873886227 :         MSLink* const link = dpi.myLink;
    3618              : 
    3619              : #ifdef DEBUG_EXEC_MOVE
    3620              :         if (DEBUG_COND) {
    3621              :             std::cout
    3622              :                     << SIMTIME
    3623              :                     << " veh=" << getID()
    3624              :                     << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
    3625              :                     << " req=" << dpi.mySetRequest
    3626              :                     << " vP=" << dpi.myVLinkPass
    3627              :                     << " vW=" << dpi.myVLinkWait
    3628              :                     << " d=" << dpi.myDistance
    3629              :                     << "\n";
    3630              :             gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
    3631              :         }
    3632              : #endif
    3633              : 
    3634              :         // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
    3635    873886227 :         if (link != nullptr && dpi.mySetRequest) {
    3636              : 
    3637              :             const LinkState ls = link->getState();
    3638              :             // vehicles should brake when running onto a yellow light if the distance allows to halt in front
    3639              :             const bool yellow = link->haveYellow();
    3640    586045667 :             const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
    3641    586045667 :                                    || (MSGlobals::gSemiImplicitEulerUpdate && myState.mySpeed < ACCEL2SPEED(getCarFollowModel().getMaxDecel())));
    3642              :             assert(link->getLaneBefore() != nullptr);
    3643    586045667 :             const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
    3644    586045667 :             const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
    3645    586045667 :             if (yellow && canBrake && !ignoreRedLink) {
    3646            1 :                 vSafe = dpi.myVLinkWait;
    3647            1 :                 myHaveToWaitOnNextLink = true;
    3648              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3649              :                 if (DEBUG_COND) {
    3650              :                     std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
    3651              :                 }
    3652              : #endif
    3653     18915566 :                 break;
    3654              :             }
    3655    586045666 :             const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
    3656              :             MSLink::BlockingFoes collectFoes;
    3657    586045666 :             bool opened = (yellow || influencerPrio
    3658   1757925424 :                            || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
    3659    585939879 :                                            getVehicleType().getLength(),
    3660    560007036 :                                            canBrake ? getImpatience() : 1,
    3661              :                                            getCarFollowModel().getMaxDecel(),
    3662    585939879 :                                            getWaitingTime(), getLateralPositionOnLane(),
    3663              :                                            ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
    3664    585939879 :                                            ignoreRedLink, this, dpi.myDistance));
    3665    581142051 :             if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
    3666      1817546 :                 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
    3667      1817546 :                 if (parallelLink != nullptr) {
    3668      1110548 :                     const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
    3669      1110548 :                                                     myLane->getWidth() + myLaneChangeModel->getShadowLane()->getWidth());
    3670      2219437 :                     opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
    3671      1108889 :                                                           getVehicleType().getLength(), getImpatience(),
    3672              :                                                           getCarFollowModel().getMaxDecel(),
    3673      1108889 :                                                           getWaitingTime(), shadowLatPos, nullptr,
    3674      1108889 :                                                           ignoreRedLink, this, dpi.myDistance));
    3675              : #ifdef DEBUG_EXEC_MOVE
    3676              :                     if (DEBUG_COND) {
    3677              :                         std::cout << SIMTIME
    3678              :                                   << " veh=" << getID()
    3679              :                                   << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
    3680              :                                   << " shadowDir=" << myLaneChangeModel->getShadowDirection()
    3681              :                                   << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
    3682              :                                   << " opened=" << opened
    3683              :                                   << "\n";
    3684              :                     }
    3685              : #endif
    3686              :                 }
    3687              :             }
    3688              :             // vehicles should decelerate when approaching a minor link
    3689              : #ifdef DEBUG_EXEC_MOVE
    3690              :             if (DEBUG_COND) {
    3691              :                 std::cout << SIMTIME
    3692              :                           << "   opened=" << opened
    3693              :                           << " influencerPrio=" << influencerPrio
    3694              :                           << " linkPrio=" << link->havePriority()
    3695              :                           << " lastContMajor=" << link->lastWasContMajor()
    3696              :                           << " isCont=" << link->isCont()
    3697              :                           << " ignoreRed=" << ignoreRedLink
    3698              :                           << "\n";
    3699              :             }
    3700              : #endif
    3701    586045666 :             if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
    3702              :                 double visibilityDistance = link->getFoeVisibilityDistance();
    3703     15682532 :                 double determinedFoePresence = dpi.myDistance <= visibilityDistance;
    3704     14817637 :                 if (!determinedFoePresence && (canBrake || !yellow)) {
    3705     14809036 :                     vSafe = dpi.myVLinkWait;
    3706     14809036 :                     myHaveToWaitOnNextLink = true;
    3707              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3708              :                     if (DEBUG_COND) {
    3709              :                         std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
    3710              :                     }
    3711              : #endif
    3712     14809036 :                     break;
    3713              :                 } else {
    3714              :                     // past the point of no return. we need to drive fast enough
    3715              :                     // to make it across the link. However, minor slowdowns
    3716              :                     // should be permissible to follow leading traffic safely
    3717              :                     // basically, this code prevents dawdling
    3718              :                     // (it's harder to do this later using
    3719              :                     // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
    3720              :                     // vehicle is already too close to stop at that part of the code)
    3721              :                     //
    3722              :                     // XXX: There is a problem in subsecond simulation: If we cannot
    3723              :                     // make it across the minor link in one step, new traffic
    3724              :                     // could appear on a major foe link and cause a collision. Refs. #1845, #2123
    3725       873496 :                     vSafeMinDist = dpi.myDistance; // distance that must be covered
    3726       873496 :                     if (MSGlobals::gSemiImplicitEulerUpdate) {
    3727      1583740 :                         vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
    3728              :                     } else {
    3729       163252 :                         vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
    3730              :                     }
    3731              :                     canBrakeVSafeMin = canBrake;
    3732              : #ifdef DEBUG_EXEC_MOVE
    3733              :                     if (DEBUG_COND) {
    3734              :                         std::cout << "     vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
    3735              :                     }
    3736              : #endif
    3737              :                 }
    3738              :             }
    3739              :             // have waited; may pass if opened...
    3740    571236630 :             if (opened) {
    3741    566311922 :                 vSafe = dpi.myVLinkPass;
    3742    566311922 :                 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
    3743              :                     // this vehicle is probably not gonna drive across the next junction (heuristic)
    3744     47948781 :                     myHaveToWaitOnNextLink = true;
    3745              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3746              :                     if (DEBUG_COND) {
    3747              :                         std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
    3748              :                     }
    3749              : #endif
    3750              :                 }
    3751      4924708 :             } else if (link->getState() == LINKSTATE_ZIPPER) {
    3752       817941 :                 vSafeZipper = MIN2(vSafeZipper,
    3753       817941 :                                    link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
    3754              :             } else if (!canBrake
    3755              :                        // always brake hard for traffic lights (since an emergency stop is necessary anyway)
    3756         1684 :                        && link->getTLLogic() == nullptr
    3757              :                        // cannot brake even with emergency deceleration
    3758      4107673 :                        && dpi.myDistance < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0.)) {
    3759              : #ifdef DEBUG_EXEC_MOVE
    3760              :                 if (DEBUG_COND) {
    3761              :                     std::cout << SIMTIME << " too fast to brake for closed link\n";
    3762              :                 }
    3763              : #endif
    3764          238 :                 vSafe = dpi.myVLinkPass;
    3765              :             } else {
    3766      4106529 :                 vSafe = dpi.myVLinkWait;
    3767      4106529 :                 myHaveToWaitOnNextLink = true;
    3768              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3769              :                 if (DEBUG_COND) {
    3770              :                     std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
    3771              :                 }
    3772              : #endif
    3773              : #ifdef DEBUG_EXEC_MOVE
    3774              :                 if (DEBUG_COND) {
    3775              :                     std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
    3776              :                 }
    3777              : #endif
    3778      4106529 :                 break;
    3779              :             }
    3780    586045666 :         } else {
    3781    287840560 :             if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
    3782              :                 // blocked on the junction. yield request so other vehicles may
    3783              :                 // become junction leader
    3784              : #ifdef DEBUG_EXEC_MOVE
    3785              :                 if (DEBUG_COND) {
    3786              :                     std::cout << SIMTIME << " resetting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
    3787              :                 }
    3788              : #endif
    3789       195022 :                 myJunctionEntryTime = SUMOTime_MAX;
    3790       195022 :                 myJunctionConflictEntryTime = SUMOTime_MAX;
    3791              :             }
    3792              :             // we have: i->link == 0 || !i->setRequest
    3793    287840560 :             vSafe = dpi.myVLinkWait;
    3794    287840560 :             if (vSafe < getSpeed()) {
    3795     42940121 :                 myHaveToWaitOnNextLink = true;
    3796              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3797              :                 if (DEBUG_COND) {
    3798              :                     std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
    3799              :                 }
    3800              : #endif
    3801    244900439 :             } else if (vSafe < SUMO_const_haltingSpeed) {
    3802     67650334 :                 myHaveToWaitOnNextLink = true;
    3803              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3804              :                 if (DEBUG_COND) {
    3805              :                     std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
    3806              :                 }
    3807              : #endif
    3808              :             }
    3809    199635231 :             if (link == nullptr && myLFLinkLanes.size() == 1
    3810    142276700 :                     && getBestLanesContinuation().size() > 1
    3811       184907 :                     && getBestLanesContinuation()[1]->hadPermissionChanges()
    3812    287976245 :                     && myLane->getFirstAnyVehicle() == this) {
    3813              :                 // temporal lane closing without notification, visible to the
    3814              :                 // vehicle at the front of the queue
    3815        32480 :                 updateBestLanes(true);
    3816              :                 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
    3817              :             }
    3818              :             break;
    3819              :         }
    3820              :     }
    3821              : 
    3822              : //#ifdef DEBUG_EXEC_MOVE
    3823              : //    if (DEBUG_COND) {
    3824              : //        std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
    3825              : //        std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
    3826              : //        std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
    3827              : //        std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
    3828              : //
    3829              : //        double gap = getLeader().second;
    3830              : //        std::cout << "gap = " << toString(gap, 24) << std::endl;
    3831              : //        std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
    3832              : //                << "\n" << std::endl;
    3833              : //    }
    3834              : //#endif
    3835              : 
    3836    468251663 :     if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
    3837    468049222 :             || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
    3838              :         // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
    3839              :         //      For the Euler update the term '+ NUMERICAL_EPS' prevented a call here... Recheck, consider of -INVALID_SPEED instead of 0 to indicate absence of vSafeMin restrictions. Refs. #2577
    3840              : #ifdef DEBUG_EXEC_MOVE
    3841              :         if (DEBUG_COND) {
    3842              :             std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
    3843              :         }
    3844              : #endif
    3845       241365 :         if (canBrakeVSafeMin && vSafe < getSpeed()) {
    3846              :             // cannot drive across a link so we need to stop before it
    3847       119640 :             vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
    3848        59820 :                                      getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
    3849        59820 :             vSafeMin = 0;
    3850        59820 :             myHaveToWaitOnNextLink = true;
    3851              : #ifdef DEBUG_CHECKREWINDLINKLANES
    3852              :             if (DEBUG_COND) {
    3853              :                 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
    3854              :             }
    3855              : #endif
    3856              :         } else {
    3857              :             // if the link is yellow or visibility distance is large
    3858              :             // then we might not make it across the link in one step anyway..
    3859              :             // Possibly, the lane after the intersection has a lower speed limit so
    3860              :             // we really need to drive slower already
    3861              :             // -> keep driving without dawdling
    3862       181545 :             vSafeMin = vSafe;
    3863              :         }
    3864              :     }
    3865              : 
    3866              :     // vehicles inside a roundabout should maintain their requests
    3867    468251663 :     if (myLane->getEdge().isRoundabout()) {
    3868      2594166 :         myHaveToWaitOnNextLink = false;
    3869              :     }
    3870              : 
    3871    468251663 :     vSafe = MIN2(vSafe, vSafeZipper);
    3872    468251663 : }
    3873              : 
    3874              : 
    3875              : double
    3876    540473461 : MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
    3877    540473461 :     if (myInfluencer != nullptr) {
    3878       467049 :         myInfluencer->setOriginalSpeed(vNext);
    3879              : #ifdef DEBUG_TRACI
    3880              :         if DEBUG_COND2(this) {
    3881              :             std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
    3882              :                       << " vSafe=" << vSafe << " (init)vNext=" << vNext << " keepStopping=" << keepStopping();
    3883              :         }
    3884              : #endif
    3885       467049 :         if (myInfluencer->isRemoteControlled()) {
    3886         7734 :             vNext = myInfluencer->implicitSpeedRemote(this, myState.mySpeed);
    3887              :         }
    3888       467049 :         const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
    3889       467049 :         double vMin = getVehicleType().getCarFollowModel().minNextSpeed(myState.mySpeed, this);
    3890       467049 :         if (MSGlobals::gSemiImplicitEulerUpdate) {
    3891              :             vMin = MAX2(0., vMin);
    3892              :         }
    3893       467049 :         vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
    3894       467049 :         if (keepStopping() && myStops.front().getSpeed() == 0) {
    3895              :             // avoid driving while stopped (unless it's actually a waypoint
    3896          203 :             vNext = myInfluencer->getOriginalSpeed();
    3897              :         }
    3898              : #ifdef DEBUG_TRACI
    3899              :         if DEBUG_COND2(this) {
    3900              :             std::cout << " (processed)vNext=" << vNext << std::endl;
    3901              :         }
    3902              : #endif
    3903              :     }
    3904    540473461 :     return vNext;
    3905              : }
    3906              : 
    3907              : 
    3908              : void
    3909     72221629 : MSVehicle::removePassedDriveItems() {
    3910              : #ifdef DEBUG_ACTIONSTEPS
    3911              :     if (DEBUG_COND) {
    3912              :         std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
    3913              :                   << "    Current items: ";
    3914              :         for (auto& j : myLFLinkLanes) {
    3915              :             if (j.myLink == 0) {
    3916              :                 std::cout << "\n    Stop at distance " << j.myDistance;
    3917              :             } else {
    3918              :                 const MSLane* to = j.myLink->getViaLaneOrLane();
    3919              :                 const MSLane* from = j.myLink->getLaneBefore();
    3920              :                 std::cout << "\n    Link at distance " << j.myDistance << ": '"
    3921              :                           << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
    3922              :             }
    3923              :         }
    3924              :         std::cout << "\n    myNextDriveItem: ";
    3925              :         if (myLFLinkLanes.size() != 0) {
    3926              :             if (myNextDriveItem->myLink == 0) {
    3927              :                 std::cout << "\n    Stop at distance " << myNextDriveItem->myDistance;
    3928              :             } else {
    3929              :                 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
    3930              :                 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
    3931              :                 std::cout << "\n    Link at distance " << myNextDriveItem->myDistance << ": '"
    3932              :                           << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
    3933              :             }
    3934              :         }
    3935              :         std::cout << std::endl;
    3936              :     }
    3937              : #endif
    3938     72548385 :     for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
    3939              : #ifdef DEBUG_ACTIONSTEPS
    3940              :         if (DEBUG_COND) {
    3941              :             std::cout << "    Removing item: ";
    3942              :             if (j->myLink == 0) {
    3943              :                 std::cout << "Stop at distance " << j->myDistance;
    3944              :             } else {
    3945              :                 const MSLane* to = j->myLink->getViaLaneOrLane();
    3946              :                 const MSLane* from = j->myLink->getLaneBefore();
    3947              :                 std::cout << "Link at distance " << j->myDistance << ": '"
    3948              :                           << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
    3949              :             }
    3950              :             std::cout << std::endl;
    3951              :         }
    3952              : #endif
    3953       326756 :         if (j->myLink != nullptr) {
    3954       326688 :             j->myLink->removeApproaching(this);
    3955              :         }
    3956              :     }
    3957     72221629 :     myLFLinkLanes.erase(myLFLinkLanes.begin(), myNextDriveItem);
    3958     72221629 :     myNextDriveItem = myLFLinkLanes.begin();
    3959     72221629 : }
    3960              : 
    3961              : 
    3962              : void
    3963       951649 : MSVehicle::updateDriveItems() {
    3964              : #ifdef DEBUG_ACTIONSTEPS
    3965              :     if (DEBUG_COND) {
    3966              :         std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
    3967              :         for (const auto& dpi : myLFLinkLanes) {
    3968              :             std::cout
    3969              :                     << " vPass=" << dpi.myVLinkPass
    3970              :                     << " vWait=" << dpi.myVLinkWait
    3971              :                     << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
    3972              :                     << " request=" << dpi.mySetRequest
    3973              :                     << "\n";
    3974              :         }
    3975              :         std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
    3976              :     }
    3977              : #endif
    3978       951649 :     if (myLFLinkLanes.size() == 0) {
    3979              :         // nothing to update
    3980              :         return;
    3981              :     }
    3982              :     const MSLink* nextPlannedLink = nullptr;
    3983              : //    auto i = myLFLinkLanes.begin();
    3984       951649 :     auto i = myNextDriveItem;
    3985      1903296 :     while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
    3986       951647 :         nextPlannedLink = i->myLink;
    3987              :         ++i;
    3988              :     }
    3989              : 
    3990       951649 :     if (nextPlannedLink == nullptr) {
    3991              :         // No link for upcoming item -> no need for an update
    3992              : #ifdef DEBUG_ACTIONSTEPS
    3993              :         if (DEBUG_COND) {
    3994              :             std::cout << "Found no link-related drive item." << std::endl;
    3995              :         }
    3996              : #endif
    3997              :         return;
    3998              :     }
    3999              : 
    4000       515817 :     if (getLane() == nextPlannedLink->getLaneBefore()) {
    4001              :         // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
    4002              : #ifdef DEBUG_ACTIONSTEPS
    4003              :         if (DEBUG_COND) {
    4004              :             std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
    4005              :         }
    4006              : #endif
    4007              :         return;
    4008              :     }
    4009              :     // Lane must have been changed, determine the change direction
    4010       506191 :     const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
    4011       506191 :     if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
    4012              :         // lcDir = 1;
    4013              :     } else {
    4014       260897 :         parallelLink = nextPlannedLink->getParallelLink(-1);
    4015       260897 :         if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
    4016              :             // lcDir = -1;
    4017              :         } else {
    4018              :             // If the vehicle's current lane is not the approaching lane for the next
    4019              :             // drive process item's link, it is expected to lead to a parallel link,
    4020              :             // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
    4021              :             //      Then a stop item should be scheduled! -> TODO!
    4022              :             //assert(false);
    4023        74375 :             return;
    4024              :         }
    4025              :     }
    4026              : #ifdef DEBUG_ACTIONSTEPS
    4027              :     if (DEBUG_COND) {
    4028              :         std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
    4029              :     }
    4030              : #endif
    4031              :     // Trace link sequence along current best lanes and transfer drive items to the corresponding links
    4032              : //        DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
    4033       431816 :     DriveItemVector::iterator driveItemIt = myNextDriveItem;
    4034              :     // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
    4035       431816 :     const MSLane* lane = myLane;
    4036              :     assert(myLane == parallelLink->getLaneBefore());
    4037              :     // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
    4038       431816 :     std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
    4039              :     // Pointer to the new link for the current drive process item
    4040              :     MSLink* newLink = nullptr;
    4041      1617850 :     while (driveItemIt != myLFLinkLanes.end()) {
    4042      1208874 :         if (driveItemIt->myLink == nullptr) {
    4043              :             // Items not related to a specific link are not updated
    4044              :             // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
    4045              :             //       the update necessary, this may slow down the vehicle's continuation on the new lane...)
    4046              :             ++driveItemIt;
    4047       155377 :             continue;
    4048              :         }
    4049              :         // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
    4050              :         // We just remove the leftover link-items, as they cannot be mapped to new links.
    4051      1053497 :         if (bestLaneIt == getBestLanesContinuation().end()) {
    4052              : #ifdef DEBUG_ACTIONSTEPS
    4053              :             if (DEBUG_COND) {
    4054              :                 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
    4055              :             }
    4056              : #endif
    4057        68045 :             while (driveItemIt != myLFLinkLanes.end()) {
    4058        45205 :                 if (driveItemIt->myLink == nullptr) {
    4059              :                     ++driveItemIt;
    4060        13215 :                     continue;
    4061              :                 } else {
    4062        31990 :                     driveItemIt->myLink->removeApproaching(this);
    4063              :                     driveItemIt = myLFLinkLanes.erase(driveItemIt);
    4064              :                 }
    4065              :             }
    4066              :             break;
    4067              :         }
    4068              :         // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
    4069      1030657 :         const MSLane* const target = *bestLaneIt;
    4070              :         assert(!target->isInternal());
    4071              :         newLink = nullptr;
    4072      1148694 :         for (MSLink* const link : lane->getLinkCont()) {
    4073      1148694 :             if (link->getLane() == target) {
    4074              :                 newLink = link;
    4075              :                 break;
    4076              :             }
    4077              :         }
    4078              : 
    4079      1030657 :         if (newLink == driveItemIt->myLink) {
    4080              :             // new continuation merged into previous - stop update
    4081              : #ifdef DEBUG_ACTIONSTEPS
    4082              :             if (DEBUG_COND) {
    4083              :                 std::cout << "Old and new continuation sequences merge at link\n"
    4084              :                           << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
    4085              :                           << "\nNo update beyond merge required." << std::endl;
    4086              :             }
    4087              : #endif
    4088              :             break;
    4089              :         }
    4090              : 
    4091              : #ifdef DEBUG_ACTIONSTEPS
    4092              :         if (DEBUG_COND) {
    4093              :             std::cout << "lane=" << lane->getID() << "\nUpdating link\n    '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
    4094              :                       << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
    4095              :         }
    4096              : #endif
    4097      1030657 :         newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
    4098      1030657 :         driveItemIt->myLink->removeApproaching(this);
    4099      1030657 :         driveItemIt->myLink = newLink;
    4100              :         lane = newLink->getViaLaneOrLane();
    4101              :         ++driveItemIt;
    4102      1030657 :         if (!lane->isInternal()) {
    4103              :             ++bestLaneIt;
    4104              :         }
    4105              :     }
    4106              : #ifdef DEBUG_ACTIONSTEPS
    4107              :     if (DEBUG_COND) {
    4108              :         std::cout << "Updated drive items:" << std::endl;
    4109              :         for (const auto& dpi : myLFLinkLanes) {
    4110              :             std::cout
    4111              :                     << " vPass=" << dpi.myVLinkPass
    4112              :                     << " vWait=" << dpi.myVLinkWait
    4113              :                     << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
    4114              :                     << " request=" << dpi.mySetRequest
    4115              :                     << "\n";
    4116              :         }
    4117              :     }
    4118              : #endif
    4119              : }
    4120              : 
    4121              : 
    4122              : void
    4123    540473461 : MSVehicle::setBrakingSignals(double vNext) {
    4124              :     // To avoid casual blinking brake lights at high speeds due to dawdling of the
    4125              :     // leading vehicle, we don't show brake lights when the deceleration could be caused
    4126              :     // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
    4127    540473461 :     double pseudoFriction = (0.05 +  0.005 * getSpeed()) * getSpeed();
    4128    540473461 :     bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
    4129              : 
    4130    540473461 :     if (vNext <= SUMO_const_haltingSpeed) {
    4131              :         brakelightsOn = true;
    4132              :     }
    4133    540473461 :     if (brakelightsOn && !isStopped()) {
    4134              :         switchOnSignal(VEH_SIGNAL_BRAKELIGHT);
    4135              :     } else {
    4136              :         switchOffSignal(VEH_SIGNAL_BRAKELIGHT);
    4137              :     }
    4138    540473461 : }
    4139              : 
    4140              : 
    4141              : void
    4142    540547878 : MSVehicle::updateWaitingTime(double vNext) {
    4143    540547878 :     if (vNext <= SUMO_const_haltingSpeed && (!isStopped() || isIdling()) && myAcceleration <= accelThresholdForWaiting())  {
    4144     78126840 :         myWaitingTime += DELTA_T;
    4145     78126840 :         myWaitingTimeCollector.passTime(DELTA_T, true);
    4146              :     } else {
    4147    462421038 :         myWaitingTime = 0;
    4148    462421038 :         myWaitingTimeCollector.passTime(DELTA_T, false);
    4149    462421038 :         if (hasInfluencer()) {
    4150       266683 :             getInfluencer().setExtraImpatience(0);
    4151              :         }
    4152              :     }
    4153    540547878 : }
    4154              : 
    4155              : 
    4156              : void
    4157    540473289 : MSVehicle::updateTimeLoss(double vNext) {
    4158              :     // update time loss (depends on the updated edge)
    4159    540473289 :     if (!isStopped()) {
    4160    527101479 :         const double vmax = myLane->getVehicleMaxSpeed(this);
    4161    527101479 :         if (vmax > 0) {
    4162    527094279 :             myTimeLoss += TS * (vmax - vNext) / vmax;
    4163              :         }
    4164              :     }
    4165    540473289 : }
    4166              : 
    4167              : 
    4168              : double
    4169   1306939938 : MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
    4170     42354934 :     const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
    4171   1324968292 :                          || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
    4172              : #ifdef DEBUG_REVERSE_BIDI
    4173              :     if (DEBUG_COND) std::cout << SIMTIME  << " checkReversal lane=" << myLane->getID()
    4174              :                                   << " pos=" << myState.myPos
    4175              :                                   << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
    4176              :                                   << " speedThreshold=" << speedThreshold
    4177              :                                   << " seen=" << seen
    4178              :                                   << " isRail=" << ((getVClass() & SVC_RAIL_CLASSES) != 0)
    4179              :                                   << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
    4180              :                                   << " posOK=" << (myState.myPos <= myLane->getLength())
    4181              :                                   << " normal=" << !myLane->isInternal()
    4182              :                                   << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
    4183              :                                   << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
    4184              :                                   << " stopOk=" << stopOk
    4185              :                                   << "\n";
    4186              : #endif
    4187   1306939938 :     if ((getVClass() & SVC_RAIL_CLASSES) != 0
    4188      3457614 :             && getPreviousSpeed() <= speedThreshold
    4189      2695097 :             && myState.myPos <= myLane->getLength()
    4190      2694163 :             && !myLane->isInternal()
    4191      2633405 :             && (myCurrEdge + 1) != myRoute->end()
    4192      2559732 :             && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
    4193              :             // ensure there are no further stops on this edge
    4194   1306995030 :             && stopOk
    4195              :        ) {
    4196              :         //if (isSelected()) std::cout << "   check1 passed\n";
    4197              : 
    4198              :         // ensure that the vehicle is fully on bidi edges that allow reversal
    4199        18540 :         const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
    4200              :                                                 ? myFurtherLanes.size()
    4201          504 :                                                 : ceil((double)myFurtherLanes.size() / 2.0));
    4202        18540 :         const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
    4203        18540 :         if (remainingRoute < neededFutureRoute) {
    4204              : #ifdef DEBUG_REVERSE_BIDI
    4205              :             if (DEBUG_COND) {
    4206              :                 std::cout << "    fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
    4207              :             }
    4208              : #endif
    4209         3513 :             return getMaxSpeed();
    4210              :         }
    4211              :         //if (isSelected()) std::cout << "   check2 passed\n";
    4212              : 
    4213              :         // ensure that the turn-around connection exists from the current edge to its bidi-edge
    4214        15027 :         const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
    4215        15027 :         if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
    4216              : #ifdef DEBUG_REVERSE_BIDI
    4217              :             if (DEBUG_COND) {
    4218              :                 std::cout << "    noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
    4219              :             }
    4220              : #endif
    4221          909 :             return getMaxSpeed();
    4222              :         }
    4223              :         //if (isSelected()) std::cout << "   check3 passed\n";
    4224              : 
    4225              :         // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
    4226        14118 :         if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
    4227         2178 :             const double stopPos = myStops.front().getEndPos(*this);
    4228         2178 :             const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
    4229         2178 :             const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
    4230         2178 :             if (newPos > stopPos) {
    4231              : #ifdef DEBUG_REVERSE_BIDI
    4232              :                 if (DEBUG_COND) {
    4233              :                     std::cout << "    reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
    4234              :                 }
    4235              : #endif
    4236          504 :                 if (seen > MAX2(brakeDist, 1.0)) {
    4237          474 :                     return getMaxSpeed();
    4238              :                 } else {
    4239              : #ifdef DEBUG_REVERSE_BIDI
    4240              :                     if (DEBUG_COND) {
    4241              :                         std::cout << "    train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
    4242              :                     }
    4243              : #endif
    4244              :                 }
    4245              :             }
    4246              :         }
    4247              :         //if (isSelected()) std::cout << "   check4 passed\n";
    4248              : 
    4249              :         // ensure that bidi-edges exist for all further edges
    4250              :         // and that no stops will be skipped when reversing
    4251              :         // and that the train will not be on top of a red rail signal after reversal
    4252        13644 :         const MSLane* bidi = myLane->getBidiLane();
    4253              :         int view = 2;
    4254        28198 :         for (MSLane* further : myFurtherLanes) {
    4255        16111 :             if (!further->getEdge().isInternal()) {
    4256         8626 :                 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
    4257              : #ifdef DEBUG_REVERSE_BIDI
    4258              :                     if (DEBUG_COND) {
    4259              :                         std::cout << "    noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
    4260              :                     }
    4261              : #endif
    4262         1398 :                     return getMaxSpeed();
    4263              :                 }
    4264         7228 :                 const MSLane* nextBidi = further->getBidiLane();
    4265         7228 :                 const MSLink* toNext = bidi->getLinkTo(nextBidi);
    4266         7228 :                 if (toNext == nullptr) {
    4267              :                     // can only happen if the route is invalid
    4268            0 :                     return getMaxSpeed();
    4269              :                 }
    4270         7228 :                 if (toNext->haveRed()) {
    4271              : #ifdef DEBUG_REVERSE_BIDI
    4272              :                     if (DEBUG_COND) {
    4273              :                         std::cout << "    do not reverse on a red signal\n";
    4274              :                     }
    4275              : #endif
    4276            0 :                     return getMaxSpeed();
    4277              :                 }
    4278              :                 bidi = nextBidi;
    4279         7228 :                 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
    4280          453 :                     const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
    4281          453 :                     const double stopPos = myStops.front().getEndPos(*this);
    4282          453 :                     const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
    4283          453 :                     if (newPos > stopPos) {
    4284              : #ifdef DEBUG_REVERSE_BIDI
    4285              :                         if (DEBUG_COND) {
    4286              :                             std::cout << "    reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
    4287              :                         }
    4288              : #endif
    4289          171 :                         if (seen > MAX2(brakeDist, 1.0)) {
    4290          159 :                             canReverse = false;
    4291          159 :                             return getMaxSpeed();
    4292              :                         } else {
    4293              : #ifdef DEBUG_REVERSE_BIDI
    4294              :                             if (DEBUG_COND) {
    4295              :                                 std::cout << "    train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
    4296              :                             }
    4297              : #endif
    4298              :                         }
    4299              :                     }
    4300              :                 }
    4301         7069 :                 view++;
    4302              :             }
    4303              :         }
    4304              :         // reverse as soon as comfortably possible
    4305        12087 :         const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
    4306              : #ifdef DEBUG_REVERSE_BIDI
    4307              :         if (DEBUG_COND) {
    4308              :             std::cout << SIMTIME << " seen=" << seen  << " vReverseOK=" << vMinComfortable << "\n";
    4309              :         }
    4310              : #endif
    4311        12087 :         canReverse = true;
    4312        12087 :         return vMinComfortable;
    4313              :     }
    4314   1306921398 :     return getMaxSpeed();
    4315              : }
    4316              : 
    4317              : 
    4318              : void
    4319    540558405 : MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
    4320    553438484 :     for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
    4321     12880079 :         passedLanes.push_back(*i);
    4322              :     }
    4323    540558405 :     if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
    4324    540558405 :         passedLanes.push_back(myLane);
    4325              :     }
    4326              :     // let trains reverse direction
    4327    540558405 :     bool reverseTrain = false;
    4328    540558405 :     checkReversal(reverseTrain);
    4329    540558405 :     if (reverseTrain) {
    4330              :         // Train is 'reversing' so toggle the logical state
    4331          289 :         myAmReversed = !myAmReversed;
    4332              :         // add some slack to ensure that the back of train does appear looped
    4333          289 :         myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
    4334          289 :         myState.mySpeed = 0;
    4335              : #ifdef DEBUG_REVERSE_BIDI
    4336              :         if (DEBUG_COND) {
    4337              :             std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
    4338              :         }
    4339              : #endif
    4340              :     }
    4341              :     // move on lane(s)
    4342    540558405 :     if (myState.myPos > myLane->getLength()) {
    4343              :         // The vehicle has moved at least to the next lane (maybe it passed even more than one)
    4344     16727924 :         if (myCurrEdge != myRoute->end() - 1) {
    4345     14374352 :             MSLane* approachedLane = myLane;
    4346              :             // move the vehicle forward
    4347     14374352 :             myNextDriveItem = myLFLinkLanes.begin();
    4348     31177647 :             while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
    4349     16818472 :                 const MSLink* link = myNextDriveItem->myLink;
    4350     16818472 :                 const double linkDist = myNextDriveItem->myDistance;
    4351              :                 ++myNextDriveItem;
    4352              :                 // check whether the vehicle was allowed to enter lane
    4353              :                 //  otherwise it is decelerated and we do not need to test for it's
    4354              :                 //  approach on the following lanes when a lane changing is performed
    4355              :                 // proceed to the next lane
    4356     16818472 :                 if (approachedLane->mustCheckJunctionCollisions()) {
    4357              :                     // vehicle moves past approachedLane within a single step, collision checking must still be done
    4358        54834 :                     MSNet::getInstance()->getEdgeControl().checkCollisionForInactive(approachedLane);
    4359              :                 }
    4360     16818472 :                 if (link != nullptr) {
    4361     16815643 :                     if ((getVClass() & SVC_RAIL_CLASSES) != 0
    4362        33796 :                             && !myLane->isInternal()
    4363        17940 :                             && myLane->getBidiLane() != nullptr
    4364        10782 :                             && link->getLane()->getBidiLane() == myLane
    4365     16815929 :                             && !reverseTrain) {
    4366              :                         emergencyReason = " because it must reverse direction";
    4367              :                         approachedLane = nullptr;
    4368              :                         break;
    4369              :                     }
    4370     16815640 :                     if ((getVClass() & SVC_RAIL_CLASSES) != 0
    4371        33793 :                             && myState.myPos < myLane->getLength() + NUMERICAL_EPS
    4372     16815833 :                             && hasStops() && getNextStop().edge == myCurrEdge) {
    4373              :                         // avoid skipping stop due to numerical instability
    4374              :                         // this is a special case for rail vehicles because they
    4375              :                         // continue myLFLinkLanes past stops
    4376          170 :                         approachedLane = myLane;
    4377          170 :                         myState.myPos = myLane->getLength();
    4378          170 :                         break;
    4379              :                     }
    4380     16815470 :                     approachedLane = link->getViaLaneOrLane();
    4381     16815470 :                     if (myInfluencer == nullptr || myInfluencer->getEmergencyBrakeRedLight()) {
    4382     16813995 :                         bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
    4383     16813995 :                         if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
    4384              :                             emergencyReason = " because of a red traffic light";
    4385              :                             break;
    4386              :                         }
    4387              :                     }
    4388     16815416 :                     if (reverseTrain && approachedLane->isInternal()) {
    4389              :                         // avoid getting stuck on a slow turn-around internal lane
    4390          341 :                         myState.myPos += approachedLane->getLength();
    4391              :                     }
    4392         2829 :                 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
    4393              :                     // avoid warning due to numerical instability
    4394          166 :                     approachedLane = myLane;
    4395          166 :                     myState.myPos = myLane->getLength();
    4396         2663 :                 } else if (reverseTrain) {
    4397            0 :                     approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
    4398            0 :                     link = myLane->getLinkTo(approachedLane);
    4399              :                     assert(link != 0);
    4400            0 :                     while (link->getViaLane() != nullptr) {
    4401            0 :                         link = link->getViaLane()->getLinkCont()[0];
    4402              :                     }
    4403              :                     --myNextDriveItem;
    4404              :                 } else {
    4405              :                     emergencyReason = " because there is no connection to the next edge";
    4406              :                     approachedLane = nullptr;
    4407              :                     break;
    4408              :                 }
    4409     16815582 :                 if (approachedLane != myLane && approachedLane != nullptr) {
    4410     16815416 :                     leaveLane(MSMoveReminder::NOTIFICATION_JUNCTION, approachedLane);
    4411     16815416 :                     myState.myPos -= myLane->getLength();
    4412              :                     assert(myState.myPos > 0);
    4413     16815416 :                     enterLaneAtMove(approachedLane);
    4414     16815416 :                     if (link->isEntryLink()) {
    4415      6375625 :                         myJunctionEntryTime = MSNet::getInstance()->getCurrentTimeStep();
    4416      6375625 :                         myJunctionEntryTimeNeverYield = myJunctionEntryTime;
    4417              :                     }
    4418     16815416 :                     if (link->isConflictEntryLink()) {
    4419      6375255 :                         myJunctionConflictEntryTime = MSNet::getInstance()->getCurrentTimeStep();
    4420              :                         // renew yielded request
    4421      6375255 :                         myJunctionEntryTime = myJunctionEntryTimeNeverYield;
    4422              :                     }
    4423     16815416 :                     if (link->isExitLink()) {
    4424              :                         // passed junction, reset for approaching the next one
    4425      6316428 :                         myJunctionEntryTime = SUMOTime_MAX;
    4426      6316428 :                         myJunctionEntryTimeNeverYield = SUMOTime_MAX;
    4427      6316428 :                         myJunctionConflictEntryTime = SUMOTime_MAX;
    4428              :                     }
    4429              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    4430              :                     if (DEBUG_COND) {
    4431              :                         std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
    4432              :                                   << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
    4433              :                                   << " ET=" << myJunctionEntryTime
    4434              :                                   << " ETN=" << myJunctionEntryTimeNeverYield
    4435              :                                   << " CET=" << myJunctionConflictEntryTime
    4436              :                                   << "\n";
    4437              :                     }
    4438              : #endif
    4439     16815416 :                     if (hasArrivedInternal()) {
    4440              :                         break;
    4441              :                     }
    4442     16803885 :                     if (myLaneChangeModel->isChangingLanes()) {
    4443         6651 :                         if (link->getDirection() == LinkDirection::LEFT || link->getDirection() == LinkDirection::RIGHT) {
    4444              :                             // abort lane change
    4445            0 :                             WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
    4446              :                                           time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    4447            0 :                             myLaneChangeModel->endLaneChangeManeuver();
    4448              :                         }
    4449              :                     }
    4450     16803885 :                     if (approachedLane->getEdge().isVaporizing()) {
    4451          756 :                         leaveLane(MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER);
    4452              :                         break;
    4453              :                     }
    4454     16803129 :                     passedLanes.push_back(approachedLane);
    4455              :                 }
    4456              :             }
    4457              :             // NOTE: Passed drive items will be erased in the next simstep's planMove()
    4458              : 
    4459              : #ifdef DEBUG_ACTIONSTEPS
    4460              :             if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
    4461              :                 std::cout << "Updated drive items:" << std::endl;
    4462              :                 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
    4463              :                     std::cout
    4464              :                             << " vPass=" << (*i).myVLinkPass
    4465              :                             << " vWait=" << (*i).myVLinkWait
    4466              :                             << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
    4467              :                             << " request=" << (*i).mySetRequest
    4468              :                             << "\n";
    4469              :                 }
    4470              :             }
    4471              : #endif
    4472      2353572 :         } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
    4473              :             // avoid warning due to numerical instability when stopping at the end of the route
    4474           56 :             myState.myPos = myLane->getLength();
    4475              :         }
    4476              : 
    4477              :     }
    4478    540558405 : }
    4479              : 
    4480              : 
    4481              : 
    4482              : bool
    4483    540473297 : MSVehicle::executeMove() {
    4484              : #ifdef DEBUG_EXEC_MOVE
    4485              :     if (DEBUG_COND) {
    4486              :         std::cout << "\nEXECUTE_MOVE\n"
    4487              :                   << SIMTIME
    4488              :                   << " veh=" << getID()
    4489              :                   << " speed=" << getSpeed() // toString(getSpeed(), 24)
    4490              :                   << std::endl;
    4491              :     }
    4492              : #endif
    4493              : 
    4494              : 
    4495              :     // Maximum safe velocity
    4496    540473297 :     double vSafe = std::numeric_limits<double>::max();
    4497              :     // Minimum safe velocity (lower bound).
    4498    540473297 :     double vSafeMin = -std::numeric_limits<double>::max();
    4499              :     // The distance to a link, which should either be crossed this step
    4500              :     // or in front of which we need to stop.
    4501    540473297 :     double vSafeMinDist = 0;
    4502              : 
    4503    540473297 :     if (myActionStep) {
    4504              :         // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
    4505    468251668 :         processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
    4506              : #ifdef DEBUG_ACTIONSTEPS
    4507              :         if (DEBUG_COND) {
    4508              :             std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
    4509              :                       "   vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
    4510              :         }
    4511              : #endif
    4512              :     } else {
    4513              :         // Continue with current acceleration
    4514     72221629 :         vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
    4515              : #ifdef DEBUG_ACTIONSTEPS
    4516              :         if (DEBUG_COND) {
    4517              :             std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
    4518              :                       "   continues with constant accel " <<  myAcceleration << "...\n"
    4519              :                       << "speed: "  << getSpeed() << " -> " << vSafe << std::endl;
    4520              :         }
    4521              : #endif
    4522              :     }
    4523              : 
    4524              : 
    4525              : //#ifdef DEBUG_EXEC_MOVE
    4526              : //    if (DEBUG_COND) {
    4527              : //        std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
    4528              : //    }
    4529              : //#endif
    4530              : 
    4531              :     // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
    4532              :     // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
    4533    540473292 :     double vNext = vSafe;
    4534    540473292 :     const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
    4535    540473292 :     if (vNext <= SUMO_const_haltingSpeed * TS && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting() && myActionStep) {
    4536     62778342 :         myTimeSinceStartup = 0;
    4537    477694950 :     } else if (isStopped()) {
    4538              :         // do not apply startupDelay for waypoints
    4539     13361370 :         if (getCarFollowModel().startupDelayStopped() && getNextStop().pars.speed <= 0) {
    4540        12452 :             myTimeSinceStartup = DELTA_T;
    4541              :         } else {
    4542              :             // do not apply startupDelay but signal that a stop has taken place
    4543     13348918 :             myTimeSinceStartup = getCarFollowModel().getStartupDelay() + DELTA_T;
    4544              :         }
    4545              :     } else {
    4546              :         // identify potential startup (before other effects reduce the speed again)
    4547    464333580 :         myTimeSinceStartup += DELTA_T;
    4548              :     }
    4549    540473292 :     if (myActionStep) {
    4550    468251663 :         vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
    4551    468251660 :         if (vNext > 0) {
    4552    427852214 :             vNext = MAX2(vNext, vSafeMin);
    4553              :         }
    4554              :     }
    4555              :     // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
    4556              :     //       (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
    4557              :     // (Jakob) We also need to make sure to reach a stop at the start of the next edge
    4558    540473289 :     if (fabs(vNext) < NUMERICAL_EPS_SPEED && myStopDist > POSITION_EPS) {
    4559              :         vNext = 0.;
    4560              :     }
    4561              : #ifdef DEBUG_EXEC_MOVE
    4562              :     if (DEBUG_COND) {
    4563              :         std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
    4564              :                   << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
    4565              :     }
    4566              : #endif
    4567              : 
    4568              :     // vNext may be higher than vSafe without implying a bug:
    4569              :     //  - when approaching a green light that suddenly switches to yellow
    4570              :     //  - when using unregulated junctions
    4571              :     //  - when using tau < step-size
    4572              :     //  - when using unsafe car following models
    4573              :     //  - when using TraCI and some speedMode / laneChangeMode settings
    4574              :     //if (vNext > vSafe + NUMERICAL_EPS) {
    4575              :     //    WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
    4576              :     //            + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
    4577              :     //            + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    4578              :     //}
    4579              : 
    4580    540473289 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
    4581              :         vNext = MAX2(vNext, 0.);
    4582              :     } else {
    4583              :         // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
    4584              :     }
    4585              : 
    4586              :     // Check for speed advices from the traci client
    4587    540473289 :     vNext = processTraCISpeedControl(vSafe, vNext);
    4588              : 
    4589              :     // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
    4590    540473289 :     MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    4591         1135 :     if (elecHybridOfVehicle != nullptr) {
    4592              :         // this is the consumption given by the car following model-computed acceleration
    4593         1135 :         elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
    4594              :         // but the maximum power of the electric motor may be lower
    4595              :         // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
    4596         1135 :         double maxPower = elecHybridOfVehicle->getParameterDouble(toString(SUMO_ATTR_MAXIMUMPOWER)) / 3600;
    4597         1135 :         if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
    4598              :             // no, we cannot accelerate that fast, recompute the maximum possible acceleration
    4599           71 :             double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
    4600              :             // and update the speed of the vehicle
    4601           71 :             vNext = MIN2(vNext, this->getSpeed() + accel * TS);
    4602              :             vNext = MAX2(vNext, 0.);
    4603              :             // and set the vehicle consumption to reflect this
    4604           71 :             elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
    4605              :         }
    4606              :     }
    4607              : 
    4608    540473289 :     setBrakingSignals(vNext);
    4609              : 
    4610              :     // update position and speed
    4611    540473289 :     int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
    4612              :     const MSLane* oldLaneMaybeOpposite = myLane;
    4613    540473289 :     if (myLaneChangeModel->isOpposite()) {
    4614              :         // transform to the forward-direction lane, move and then transform back
    4615       407414 :         myState.myPos = myLane->getOppositePos(myState.myPos);
    4616       407414 :         myLane = myLane->getParallelOpposite();
    4617              :     }
    4618    540473289 :     updateState(vNext);
    4619    540473289 :     updateWaitingTime(vNext);
    4620              : 
    4621              :     // Lanes, which the vehicle touched at some moment of the executed simstep
    4622              :     std::vector<MSLane*> passedLanes;
    4623              :     // remember previous lane (myLane is updated in processLaneAdvances)
    4624    540473289 :     const MSLane* oldLane = myLane;
    4625              :     // Reason for a possible emergency stop
    4626              :     std::string emergencyReason;
    4627    540473289 :     processLaneAdvances(passedLanes, emergencyReason);
    4628              : 
    4629    540473289 :     updateTimeLoss(vNext);
    4630    540473289 :     myCollisionImmunity = MAX2((SUMOTime) - 1, myCollisionImmunity - DELTA_T);
    4631              : 
    4632    540473289 :     if (!hasArrivedInternal() && !myLane->getEdge().isVaporizing()) {
    4633    537967223 :         if (myState.myPos > myLane->getLength()) {
    4634          275 :             if (emergencyReason == "") {
    4635           35 :                 emergencyReason = TL(" for unknown reasons");
    4636              :             }
    4637         1100 :             WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
    4638              :                            getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
    4639              :                            myState.myPos - myLane->getLength(), time2string(SIMSTEP));
    4640          275 :             MSNet::getInstance()->getVehicleControl().registerEmergencyStop();
    4641          275 :             MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::EMERGENCYSTOP);
    4642          275 :             myState.myPos = myLane->getLength();
    4643          275 :             myState.mySpeed = 0;
    4644          275 :             myAcceleration = 0;
    4645              :         }
    4646    537967223 :         const MSLane* oldBackLane = getBackLane();
    4647    537967223 :         if (myLaneChangeModel->isOpposite()) {
    4648              :             passedLanes.clear(); // ignore back occupation
    4649              :         }
    4650              : #ifdef DEBUG_ACTIONSTEPS
    4651              :         if (DEBUG_COND) {
    4652              :             std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
    4653              :         }
    4654              : #endif
    4655    537967223 :         myState.myBackPos = updateFurtherLanes(myFurtherLanes, myFurtherLanesPosLat, passedLanes);
    4656    537967223 :         if (passedLanes.size() > 1 && isRailway(getVClass())) {
    4657       636994 :             for (auto pi = passedLanes.rbegin(); pi != passedLanes.rend(); ++pi) {
    4658       479699 :                 MSLane* pLane = *pi;
    4659       479699 :                 if (pLane != myLane && std::find(myFurtherLanes.begin(), myFurtherLanes.end(), pLane) == myFurtherLanes.end()) {
    4660        33956 :                     leaveLaneBack(MSMoveReminder::NOTIFICATION_JUNCTION, *pi);
    4661              :                 }
    4662              :             }
    4663              :         }
    4664              :         // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
    4665    537967223 :         updateBestLanes();
    4666    537967223 :         if (myLane != oldLane || oldBackLane != getBackLane()) {
    4667     20806928 :             if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
    4668              :                 // shadow lane must be updated if the front or back lane changed
    4669              :                 // either if we already have a shadowLane or if there is lateral overlap
    4670       410486 :                 myLaneChangeModel->updateShadowLane();
    4671              :             }
    4672     20806928 :             if (MSGlobals::gLateralResolution > 0 && !myLaneChangeModel->isOpposite()) {
    4673              :                 // The vehicles target lane must be also be updated if the front or back lane changed
    4674      4101741 :                 myLaneChangeModel->updateTargetLane();
    4675              :             }
    4676              :         }
    4677    537967223 :         setBlinkerInformation(); // needs updated bestLanes
    4678              :         //change the blue light only for emergency vehicles SUMOVehicleClass
    4679    537967223 :         if (myType->getVehicleClass() == SVC_EMERGENCY) {
    4680        72477 :             setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
    4681              :         }
    4682              :         // must be done before angle computation
    4683              :         // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
    4684    537967223 :         if (myActionStep) {
    4685              :             // check (#2681): Can this be skipped?
    4686    465766748 :             myLaneChangeModel->prepareStep();
    4687              :         } else {
    4688     72200475 :             myLaneChangeModel->resetSpeedLat();
    4689              : #ifdef DEBUG_ACTIONSTEPS
    4690              :             if (DEBUG_COND) {
    4691              :                 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
    4692              :             }
    4693              : #endif
    4694              :         }
    4695    537967223 :         myLaneChangeModel->setPreviousAngleOffset(myLaneChangeModel->getAngleOffset());
    4696    537967223 :         myAngle = computeAngle();
    4697              :     }
    4698              : 
    4699              : #ifdef DEBUG_EXEC_MOVE
    4700              :     if (DEBUG_COND) {
    4701              :         std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
    4702              :         gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
    4703              :     }
    4704              : #endif
    4705    540473289 :     if (myLaneChangeModel->isOpposite()) {
    4706              :         // transform back to the opposite-direction lane
    4707              :         MSLane* newOpposite = nullptr;
    4708       407414 :         const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
    4709       407414 :         if (newOppositeEdge != nullptr) {
    4710       407385 :             newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
    4711              : #ifdef DEBUG_EXEC_MOVE
    4712              :             if (DEBUG_COND) {
    4713              :                 std::cout << SIMTIME << "   newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
    4714              :             }
    4715              : #endif
    4716              :         }
    4717       407385 :         if (newOpposite == nullptr) {
    4718           29 :             if (!myLaneChangeModel->hasBlueLight()) {
    4719              :                 // unusual overtaking at junctions is ok for emergency vehicles
    4720            0 :                 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
    4721              :                                getID(), myLane->getID(), time2string(SIMSTEP));
    4722              :             }
    4723           29 :             myLaneChangeModel->changedToOpposite();
    4724           29 :             if (myState.myPos < getLength()) {
    4725              :                 // further lanes is always cleared during opposite driving
    4726           29 :                 MSLane* oldOpposite = oldLane->getOpposite();
    4727           29 :                 if (oldOpposite != nullptr) {
    4728           29 :                     myFurtherLanes.push_back(oldOpposite);
    4729           29 :                     myFurtherLanesPosLat.push_back(0);
    4730              :                     // small value since the lane is going in the other direction
    4731           29 :                     myState.myBackPos = getLength() - myState.myPos;
    4732           29 :                     myAngle = computeAngle();
    4733              :                 } else {
    4734              :                     SOFT_ASSERT(false);
    4735              :                 }
    4736              :             }
    4737              :         } else {
    4738       407385 :             myState.myPos = myLane->getOppositePos(myState.myPos);
    4739       407385 :             myLane = newOpposite;
    4740              :             oldLane = oldLaneMaybeOpposite;
    4741              :             //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
    4742       407385 :             myCachedPosition = Position::INVALID;
    4743       407385 :             myLaneChangeModel->updateShadowLane();
    4744              :         }
    4745              :     }
    4746    540473289 :     workOnMoveReminders(myState.myPos - myState.myLastCoveredDist, myState.myPos, myState.mySpeed);
    4747              :     // Return whether the vehicle did move to another lane
    4748   1080946578 :     return myLane != oldLane;
    4749    540473289 : }
    4750              : 
    4751              : void
    4752        85116 : MSVehicle::executeFractionalMove(double dist) {
    4753        85116 :     myState.myPos += dist;
    4754        85116 :     myState.myLastCoveredDist = dist;
    4755        85116 :     myCachedPosition = Position::INVALID;
    4756              : 
    4757        85116 :     const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
    4758        85116 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    4759       186237 :     for (int i = 0; i < (int)lanes.size(); i++) {
    4760       101121 :         MSLink* link = nullptr;
    4761       101121 :         if (i + 1 < (int)lanes.size()) {
    4762        16005 :             const MSLane* const to = lanes[i + 1];
    4763        16005 :             const bool internal = to->isInternal();
    4764        16010 :             for (MSLink* const l : lanes[i]->getLinkCont()) {
    4765        16010 :                 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
    4766        16005 :                     link = l;
    4767        16005 :                     break;
    4768              :                 }
    4769              :             }
    4770              :         }
    4771       101121 :         myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
    4772              :     }
    4773              :     // minimum execute move:
    4774              :     std::vector<MSLane*> passedLanes;
    4775              :     // Reason for a possible emergency stop
    4776        85116 :     if (lanes.size() > 1) {
    4777         4005 :         myLane->removeVehicle(this, MSMoveReminder::NOTIFICATION_JUNCTION, false);
    4778              :     }
    4779              :     std::string emergencyReason;
    4780        85116 :     processLaneAdvances(passedLanes, emergencyReason);
    4781              : #ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
    4782              :     if (DEBUG_COND) {
    4783              :         std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
    4784              :                   << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
    4785              :                   << " finalPos=" << myState.myPos
    4786              :                   << " speed=" << getSpeed()
    4787              :                   << " myFurtherLanes=" << toString(myFurtherLanes)
    4788              :                   << "\n";
    4789              :     }
    4790              : #endif
    4791        85116 :     workOnMoveReminders(myState.myPos - myState.myLastCoveredDist, myState.myPos, myState.mySpeed);
    4792        85116 :     if (lanes.size() > 1) {
    4793         4010 :         for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
    4794              : #ifdef DEBUG_FURTHER
    4795              :             if (DEBUG_COND) {
    4796              :                 std::cout << SIMTIME << " leaveLane \n";
    4797              :             }
    4798              : #endif
    4799            5 :             (*i)->resetPartialOccupation(this);
    4800              :         }
    4801              :         myFurtherLanes.clear();
    4802              :         myFurtherLanesPosLat.clear();
    4803         4005 :         myLane->forceVehicleInsertion(this, getPositionOnLane(), MSMoveReminder::NOTIFICATION_JUNCTION, getLateralPositionOnLane());
    4804              :     }
    4805        85116 : }
    4806              : 
    4807              : 
    4808              : void
    4809    547996509 : MSVehicle::updateState(double vNext) {
    4810              :     // update position and speed
    4811              :     double deltaPos; // positional change
    4812    547996509 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
    4813              :         // euler
    4814    448735316 :         deltaPos = SPEED2DIST(vNext);
    4815              :     } else {
    4816              :         // ballistic
    4817     99261193 :         deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
    4818              :     }
    4819              : 
    4820              :     // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
    4821              :     // NOTE: for the ballistic update vNext may be negative, indicating a stop.
    4822    547996509 :     myAcceleration = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
    4823              : 
    4824              : #ifdef DEBUG_EXEC_MOVE
    4825              :     if (DEBUG_COND) {
    4826              :         std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
    4827              :                   << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
    4828              :     }
    4829              : #endif
    4830    547996509 :     double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
    4831    547996509 :     if (decelPlus > 0) {
    4832       390749 :         const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
    4833       390749 :         if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
    4834              :             // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
    4835       268038 :             decelPlus += 2 * NUMERICAL_EPS;
    4836       268038 :             const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
    4837       268038 :             if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
    4838        91206 :                 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
    4839              :                                //+ " decelPlus=" + toString(decelPlus)
    4840              :                                //+ " prevAccel=" + toString(previousAcceleration)
    4841              :                                //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
    4842              :                                getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
    4843        30402 :                 MSNet::getInstance()->getVehicleControl().registerEmergencyBraking();
    4844              :             }
    4845              :         }
    4846              :     }
    4847              : 
    4848    547996509 :     myState.myPreviousSpeed = myState.mySpeed;
    4849    547996509 :     myState.mySpeed = MAX2(vNext, 0.);
    4850              : 
    4851    547996509 :     if (isRemoteControlled()) {
    4852         7562 :         deltaPos = myInfluencer->implicitDeltaPosRemote(this);
    4853              :     }
    4854              : 
    4855    547996509 :     myState.myPos += deltaPos;
    4856    547996509 :     myState.myLastCoveredDist = deltaPos;
    4857    547996509 :     myNextTurn.first -= deltaPos;
    4858              : 
    4859    547996509 :     myCachedPosition = Position::INVALID;
    4860    547996509 : }
    4861              : 
    4862              : void
    4863      7523220 : MSVehicle::updateParkingState() {
    4864      7523220 :     updateState(0);
    4865              :     // deboard while parked
    4866      7523220 :     if (myPersonDevice != nullptr) {
    4867       455864 :         myPersonDevice->notifyMove(*this, getPositionOnLane(), getPositionOnLane(), 0);
    4868              :     }
    4869      7523220 :     if (myContainerDevice != nullptr) {
    4870        59855 :         myContainerDevice->notifyMove(*this, getPositionOnLane(), getPositionOnLane(), 0);
    4871              :     }
    4872     14282861 :     for (MSVehicleDevice* const dev : myDevices) {
    4873      6759641 :         dev->notifyParking();
    4874              :     }
    4875      7523220 : }
    4876              : 
    4877              : 
    4878              : void
    4879        30437 : MSVehicle::replaceVehicleType(MSVehicleType* type) {
    4880        30437 :     MSBaseVehicle::replaceVehicleType(type);
    4881        30437 :     delete myCFVariables;
    4882        30437 :     myCFVariables = type->getCarFollowModel().createVehicleVariables();
    4883        30437 : }
    4884              : 
    4885              : 
    4886              : const MSLane*
    4887   1062440748 : MSVehicle::getBackLane() const {
    4888   1062440748 :     if (myFurtherLanes.size() > 0) {
    4889     15283810 :         return myFurtherLanes.back();
    4890              :     } else {
    4891   1047156938 :         return myLane;
    4892              :     }
    4893              : }
    4894              : 
    4895              : 
    4896              : double
    4897    542965163 : MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
    4898              :                               const std::vector<MSLane*>& passedLanes) {
    4899              : #ifdef DEBUG_SETFURTHER
    4900              :     if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
    4901              :                                   << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
    4902              :                                   << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
    4903              :                                   << " passed=" << toString(passedLanes)
    4904              :                                   << "\n";
    4905              : #endif
    4906    555881627 :     for (MSLane* further : furtherLanes) {
    4907     12916464 :         further->resetPartialOccupation(this);
    4908     12916464 :         if (further->getBidiLane() != nullptr
    4909     12916464 :                 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    4910        28231 :             further->getBidiLane()->resetPartialOccupation(this);
    4911              :         }
    4912              :     }
    4913              : 
    4914              :     std::vector<MSLane*> newFurther;
    4915              :     std::vector<double> newFurtherPosLat;
    4916    542965163 :     double backPosOnPreviousLane = myState.myPos - getLength();
    4917              :     bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
    4918    542965163 :     if (passedLanes.size() > 1) {
    4919              :         // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
    4920              :         std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
    4921              :         std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
    4922     36862863 :         for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
    4923              :             // As long as vehicle back reaches into passed lane, add it to the further lanes
    4924     12849821 :             MSLane* further = *pi;
    4925     12849821 :             newFurther.push_back(further);
    4926     12849821 :             backPosOnPreviousLane += further->setPartialOccupation(this);
    4927     12849821 :             if (further->getBidiLane() != nullptr
    4928     12849821 :                     && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    4929        27725 :                 further->getBidiLane()->setPartialOccupation(this);
    4930              :             }
    4931     12849821 :             if (fi != furtherLanes.end() && further == *fi) {
    4932              :                 // Lateral position on this lane is already known. Assume constant and use old value.
    4933      4508927 :                 newFurtherPosLat.push_back(*fpi);
    4934              :                 ++fi;
    4935              :                 ++fpi;
    4936              :             } else {
    4937              :                 // The lane *pi was not in furtherLanes before.
    4938              :                 // If it is downstream, we assume as lateral position the current position
    4939              :                 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
    4940              :                 // we assign the last known lateral position.
    4941      8340894 :                 if (newFurtherPosLat.size() == 0) {
    4942      7772783 :                     if (widthShift) {
    4943      1371064 :                         newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
    4944              :                     } else {
    4945      6401719 :                         newFurtherPosLat.push_back(myState.myPosLat);
    4946              :                     }
    4947              :                 } else {
    4948       568111 :                     newFurtherPosLat.push_back(newFurtherPosLat.back());
    4949              :                 }
    4950              :             }
    4951              : #ifdef DEBUG_SETFURTHER
    4952              :             if (DEBUG_COND) {
    4953              :                 std::cout << SIMTIME << " updateFurtherLanes \n"
    4954              :                           << "    further lane '" << further->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
    4955              :                           << std::endl;
    4956              :             }
    4957              : #endif
    4958              :         }
    4959     24013042 :         furtherLanes = newFurther;
    4960     24013042 :         furtherLanesPosLat = newFurtherPosLat;
    4961              :     } else {
    4962              :         furtherLanes.clear();
    4963              :         furtherLanesPosLat.clear();
    4964              :     }
    4965              : #ifdef DEBUG_SETFURTHER
    4966              :     if (DEBUG_COND) std::cout
    4967              :                 << " newFurther=" << toString(furtherLanes)
    4968              :                 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
    4969              :                 << " newBackPos=" << backPosOnPreviousLane
    4970              :                 << "\n";
    4971              : #endif
    4972    542965163 :     return backPosOnPreviousLane;
    4973    542965163 : }
    4974              : 
    4975              : 
    4976              : double
    4977  28669119171 : MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
    4978              : #ifdef DEBUG_FURTHER
    4979              :     if (DEBUG_COND) {
    4980              :         std::cout << SIMTIME
    4981              :                   << " getBackPositionOnLane veh=" << getID()
    4982              :                   << " lane=" << Named::getIDSecure(lane)
    4983              :                   << " cbgP=" << calledByGetPosition
    4984              :                   << " pos=" << myState.myPos
    4985              :                   << " backPos=" << myState.myBackPos
    4986              :                   << " myLane=" << myLane->getID()
    4987              :                   << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
    4988              :                   << " further=" << toString(myFurtherLanes)
    4989              :                   << " furtherPosLat=" << toString(myFurtherLanesPosLat)
    4990              :                   << "\n     shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
    4991              :                   << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
    4992              :                   << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
    4993              :                   << "\n     targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
    4994              :                   << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
    4995              :                   << std::endl;
    4996              :     }
    4997              : #endif
    4998  28669119171 :     if (lane == myLane
    4999   6454543269 :             || lane == myLaneChangeModel->getShadowLane()
    5000  32501116048 :             || lane == myLaneChangeModel->getTargetLane()) {
    5001  24838459838 :         if (myLaneChangeModel->isOpposite()) {
    5002    231258424 :             if (lane == myLaneChangeModel->getShadowLane()) {
    5003    198639530 :                 return lane->getLength() - myState.myPos - myType->getLength();
    5004              :             } else {
    5005     37532689 :                 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
    5006              :             }
    5007  24607201414 :         } else if (&lane->getEdge() != &myLane->getEdge()) {
    5008     20496225 :             return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
    5009              :         } else {
    5010              :             // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
    5011  49174130678 :             return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
    5012              :         }
    5013   3830659333 :     } else if (lane == myLane->getBidiLane()) {
    5014      3894838 :         return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
    5015   3828154315 :     } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
    5016   3787155045 :         return myState.myBackPos;
    5017     40999270 :     } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
    5018     41482484 :                || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
    5019              :         assert(myFurtherLanes.size() > 0);
    5020     15062605 :         if (lane->getLength() == myFurtherLanes.back()->getLength()) {
    5021     14559078 :             return myState.myBackPos;
    5022              :         } else {
    5023              :             // interpolate
    5024              :             //if (DEBUG_COND) {
    5025              :             //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
    5026              :             //    std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
    5027              :             //        << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
    5028              :             //        << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
    5029              :             //}
    5030       503527 :             return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
    5031              :         }
    5032              :     } else {
    5033              :         //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
    5034     25936665 :         double leftLength = myType->getLength() - myState.myPos;
    5035              : 
    5036              :         std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
    5037     27925396 :         while (leftLength > 0 && i != myFurtherLanes.end()) {
    5038     27896429 :             leftLength -= (*i)->getLength();
    5039              :             //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
    5040     27896429 :             if (*i == lane) {
    5041     25545009 :                 return -leftLength;
    5042      2351420 :             } else if (*i == lane->getBidiLane()) {
    5043       362689 :                 return lane->getLength() + leftLength - (calledByGetPosition ? 2 * myType->getLength() : 0);
    5044              :             }
    5045              :             ++i;
    5046              :         }
    5047              :         //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
    5048        28967 :         leftLength = myType->getLength() - myState.myPos;
    5049        28967 :         i = myLaneChangeModel->getShadowFurtherLanes().begin();
    5050        28967 :         while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
    5051        28963 :             leftLength -= (*i)->getLength();
    5052              :             //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
    5053        28963 :             if (*i == lane) {
    5054        28963 :                 return -leftLength;
    5055              :             }
    5056              :             ++i;
    5057              :         }
    5058              :         //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
    5059              :         leftLength = myType->getLength() - myState.myPos;
    5060              :         i = getFurtherLanes().begin();
    5061            4 :         const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
    5062              :         auto j = furtherTargetLanes.begin();
    5063            4 :         while (leftLength > 0 && j != furtherTargetLanes.end()) {
    5064            0 :             leftLength -= (*i)->getLength();
    5065              :             // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
    5066            0 :             if (*j == lane) {
    5067            0 :                 return -leftLength;
    5068              :             }
    5069              :             ++i;
    5070              :             ++j;
    5071              :         }
    5072           28 :         WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
    5073              :                       + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
    5074              :         SOFT_ASSERT(false);
    5075            4 :         return  myState.myBackPos;
    5076            4 :     }
    5077              : }
    5078              : 
    5079              : 
    5080              : double
    5081  23458942541 : MSVehicle::getPositionOnLane(const MSLane* lane) const {
    5082  23458942541 :     return getBackPositionOnLane(lane, true) + myType->getLength();
    5083              : }
    5084              : 
    5085              : 
    5086              : bool
    5087    390447839 : MSVehicle::isFrontOnLane(const MSLane* lane) const {
    5088    390447839 :     return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
    5089              : }
    5090              : 
    5091              : 
    5092              : void
    5093    468251683 : MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
    5094    468251683 :     if (MSGlobals::gUsingInternalLanes && !myLane->getEdge().isRoundabout() && !myLaneChangeModel->isOpposite()) {
    5095    465136509 :         double seenSpace = -lengthsInFront;
    5096              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5097              :         if (DEBUG_COND) {
    5098              :             std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
    5099              :         };
    5100              : #endif
    5101    465136509 :         bool foundStopped = false;
    5102              :         // compute available space until a stopped vehicle is found
    5103              :         // this is the sum of non-interal lane length minus in-between vehicle lengths
    5104   1438975928 :         for (int i = 0; i < (int)lfLinks.size(); ++i) {
    5105              :             // skip unset links
    5106    973839419 :             DriveProcessItem& item = lfLinks[i];
    5107              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5108              :             if (DEBUG_COND) std::cout << SIMTIME
    5109              :                                           << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
    5110              :                                           << " foundStopped=" << foundStopped;
    5111              : #endif
    5112    973839419 :             if (item.myLink == nullptr || foundStopped) {
    5113    258220592 :                 if (!foundStopped) {
    5114    205609973 :                     item.availableSpace += seenSpace;
    5115              :                 } else {
    5116     52610619 :                     item.availableSpace = seenSpace;
    5117              :                 }
    5118              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5119              :                 if (DEBUG_COND) {
    5120              :                     std::cout << " avail=" << item.availableSpace << "\n";
    5121              :                 }
    5122              : #endif
    5123    258220592 :                 continue;
    5124              :             }
    5125              :             // get the next lane, determine whether it is an internal lane
    5126              :             const MSLane* approachedLane = item.myLink->getViaLane();
    5127    715618827 :             if (approachedLane != nullptr) {
    5128    381734306 :                 if (keepClear(item.myLink)) {
    5129    117751862 :                     seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
    5130    117751862 :                     if (approachedLane == myLane) {
    5131        45611 :                         seenSpace += getVehicleType().getLengthWithGap();
    5132              :                     }
    5133              :                 } else {
    5134    263982444 :                     seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
    5135              :                 }
    5136    381734306 :                 item.availableSpace = seenSpace;
    5137              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5138              :                 if (DEBUG_COND) std::cout
    5139              :                             << " approached=" << approachedLane->getID()
    5140              :                             << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
    5141              :                             << " avail=" << item.availableSpace
    5142              :                             << " seenSpace=" << seenSpace
    5143              :                             << " hadStoppedVehicle=" << item.hadStoppedVehicle
    5144              :                             << " lengthsInFront=" << lengthsInFront
    5145              :                             << "\n";
    5146              : #endif
    5147    381734306 :                 continue;
    5148              :             }
    5149              :             approachedLane = item.myLink->getLane();
    5150    333884521 :             const MSVehicle* last = approachedLane->getLastAnyVehicle();
    5151    333884521 :             if (last == nullptr || last == this) {
    5152     50506420 :                 if (approachedLane->getLength() > getVehicleType().getLength()
    5153     50506420 :                         || keepClear(item.myLink)) {
    5154     48316708 :                     seenSpace += approachedLane->getLength();
    5155              :                 }
    5156     50506420 :                 item.availableSpace = seenSpace;
    5157              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5158              :                 if (DEBUG_COND) {
    5159              :                     std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
    5160              :                 }
    5161              : #endif
    5162              :             } else {
    5163    283378101 :                 bool foundStopped2 = false;
    5164    283378101 :                 double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
    5165    283378101 :                 if (approachedLane->getBidiLane() != nullptr) {
    5166        77288 :                     const MSVehicle* oncomingVeh = approachedLane->getBidiLane()->getFirstFullVehicle();
    5167        77288 :                     if (oncomingVeh) {
    5168        28969 :                         const double oncomingGap = approachedLane->getLength() - oncomingVeh->getPositionOnLane();
    5169        28969 :                         const double oncomingBGap = oncomingVeh->getBrakeGap(true);
    5170              :                         // oncoming movement until ego enters the junction
    5171        28969 :                         const double oncomingMove = STEPS2TIME(item.myArrivalTime - SIMSTEP) * oncomingVeh->getSpeed();
    5172        28969 :                         const double spaceTillOncoming = oncomingGap - oncomingBGap - oncomingMove;
    5173              :                         spaceTillLastStanding = MIN2(spaceTillLastStanding, spaceTillOncoming);
    5174        28969 :                         if (spaceTillOncoming <= getVehicleType().getLengthWithGap()) {
    5175        23901 :                             foundStopped = true;
    5176              :                         }
    5177              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5178              :                         if (DEBUG_COND) {
    5179              :                             std::cout << " oVeh=" << oncomingVeh->getID()
    5180              :                                       << " oGap=" << oncomingGap
    5181              :                                       << " bGap=" << oncomingBGap
    5182              :                                       << " mGap=" << oncomingMove
    5183              :                                       << " sto=" << spaceTillOncoming;
    5184              :                         }
    5185              : #endif
    5186              :                     }
    5187              :                 }
    5188    283378101 :                 seenSpace += spaceTillLastStanding;
    5189    283378101 :                 if (foundStopped2) {
    5190     18013445 :                     foundStopped = true;
    5191     18013445 :                     item.hadStoppedVehicle = true;
    5192              :                 }
    5193    283378101 :                 item.availableSpace = seenSpace;
    5194    283378101 :                 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
    5195     38552863 :                     foundStopped = true;
    5196     38552863 :                     item.hadStoppedVehicle = true;
    5197              :                 }
    5198              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5199              :                 if (DEBUG_COND) std::cout
    5200              :                             << " approached=" << approachedLane->getID()
    5201              :                             << " last=" << last->getID()
    5202              :                             << " lastHasToWait=" << last->myHaveToWaitOnNextLink
    5203              :                             << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
    5204              :                             << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
    5205              :                             << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
    5206              :                                                // gap of last up to the next intersection
    5207              :                                                - last->getVehicleType().getMinGap())
    5208              :                             << " stls=" << spaceTillLastStanding
    5209              :                             << " avail=" << item.availableSpace
    5210              :                             << " seenSpace=" << seenSpace
    5211              :                             << " foundStopped=" << foundStopped
    5212              :                             << " foundStopped2=" << foundStopped2
    5213              :                             << "\n";
    5214              : #endif
    5215              :             }
    5216              :         }
    5217              : 
    5218              :         // check which links allow continuation and add pass available to the previous item
    5219    973839419 :         for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
    5220    508702910 :             DriveProcessItem& item = lfLinks[i - 1];
    5221    508702910 :             DriveProcessItem& nextItem = lfLinks[i];
    5222    508702910 :             const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
    5223              :             const bool opened = (item.myLink != nullptr
    5224    508702910 :                                  && (canLeaveJunction || (
    5225              :                                          // indirect bicycle turn
    5226     23837354 :                                          nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
    5227    484880068 :                                  && (
    5228    484880068 :                                      item.myLink->havePriority()
    5229     23979347 :                                      || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
    5230      4182601 :                                      || (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority())
    5231      4168589 :                                      || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
    5232      4168589 :                                              item.getLeaveSpeed(), getVehicleType().getLength(),
    5233      4168589 :                                              getImpatience(), getCarFollowModel().getMaxDecel(), getWaitingTime(), getLateralPositionOnLane(), nullptr, false, this)));
    5234    508702910 :             bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
    5235              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5236              :             if (DEBUG_COND) std::cout
    5237              :                         << "   link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
    5238              :                         << " canLeave=" << canLeaveJunction
    5239              :                         << " opened=" << opened
    5240              :                         << " allowsContinuation=" << allowsContinuation
    5241              :                         << " foundStopped=" << foundStopped
    5242              :                         << "\n";
    5243              : #endif
    5244    508702910 :             if (!opened && item.myLink != nullptr) {
    5245     24394952 :                 foundStopped = true;
    5246     24394952 :                 if (i > 1) {
    5247      4094568 :                     DriveProcessItem& item2 = lfLinks[i - 2];
    5248      4094568 :                     if (item2.myLink != nullptr && item2.myLink->isCont()) {
    5249              :                         allowsContinuation = true;
    5250              :                     }
    5251              :                 }
    5252              :             }
    5253    506313438 :             if (allowsContinuation) {
    5254    447696569 :                 item.availableSpace = nextItem.availableSpace;
    5255              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5256              :                 if (DEBUG_COND) std::cout
    5257              :                             << "   link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
    5258              :                             << " copy nextAvail=" << nextItem.availableSpace
    5259              :                             << "\n";
    5260              : #endif
    5261              :             }
    5262              :         }
    5263              : 
    5264              :         // find removalBegin
    5265              :         int removalBegin = -1;
    5266    600326672 :         for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
    5267              :             // skip unset links
    5268    135190163 :             const DriveProcessItem& item = lfLinks[i];
    5269    135190163 :             if (item.myLink == nullptr) {
    5270      7421758 :                 continue;
    5271              :             }
    5272              :             /*
    5273              :             double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
    5274              :             if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
    5275              :                 removalBegin = lastLinkToInternal;
    5276              :             }
    5277              :             */
    5278              : 
    5279    127768405 :             const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
    5280              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5281              :             if (DEBUG_COND) std::cout
    5282              :                         << SIMTIME
    5283              :                         << " veh=" << getID()
    5284              :                         << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
    5285              :                         << " avail=" << item.availableSpace
    5286              :                         << " leftSpace=" << leftSpace
    5287              :                         << "\n";
    5288              : #endif
    5289    127768405 :             if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
    5290              :                 double impatienceCorrection = 0;
    5291              :                 /*
    5292              :                 if(item.myLink->getState()==LINKSTATE_MINOR) {
    5293              :                     impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
    5294              :                 }
    5295              :                 */
    5296              :                 // may ignore keepClear rules
    5297     72022057 :                 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
    5298              :                     removalBegin = i;
    5299              :                 }
    5300              :                 //removalBegin = i;
    5301              :             }
    5302              :         }
    5303              :         // abort requests
    5304    465136509 :         if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
    5305     28168471 :             const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
    5306     97528776 :             while (removalBegin < (int)(lfLinks.size())) {
    5307     73796305 :                 DriveProcessItem& dpi = lfLinks[removalBegin];
    5308     73796305 :                 if (dpi.myLink == nullptr) {
    5309              :                     break;
    5310              :                 }
    5311     69360305 :                 dpi.myVLinkPass = dpi.myVLinkWait;
    5312              : #ifdef DEBUG_CHECKREWINDLINKLANES
    5313              :                 if (DEBUG_COND) {
    5314              :                     std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
    5315              :                 }
    5316              : #endif
    5317     69360305 :                 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
    5318              :                     // always leave junctions after requesting to enter
    5319     69351633 :                     if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
    5320     69344793 :                         dpi.mySetRequest = false;
    5321              :                     }
    5322              :                 }
    5323     69360305 :                 ++removalBegin;
    5324              :             }
    5325              :         }
    5326              :     }
    5327    468251683 : }
    5328              : 
    5329              : 
    5330              : void
    5331    540473312 : MSVehicle::setApproachingForAllLinks(const SUMOTime t) {
    5332    540473312 :     if (!checkActionStep(t)) {
    5333              :         return;
    5334              :     }
    5335    468251683 :     removeApproachingInformation(myLFLinkLanesPrev);
    5336   1449466955 :     for (DriveProcessItem& dpi : myLFLinkLanes) {
    5337    981215272 :         if (dpi.myLink != nullptr) {
    5338    766381533 :             if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
    5339      3087374 :                 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
    5340              :             }
    5341    766381533 :             dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
    5342    766381533 :                                        dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance, getLateralPositionOnLane());
    5343              :         }
    5344              :     }
    5345    468251683 :     if (isRailway(getVClass())) {
    5346      4105917 :         for (DriveProcessItem& dpi : myLFLinkLanes) {
    5347      3191019 :             if (dpi.myLink != nullptr && dpi.myLink->getTLLogic() != nullptr && dpi.myLink->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
    5348       422667 :                 MSRailSignalControl::getInstance().notifyApproach(dpi.myLink);
    5349              :             }
    5350              :         }
    5351              :     }
    5352    468251683 :     if (myLaneChangeModel->getShadowLane() != nullptr) {
    5353              :         // register on all shadow links
    5354      6843692 :         for (const DriveProcessItem& dpi : myLFLinkLanes) {
    5355      4563809 :             if (dpi.myLink != nullptr) {
    5356      3160922 :                 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
    5357      3160922 :                 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
    5358              :                     // register on opposite direction entry link to warn foes at minor side road
    5359       172201 :                     parallelLink = dpi.myLink->getOppositeDirectionLink();
    5360              :                 }
    5361      3160922 :                 if (parallelLink != nullptr) {
    5362      2281664 :                     const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
    5363      2281664 :                     parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
    5364      2281664 :                                                  dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance,
    5365              :                                                  latOffset);
    5366      2281664 :                     myLaneChangeModel->setShadowApproachingInformation(parallelLink);
    5367              :                 }
    5368              :             }
    5369              :         }
    5370              :     }
    5371              : #ifdef DEBUG_PLAN_MOVE
    5372              :     if (DEBUG_COND) {
    5373              :         std::cout << SIMTIME
    5374              :                   << " veh=" << getID()
    5375              :                   << " after checkRewindLinkLanes\n";
    5376              :         for (DriveProcessItem& dpi : myLFLinkLanes) {
    5377              :             std::cout
    5378              :                     << " vPass=" << dpi.myVLinkPass
    5379              :                     << " vWait=" << dpi.myVLinkWait
    5380              :                     << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
    5381              :                     << " request=" << dpi.mySetRequest
    5382              :                     << " atime=" << dpi.myArrivalTime
    5383              :                     << "\n";
    5384              :         }
    5385              :     }
    5386              : #endif
    5387              : }
    5388              : 
    5389              : 
    5390              : void
    5391         1426 : MSVehicle::registerInsertionApproach(MSLink* link, double dist) {
    5392              :     DriveProcessItem dpi(0, dist);
    5393         1426 :     dpi.myLink = link;
    5394         1426 :     const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
    5395         1426 :     link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
    5396              :     // ensure cleanup in the next step
    5397         1426 :     myLFLinkLanes.push_back(dpi);
    5398         1426 :     MSRailSignalControl::getInstance().notifyApproach(link);
    5399         1426 : }
    5400              : 
    5401              : 
    5402              : void
    5403     20439090 : MSVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
    5404     61483259 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
    5405              :         // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
    5406     41044169 :         if (rem->first->getLane() != nullptr && rem->second > 0.) {
    5407              : #ifdef _DEBUG
    5408              :             if (myTraceMoveReminders) {
    5409              :                 traceMoveReminder("notifyEnter_skipped", rem->first, rem->second, true);
    5410              :             }
    5411              : #endif
    5412              :             ++rem;
    5413              :         } else {
    5414     28897094 :             if (rem->first->notifyEnter(*this, reason, enteredLane)) {
    5415              : #ifdef _DEBUG
    5416              :                 if (myTraceMoveReminders) {
    5417              :                     traceMoveReminder("notifyEnter", rem->first, rem->second, true);
    5418              :                 }
    5419              : #endif
    5420              :                 ++rem;
    5421              :             } else {
    5422              : #ifdef _DEBUG
    5423              :                 if (myTraceMoveReminders) {
    5424              :                     traceMoveReminder("notifyEnter", rem->first, rem->second, false);
    5425              :                 }
    5426              : //                std::cout << SIMTIME << " Vehicle '" << getID() << "' erases MoveReminder (with offset " << rem->second << ")" << std::endl;
    5427              : #endif
    5428              :                 rem = myMoveReminders.erase(rem);
    5429              :             }
    5430              :         }
    5431              :     }
    5432     20439090 : }
    5433              : 
    5434              : 
    5435              : void
    5436     16834255 : MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
    5437     16834255 :     myAmOnNet = !onTeleporting;
    5438              :     // vaporizing edge?
    5439              :     /*
    5440              :     if (enteredLane->getEdge().isVaporizing()) {
    5441              :         // yep, let's do the vaporization...
    5442              :         myLane = enteredLane;
    5443              :         return true;
    5444              :     }
    5445              :     */
    5446              :     // Adjust MoveReminder offset to the next lane
    5447     16834255 :     adaptLaneEntering2MoveReminder(*enteredLane);
    5448              :     // set the entered lane as the current lane
    5449     16834255 :     MSLane* oldLane = myLane;
    5450     16834255 :     myLane = enteredLane;
    5451     16834255 :     myLastBestLanesEdge = nullptr;
    5452              : 
    5453              :     // internal edges are not a part of the route...
    5454     16834255 :     if (!enteredLane->getEdge().isInternal()) {
    5455              :         ++myCurrEdge;
    5456              :         assert(myLaneChangeModel->isOpposite() || haveValidStopEdges());
    5457              :     }
    5458     16834255 :     if (myInfluencer != nullptr) {
    5459         8936 :         myInfluencer->adaptLaneTimeLine(myLane->getIndex() - oldLane->getIndex());
    5460              :     }
    5461     16834255 :     if (!onTeleporting) {
    5462     16815439 :         activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION, enteredLane);
    5463     16815439 :         if (MSGlobals::gLateralResolution > 0) {
    5464              :             // transform lateral position when the lane width changes
    5465              :             assert(oldLane != nullptr);
    5466      3564908 :             const MSLink* const link = oldLane->getLinkTo(myLane);
    5467      3564908 :             if (link != nullptr) {
    5468      3564885 :                 myFurtherLanesPosLat.push_back(myState.myPosLat);
    5469      3564885 :                 myState.myPosLat += link->getLateralShift();
    5470              :             }
    5471     13250531 :         } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
    5472       199259 :             const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
    5473       199259 :             const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
    5474       199259 :             const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
    5475       199259 :             myState.myPosLat *= range2 / range;
    5476              :         }
    5477     16815439 :         if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5478              :             // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
    5479              :             // (unless the lane is shared with cars)
    5480         9720 :             myLane->getBidiLane()->setPartialOccupation(this);
    5481              :         }
    5482              :     } else {
    5483              :         // normal move() isn't called so reset position here. must be done
    5484              :         // before calling reminders
    5485        18816 :         myState.myPos = 0;
    5486        18816 :         myCachedPosition = Position::INVALID;
    5487        18816 :         activateReminders(MSMoveReminder::NOTIFICATION_TELEPORT, enteredLane);
    5488              :     }
    5489              :     // update via
    5490     16834255 :     if (myParameter->via.size() > 0 &&  myLane->getEdge().getID() == myParameter->via.front()) {
    5491         5709 :         myParameter->via.erase(myParameter->via.begin());
    5492              :     }
    5493     16834255 : }
    5494              : 
    5495              : 
    5496              : void
    5497       908842 : MSVehicle::enterLaneAtLaneChange(MSLane* enteredLane) {
    5498       908842 :     myAmOnNet = true;
    5499       908842 :     myLane = enteredLane;
    5500       908842 :     myCachedPosition = Position::INVALID;
    5501              :     // need to update myCurrentLaneInBestLanes
    5502       908842 :     updateBestLanes();
    5503              :     // switch to and activate the new lane's reminders
    5504              :     // keep OldLaneReminders
    5505      1066728 :     for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
    5506       157886 :         addReminder(*rem);
    5507              :     }
    5508       908842 :     activateReminders(MSMoveReminder::NOTIFICATION_LANE_CHANGE, enteredLane);
    5509       908842 :     MSLane* lane = myLane;
    5510       908842 :     double leftLength = getVehicleType().getLength() - myState.myPos;
    5511              :     int deleteFurther = 0;
    5512              : #ifdef DEBUG_SETFURTHER
    5513              :     if (DEBUG_COND) {
    5514              :         std::cout << SIMTIME << " enterLaneAtLaneChange entered=" << Named::getIDSecure(enteredLane) << " oldFurther=" << toString(myFurtherLanes) << "\n";
    5515              :     }
    5516              : #endif
    5517       908842 :     if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5518              :         // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
    5519              :         // (unless the lane is shared with cars)
    5520         8667 :         myLane->getBidiLane()->setPartialOccupation(this);
    5521              :     }
    5522       985788 :     for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
    5523        76946 :         if (lane != nullptr) {
    5524        73903 :             lane = lane->getLogicalPredecessorLane(myFurtherLanes[i]->getEdge());
    5525              :         }
    5526              : #ifdef DEBUG_SETFURTHER
    5527              :         if (DEBUG_COND) {
    5528              :             std::cout << "  enterLaneAtLaneChange i=" << i << " lane=" << Named::getIDSecure(lane) << " leftLength=" << leftLength << "\n";
    5529              :         }
    5530              : #endif
    5531        76946 :         if (leftLength > 0) {
    5532        76371 :             if (lane != nullptr) {
    5533        29452 :                 myFurtherLanes[i]->resetPartialOccupation(this);
    5534        29452 :                 if (myFurtherLanes[i]->getBidiLane() != nullptr
    5535        29452 :                         && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5536           42 :                     myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
    5537              :                 }
    5538              :                 // lane changing onto longer lanes may reduce the number of
    5539              :                 // remaining further lanes
    5540        29452 :                 myFurtherLanes[i] = lane;
    5541        29452 :                 myFurtherLanesPosLat[i] = myState.myPosLat;
    5542        29452 :                 leftLength -= lane->setPartialOccupation(this);
    5543        29452 :                 if (lane->getBidiLane() != nullptr
    5544        29452 :                         && (!isRailway(getVClass()) || (lane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5545          543 :                     lane->getBidiLane()->setPartialOccupation(this);
    5546              :                 }
    5547        29452 :                 myState.myBackPos = -leftLength;
    5548              : #ifdef DEBUG_SETFURTHER
    5549              :                 if (DEBUG_COND) {
    5550              :                     std::cout << SIMTIME << "   newBackPos=" << myState.myBackPos << "\n";
    5551              :                 }
    5552              : #endif
    5553              :             } else {
    5554              :                 // keep the old values, but ensure there is no shadow
    5555        46919 :                 if (myLaneChangeModel->isChangingLanes()) {
    5556            0 :                     myLaneChangeModel->setNoShadowPartialOccupator(myFurtherLanes[i]);
    5557              :                 }
    5558        46919 :                 if (myState.myBackPos < 0) {
    5559           51 :                     myState.myBackPos += myFurtherLanes[i]->getLength();
    5560              :                 }
    5561              : #ifdef DEBUG_SETFURTHER
    5562              :                 if (DEBUG_COND) {
    5563              :                     std::cout << SIMTIME << "   i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
    5564              :                 }
    5565              : #endif
    5566              :             }
    5567              :         } else {
    5568          575 :             myFurtherLanes[i]->resetPartialOccupation(this);
    5569          575 :             if (myFurtherLanes[i]->getBidiLane() != nullptr
    5570          575 :                     && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5571            0 :                 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
    5572              :             }
    5573          575 :             deleteFurther++;
    5574              :         }
    5575              :     }
    5576       908842 :     if (deleteFurther > 0) {
    5577              : #ifdef DEBUG_SETFURTHER
    5578              :         if (DEBUG_COND) {
    5579              :             std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
    5580              :         }
    5581              : #endif
    5582          563 :         myFurtherLanes.erase(myFurtherLanes.end() - deleteFurther, myFurtherLanes.end());
    5583          563 :         myFurtherLanesPosLat.erase(myFurtherLanesPosLat.end() - deleteFurther, myFurtherLanesPosLat.end());
    5584              :     }
    5585              : #ifdef DEBUG_SETFURTHER
    5586              :     if (DEBUG_COND) {
    5587              :         std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
    5588              :                   << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
    5589              :     }
    5590              : #endif
    5591       908842 :     myAngle = computeAngle();
    5592       908842 : }
    5593              : 
    5594              : 
    5595              : void
    5596      2702723 : MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
    5597              :     // build the list of lanes the vehicle is lapping into
    5598      2702723 :     if (!myLaneChangeModel->isOpposite()) {
    5599      2681217 :         double leftLength = myType->getLength() - pos;
    5600      2681217 :         MSLane* clane = enteredLane;
    5601      2681217 :         int routeIndex = getRoutePosition();
    5602      2779542 :         while (leftLength > 0) {
    5603       215698 :             if (routeIndex > 0 && clane->getEdge().isNormal()) {
    5604              :                 // get predecessor lane that corresponds to prior route
    5605         4235 :                 routeIndex--;
    5606         4235 :                 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
    5607              :                 MSLane* target = clane;
    5608         4235 :                 clane = nullptr;
    5609         5483 :                 for (auto ili : target->getIncomingLanes()) {
    5610         5472 :                     if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
    5611         4224 :                         clane = ili.lane;
    5612         4224 :                         break;
    5613              :                     }
    5614              :                 }
    5615              :             } else {
    5616       211463 :                 clane = clane->getLogicalPredecessorLane();
    5617              :             }
    5618       128106 :             if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
    5619       343796 :                     || (clane->isInternal() && (
    5620       105351 :                             clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
    5621        75578 :                             || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
    5622              :                 break;
    5623              :             }
    5624        98325 :             if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
    5625        97944 :                 myFurtherLanes.push_back(clane);
    5626        97944 :                 myFurtherLanesPosLat.push_back(myState.myPosLat);
    5627        97944 :                 clane->setPartialOccupation(this);
    5628        97944 :                 if (clane->getBidiLane() != nullptr
    5629        97944 :                         && (!isRailway(getVClass()) || (clane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5630            5 :                     clane->getBidiLane()->setPartialOccupation(this);
    5631              :                 }
    5632              :             }
    5633        98325 :             leftLength -= clane->getLength();
    5634              :         }
    5635      2681217 :         myState.myBackPos = -leftLength;
    5636              : #ifdef DEBUG_SETFURTHER
    5637              :         if (DEBUG_COND) {
    5638              :             std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
    5639              :         }
    5640              : #endif
    5641              :     } else {
    5642              :         // clear partial occupation
    5643        21869 :         for (MSLane* further : myFurtherLanes) {
    5644              : #ifdef DEBUG_SETFURTHER
    5645              :             if (DEBUG_COND) {
    5646              :                 std::cout << SIMTIME << " opposite: resetPartialOccupation " << further->getID() << " \n";
    5647              :             }
    5648              : #endif
    5649          363 :             further->resetPartialOccupation(this);
    5650          363 :             if (further->getBidiLane() != nullptr
    5651          363 :                     && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5652            0 :                 further->getBidiLane()->resetPartialOccupation(this);
    5653              :             }
    5654              :         }
    5655              :         myFurtherLanes.clear();
    5656              :         myFurtherLanesPosLat.clear();
    5657              :     }
    5658      2702723 : }
    5659              : 
    5660              : 
    5661              : void
    5662      2702359 : MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
    5663      2702359 :     myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
    5664      2702359 :     if (myDeparture == NOT_YET_DEPARTED) {
    5665      2638510 :         onDepart();
    5666              :     }
    5667      2702359 :     myCachedPosition = Position::INVALID;
    5668              :     assert(myState.myPos >= 0);
    5669              :     assert(myState.mySpeed >= 0);
    5670      2702359 :     myLane = enteredLane;
    5671      2702359 :     myAmOnNet = true;
    5672              :     // schedule action for the next timestep
    5673      2702359 :     myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + DELTA_T;
    5674      2702359 :     if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
    5675              :         // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
    5676      4320003 :         for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
    5677      1624102 :             addReminder(*rem);
    5678              :         }
    5679      2695901 :         activateReminders(notification, enteredLane);
    5680              :     } else {
    5681         6458 :         myLastBestLanesEdge = nullptr;
    5682         6458 :         myLastBestLanesInternalLane = nullptr;
    5683         6458 :         myLaneChangeModel->resetState();
    5684              :     }
    5685      2702359 :     computeFurtherLanes(enteredLane, pos);
    5686      2702359 :     if (MSGlobals::gLateralResolution > 0) {
    5687       474379 :         myLaneChangeModel->updateShadowLane();
    5688       474379 :         myLaneChangeModel->updateTargetLane();
    5689      2227980 :     } else if (MSGlobals::gLaneChangeDuration > 0) {
    5690        34035 :         myLaneChangeModel->updateShadowLane();
    5691              :     }
    5692      2702359 :     if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
    5693      2700952 :         myAngle = computeAngle();
    5694      2700952 :         if (myLaneChangeModel->isOpposite()) {
    5695        21506 :             myAngle += M_PI;
    5696              :         }
    5697              :     }
    5698      2702359 : }
    5699              : 
    5700              : 
    5701              : void
    5702     20342108 : MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
    5703     51681517 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
    5704     31339409 :         if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
    5705              : #ifdef _DEBUG
    5706              :             if (myTraceMoveReminders) {
    5707              :                 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
    5708              :             }
    5709              : #endif
    5710              :             ++rem;
    5711              :         } else {
    5712              : #ifdef _DEBUG
    5713              :             if (myTraceMoveReminders) {
    5714              :                 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
    5715              :             }
    5716              : #endif
    5717              :             rem = myMoveReminders.erase(rem);
    5718              :         }
    5719              :     }
    5720     20342108 :     if ((reason == MSMoveReminder::NOTIFICATION_JUNCTION
    5721     20342108 :             || reason == MSMoveReminder::NOTIFICATION_TELEPORT
    5722      3519598 :             || reason == MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION)
    5723     16834514 :             && myLane != nullptr) {
    5724     16834484 :         myOdometer += getLane()->getLength();
    5725              :     }
    5726     20342078 :     if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
    5727     20381504 :             && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5728        18926 :         myLane->getBidiLane()->resetPartialOccupation(this);
    5729              :     }
    5730     20342108 :     if (reason != MSMoveReminder::NOTIFICATION_JUNCTION && reason != MSMoveReminder::NOTIFICATION_LANE_CHANGE) {
    5731              :         // @note. In case of lane change, myFurtherLanes and partial occupation
    5732              :         // are handled in enterLaneAtLaneChange()
    5733      2602284 :         for (MSLane* further : myFurtherLanes) {
    5734              : #ifdef DEBUG_FURTHER
    5735              :             if (DEBUG_COND) {
    5736              :                 std::cout << SIMTIME << " leaveLane \n";
    5737              :             }
    5738              : #endif
    5739        27264 :             further->resetPartialOccupation(this);
    5740        27264 :             if (further->getBidiLane() != nullptr
    5741        27264 :                     && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
    5742            0 :                 further->getBidiLane()->resetPartialOccupation(this);
    5743              :             }
    5744              :         }
    5745              :         myFurtherLanes.clear();
    5746              :         myFurtherLanesPosLat.clear();
    5747              :     }
    5748      2575020 :     if (reason >= MSMoveReminder::NOTIFICATION_TELEPORT) {
    5749      2575020 :         myAmOnNet = false;
    5750      2575020 :         myWaitingTime = 0;
    5751              :     }
    5752     20342108 :     if (reason != MSMoveReminder::NOTIFICATION_PARKING && resumeFromStopping()) {
    5753          512 :         myStopDist = std::numeric_limits<double>::max();
    5754          512 :         if (myPastStops.back().speed <= 0) {
    5755          975 :             WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
    5756              :         }
    5757              :     }
    5758     20342108 :     if (reason != MSMoveReminder::NOTIFICATION_PARKING && reason != MSMoveReminder::NOTIFICATION_LANE_CHANGE) {
    5759     19378982 :         while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
    5760         1019 :             if (myStops.front().getSpeed() <= 0) {
    5761         1806 :                 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
    5762              :                                time2string(MSNet::getInstance()->getCurrentTimeStep()))
    5763          602 :                 myStops.pop_front();
    5764              :             } else {
    5765              :                 MSStop& stop = myStops.front();
    5766              :                 // passed waypoint at the end of the lane
    5767          417 :                 if (!stop.reached) {
    5768          417 :                     if (MSStopOut::active()) {
    5769           12 :                         MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), MSNet::getInstance()->getCurrentTimeStep());
    5770              :                     }
    5771          417 :                     stop.reached = true;
    5772              :                     // enter stopping place so leaveFrom works as expected
    5773          417 :                     if (stop.busstop != nullptr) {
    5774              :                         // let the bus stop know the vehicle
    5775           26 :                         stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    5776              :                     }
    5777          417 :                     if (stop.containerstop != nullptr) {
    5778              :                         // let the container stop know the vehicle
    5779           14 :                         stop.containerstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    5780              :                     }
    5781              :                     // do not enter parkingarea!
    5782          417 :                     if (stop.chargingStation != nullptr) {
    5783              :                         // let the container stop know the vehicle
    5784          121 :                         stop.chargingStation->enter(this, stop.pars.parking == ParkingType::OFFROAD);
    5785              :                     }
    5786              :                 }
    5787          417 :                 resumeFromStopping();
    5788              :             }
    5789         1019 :             myStopDist = std::numeric_limits<double>::max();
    5790              :         }
    5791              :     }
    5792     20342108 : }
    5793              : 
    5794              : 
    5795              : void
    5796        33956 : MSVehicle::leaveLaneBack(const MSMoveReminder::Notification reason, const MSLane* leftLane) {
    5797       131011 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
    5798        97055 :         if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
    5799              : #ifdef _DEBUG
    5800              :             if (myTraceMoveReminders) {
    5801              :                 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
    5802              :             }
    5803              : #endif
    5804              :             ++rem;
    5805              :         } else {
    5806              : #ifdef _DEBUG
    5807              :             if (myTraceMoveReminders) {
    5808              :                 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
    5809              :             }
    5810              : #endif
    5811              :             rem = myMoveReminders.erase(rem);
    5812              :         }
    5813              :     }
    5814              : #ifdef DEBUG_MOVEREMINDERS
    5815              :     if (DEBUG_COND) {
    5816              :         std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
    5817              :         for (auto rem : myMoveReminders) {
    5818              :             std::cout << rem.first->getDescription() << " ";
    5819              :         }
    5820              :         std::cout << "\n";
    5821              :     }
    5822              : #endif
    5823        33956 : }
    5824              : 
    5825              : 
    5826              : MSAbstractLaneChangeModel&
    5827   7690303974 : MSVehicle::getLaneChangeModel() {
    5828   7690303974 :     return *myLaneChangeModel;
    5829              : }
    5830              : 
    5831              : 
    5832              : const MSAbstractLaneChangeModel&
    5833   4139252106 : MSVehicle::getLaneChangeModel() const {
    5834   4139252106 :     return *myLaneChangeModel;
    5835              : }
    5836              : 
    5837              : bool
    5838       518416 : MSVehicle::isOppositeLane(const MSLane* lane) const {
    5839       518416 :     return (lane->isInternal()
    5840       518416 :             ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
    5841       516495 :             : &lane->getEdge() != *myCurrEdge);
    5842              : }
    5843              : 
    5844              : const std::vector<MSVehicle::LaneQ>&
    5845    349441859 : MSVehicle::getBestLanes() const {
    5846    349441859 :     return *myBestLanes.begin();
    5847              : }
    5848              : 
    5849              : 
    5850              : void
    5851    740242416 : MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
    5852              : #ifdef DEBUG_BESTLANES
    5853              :     if (DEBUG_COND) {
    5854              :         std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
    5855              :     }
    5856              : #endif
    5857    740242416 :     if (startLane == nullptr) {
    5858    701139157 :         startLane = myLane;
    5859              :     }
    5860              :     assert(startLane != 0);
    5861    740242416 :     if (myLaneChangeModel->isOpposite()) {
    5862              :         // depending on the calling context, startLane might be the forward lane
    5863              :         // or the reverse-direction lane. In the latter case we need to
    5864              :         // transform it to the forward lane.
    5865       518416 :         if (isOppositeLane(startLane)) {
    5866              :             // use leftmost lane of forward edge
    5867       110831 :             startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
    5868              :             assert(startLane != 0);
    5869              : #ifdef DEBUG_BESTLANES
    5870              :             if (DEBUG_COND) {
    5871              :                 std::cout << "   startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
    5872              :             }
    5873              : #endif
    5874              :         }
    5875              :     }
    5876    740242416 :     if (forceRebuild) {
    5877      1811785 :         myLastBestLanesEdge = nullptr;
    5878      1811785 :         myLastBestLanesInternalLane = nullptr;
    5879              :     }
    5880    740242416 :     if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
    5881    714801285 :         updateOccupancyAndCurrentBestLane(startLane);
    5882              : #ifdef DEBUG_BESTLANES
    5883              :         if (DEBUG_COND) {
    5884              :             std::cout << "  only updateOccupancyAndCurrentBestLane\n";
    5885              :         }
    5886              : #endif
    5887    714801285 :         return;
    5888              :     }
    5889     25441131 :     if (startLane->getEdge().isInternal()) {
    5890     11509695 :         if (myBestLanes.size() == 0 || forceRebuild) {
    5891              :             // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
    5892         2198 :             updateBestLanes(true, startLane->getLogicalPredecessorLane());
    5893              :         }
    5894     11509695 :         if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
    5895              : #ifdef DEBUG_BESTLANES
    5896              :             if (DEBUG_COND) {
    5897              :                 std::cout << "  nothing to do on internal\n";
    5898              :             }
    5899              : #endif
    5900              :             return;
    5901              :         }
    5902              :         // adapt best lanes to fit the current internal edge:
    5903              :         // keep the entries that are reachable from this edge
    5904      4139338 :         const MSEdge* nextEdge = startLane->getNextNormal();
    5905              :         assert(!nextEdge->isInternal());
    5906      8164657 :         for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
    5907              :             std::vector<LaneQ>& lanes = *it;
    5908              :             assert(lanes.size() > 0);
    5909      8164657 :             if (&(lanes[0].lane->getEdge()) == nextEdge) {
    5910              :                 // keep those lanes which are successors of internal lanes from the edge of startLane
    5911      4139338 :                 std::vector<LaneQ> oldLanes = lanes;
    5912              :                 lanes.clear();
    5913              :                 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
    5914      9529820 :                 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
    5915      9100962 :                     for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
    5916      9100962 :                         if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
    5917      5390482 :                             lanes.push_back(*it_lane);
    5918              :                             break;
    5919              :                         }
    5920              :                     }
    5921              :                 }
    5922              :                 assert(lanes.size() == startLane->getEdge().getLanes().size());
    5923              :                 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
    5924      9529820 :                 for (int i = 0; i < (int)lanes.size(); ++i) {
    5925      5390482 :                     if (i + lanes[i].bestLaneOffset < 0) {
    5926        85648 :                         lanes[i].bestLaneOffset = -i;
    5927              :                     }
    5928      5390482 :                     if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
    5929        17353 :                         lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
    5930              :                     }
    5931              :                     assert(i + lanes[i].bestLaneOffset >= 0);
    5932              :                     assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
    5933      5390482 :                     if (lanes[i].bestContinuations[0] != 0) {
    5934              :                         // patch length of bestContinuation to match expectations (only once)
    5935      5231722 :                         lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
    5936              :                     }
    5937      5390482 :                     if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
    5938      4177414 :                         myCurrentLaneInBestLanes = lanes.begin() + i;
    5939              :                     }
    5940              :                     assert(&(lanes[i].lane->getEdge()) == nextEdge);
    5941              :                 }
    5942      4139338 :                 myLastBestLanesInternalLane = startLane;
    5943      4139338 :                 updateOccupancyAndCurrentBestLane(startLane);
    5944              : #ifdef DEBUG_BESTLANES
    5945              :                 if (DEBUG_COND) {
    5946              :                     std::cout << "  updated for internal\n";
    5947              :                 }
    5948              : #endif
    5949              :                 return;
    5950      4139338 :             } else {
    5951              :                 // remove passed edges
    5952      4025319 :                 it = myBestLanes.erase(it);
    5953              :             }
    5954              :         }
    5955              :         assert(false); // should always find the next edge
    5956              :     }
    5957              :     // start rebuilding
    5958     13931436 :     myLastBestLanesInternalLane = nullptr;
    5959     13931436 :     myLastBestLanesEdge = &startLane->getEdge();
    5960              :     myBestLanes.clear();
    5961              : 
    5962              :     // get information about the next stop
    5963     13931436 :     MSRouteIterator nextStopEdge = myRoute->end();
    5964              :     const MSLane* nextStopLane = nullptr;
    5965              :     double nextStopPos = 0;
    5966              :     bool nextStopIsWaypoint = false;
    5967     13931436 :     if (!myStops.empty()) {
    5968              :         const MSStop& nextStop = myStops.front();
    5969       236029 :         nextStopLane = nextStop.lane;
    5970       236029 :         if (nextStop.isOpposite) {
    5971              :             // target leftmost lane in forward direction
    5972          340 :             nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
    5973              :         }
    5974       236029 :         nextStopEdge = nextStop.edge;
    5975       236029 :         nextStopPos = nextStop.pars.startPos;
    5976       236029 :         nextStopIsWaypoint = nextStop.getSpeed() > 0;
    5977              :     }
    5978              :     // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
    5979     13931436 :     if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
    5980       266261 :         nextStopEdge = (myRoute->end() - 1);
    5981       266261 :         nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
    5982       266261 :         nextStopPos = myArrivalPos;
    5983              :     }
    5984     13931436 :     if (nextStopEdge != myRoute->end()) {
    5985              :         // make sure that the "wrong" lanes get a penalty. (penalty needs to be
    5986              :         // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
    5987       502290 :         nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
    5988       502290 :         if (nextStopLane->isInternal()) {
    5989              :             // switch to the correct lane before entering the intersection
    5990          155 :             nextStopPos = (*nextStopEdge)->getLength();
    5991              :         }
    5992              :     }
    5993              : 
    5994              :     // go forward along the next lanes;
    5995              :     // trains do not have to deal with lane-changing for stops but their best
    5996              :     // lanes lookahead is needed for rail signal control
    5997     13931436 :     const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
    5998              :     int seen = 0;
    5999              :     double seenLength = 0;
    6000              :     bool progress = true;
    6001              :     // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
    6002     27862872 :     const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
    6003     73653574 :     for (MSRouteIterator ce = myCurrEdge; progress;) {
    6004              :         std::vector<LaneQ> currentLanes;
    6005              :         const std::vector<MSLane*>* allowed = nullptr;
    6006              :         const MSEdge* nextEdge = nullptr;
    6007     59722138 :         if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
    6008     49862267 :             nextEdge = *(ce + 1);
    6009     49862267 :             allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
    6010              :         }
    6011     59722138 :         const std::vector<MSLane*>& lanes = (*ce)->getLanes();
    6012    149785160 :         for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
    6013              :             LaneQ q;
    6014     90063022 :             MSLane* cl = *i;
    6015     90063022 :             q.lane = cl;
    6016     90063022 :             q.bestContinuations.push_back(cl);
    6017     90063022 :             q.bestLaneOffset = 0;
    6018     90063022 :             q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
    6019     90063022 :             q.currentLength = q.length;
    6020              :             // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
    6021     90063022 :             q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
    6022     90063022 :             q.occupation = 0;
    6023     90063022 :             q.nextOccupation = 0;
    6024     90063022 :             currentLanes.push_back(q);
    6025              :         }
    6026              :         //
    6027              :         if (nextStopEdge == ce
    6028              :                 // already past the stop edge
    6029     59722138 :                 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
    6030       494450 :             if (!nextStopLane->isInternal() && !continueAfterStop) {
    6031              :                 progress = false;
    6032              :             }
    6033       494450 :             const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
    6034      1620600 :             for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
    6035      1126150 :                 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
    6036       631700 :                     (*q).allowsContinuation = false;
    6037       631700 :                     (*q).length = nextStopPos;
    6038       631700 :                     (*q).currentLength = (*q).length;
    6039              :                 }
    6040              :             }
    6041              :         }
    6042              : 
    6043     59722138 :         myBestLanes.push_back(currentLanes);
    6044     59722138 :         ++seen;
    6045     59722138 :         seenLength += currentLanes[0].lane->getLength();
    6046              :         ++ce;
    6047     79944054 :         progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
    6048     64285037 :         progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass()));  // urban
    6049     59722138 :         progress &= ce != myRoute->end();
    6050              :         /*
    6051              :         if(progress) {
    6052              :           progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
    6053              :         }
    6054              :         */
    6055     59722138 :     }
    6056              : 
    6057              :     // we are examining the last lane explicitly
    6058     13931436 :     if (myBestLanes.size() != 0) {
    6059              :         double bestLength = -1;
    6060              :         // minimum and maximum lane index with best length
    6061              :         int bestThisIndex = 0;
    6062              :         int bestThisMaxIndex = 0;
    6063              :         int index = 0;
    6064              :         std::vector<LaneQ>& last = myBestLanes.back();
    6065     35733778 :         for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
    6066     21802342 :             if ((*j).length > bestLength) {
    6067              :                 bestLength = (*j).length;
    6068              :                 bestThisIndex = index;
    6069              :                 bestThisMaxIndex = index;
    6070      4973690 :             } else if ((*j).length == bestLength) {
    6071              :                 bestThisMaxIndex = index;
    6072              :             }
    6073              :         }
    6074              :         index = 0;
    6075              :         bool requiredChangeRightForbidden = false;
    6076              :         int requireChangeToLeftForbidden = -1;
    6077     35733778 :         for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
    6078     21802342 :             if ((*j).length < bestLength) {
    6079      3330754 :                 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
    6080       114761 :                     (*j).bestLaneOffset = bestThisIndex - index;
    6081              :                 } else {
    6082      3215993 :                     (*j).bestLaneOffset = bestThisMaxIndex - index;
    6083              :                 }
    6084      3330754 :                 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
    6085       320127 :                                                 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
    6086       315706 :                                                 || requiredChangeRightForbidden)) {
    6087              :                     // this lane and all further lanes to the left cannot be used
    6088              :                     requiredChangeRightForbidden = true;
    6089         4431 :                     (*j).length = 0;
    6090      3326323 :                 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
    6091      3010586 :                                                        || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
    6092              :                     // this lane and all previous lanes to the right cannot be used
    6093        31035 :                     requireChangeToLeftForbidden = (*j).lane->getIndex();
    6094              :                 }
    6095              :             }
    6096              :         }
    6097     13962486 :         for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
    6098        31050 :             last[i].length = 0;
    6099              :         }
    6100              : #ifdef DEBUG_BESTLANES
    6101              :         if (DEBUG_COND) {
    6102              :             std::cout << "   last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
    6103              :             std::vector<LaneQ>& laneQs = myBestLanes.back();
    6104              :             for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
    6105              :                 std::cout << "     lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
    6106              :             }
    6107              :         }
    6108              : #endif
    6109              :     }
    6110              :     // go backward through the lanes
    6111              :     // track back best lane and compute the best prior lane(s)
    6112     59722138 :     for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
    6113              :         std::vector<LaneQ>& nextLanes = (*(i - 1));
    6114              :         std::vector<LaneQ>& clanes = (*i);
    6115     45790702 :         MSEdge* const cE = &clanes[0].lane->getEdge();
    6116              :         int index = 0;
    6117              :         double bestConnectedLength = -1;
    6118              :         double bestLength = -1;
    6119    113543092 :         for (const LaneQ& j : nextLanes) {
    6120    135504780 :             if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
    6121              :                 bestConnectedLength = j.length;
    6122              :             }
    6123     67752390 :             if (bestLength < j.length) {
    6124              :                 bestLength = j.length;
    6125              :             }
    6126              :         }
    6127              :         // compute index of the best lane (highest length and least offset from the best next lane)
    6128              :         int bestThisIndex = 0;
    6129              :         int bestThisMaxIndex = 0;
    6130     45790702 :         if (bestConnectedLength > 0) {
    6131              :             index = 0;
    6132    114031608 :             for (LaneQ& j : clanes) {
    6133              :                 const LaneQ* bestConnectedNext = nullptr;
    6134     68248359 :                 if (j.allowsContinuation) {
    6135    165213185 :                     for (const LaneQ& m : nextLanes) {
    6136    114037466 :                         if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
    6137    105184738 :                                 && m.lane->isApproachedFrom(cE, j.lane)) {
    6138     61835326 :                             if (betterContinuation(bestConnectedNext, m)) {
    6139              :                                 bestConnectedNext = &m;
    6140              :                             }
    6141              :                         }
    6142              :                     }
    6143     60081977 :                     if (bestConnectedNext != nullptr) {
    6144     60081977 :                         if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
    6145     58517214 :                             j.length += bestLength;
    6146              :                         } else {
    6147      1564763 :                             j.length += bestConnectedNext->length;
    6148              :                         }
    6149     60081977 :                         j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
    6150              :                     }
    6151              :                 }
    6152     60081977 :                 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
    6153     60056716 :                     copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
    6154              :                 } else {
    6155      8191643 :                     j.allowsContinuation = false;
    6156              :                 }
    6157     68248359 :                 if (clanes[bestThisIndex].length < j.length
    6158     62349840 :                         || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
    6159    189228062 :                         || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
    6160     58759032 :                             nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
    6161              :                    ) {
    6162              :                     bestThisIndex = index;
    6163              :                     bestThisMaxIndex = index;
    6164     62208653 :                 } else if (clanes[bestThisIndex].length == j.length
    6165     58747111 :                            && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
    6166    120955667 :                            && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
    6167              :                     bestThisMaxIndex = index;
    6168              :                 }
    6169     68248359 :                 index++;
    6170              :             }
    6171              : 
    6172              :             //vehicle with elecHybrid device prefers running under an overhead wire
    6173     45783249 :             if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
    6174              :                 index = 0;
    6175          221 :                 for (const LaneQ& j : clanes) {
    6176          159 :                     std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
    6177          159 :                     if (overheadWireSegmentID != "") {
    6178              :                         bestThisIndex = index;
    6179              :                         bestThisMaxIndex = index;
    6180              :                     }
    6181          159 :                     index++;
    6182              :                 }
    6183              :             }
    6184              : 
    6185              :         } else {
    6186              :             // only needed in case of disconnected routes
    6187              :             int bestNextIndex = 0;
    6188         7453 :             int bestDistToNeeded = (int) clanes.size();
    6189              :             index = 0;
    6190        19774 :             for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
    6191        12321 :                 if ((*j).allowsContinuation) {
    6192              :                     int nextIndex = 0;
    6193        26727 :                     for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
    6194        14406 :                         if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
    6195         5893 :                             if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
    6196              :                                 bestDistToNeeded = abs((*m).bestLaneOffset);
    6197              :                                 bestThisIndex = index;
    6198              :                                 bestThisMaxIndex = index;
    6199              :                                 bestNextIndex = nextIndex;
    6200              :                             }
    6201              :                         }
    6202              :                     }
    6203              :                 }
    6204              :             }
    6205         7453 :             clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
    6206         7453 :             copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
    6207              : 
    6208              :         }
    6209              :         // set bestLaneOffset for all lanes
    6210              :         index = 0;
    6211              :         bool requiredChangeRightForbidden = false;
    6212              :         int requireChangeToLeftForbidden = -1;
    6213    114051382 :         for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
    6214     68260680 :             if ((*j).length < clanes[bestThisIndex].length
    6215     58531155 :                     || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
    6216    126791684 :                     || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
    6217              :                ) {
    6218      9904953 :                 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
    6219       699442 :                     (*j).bestLaneOffset = bestThisIndex - index;
    6220              :                 } else {
    6221      9205511 :                     (*j).bestLaneOffset = bestThisMaxIndex - index;
    6222              :                 }
    6223      9904953 :                 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
    6224              :                     // try to move away from the lower-priority lane before it ends
    6225      8386924 :                     (*j).length = (*j).currentLength;
    6226              :                 }
    6227      9904953 :                 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
    6228      3151987 :                                                 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
    6229      3139448 :                                                 || requiredChangeRightForbidden)) {
    6230              :                     // this lane and all further lanes to the left cannot be used
    6231              :                     requiredChangeRightForbidden = true;
    6232        29722 :                     if ((*j).length == (*j).currentLength) {
    6233        26851 :                         (*j).length = 0;
    6234              :                     }
    6235      9875231 :                 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
    6236      6696048 :                                                        || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
    6237              :                     // this lane and all previous lanes to the right cannot be used
    6238        94374 :                     requireChangeToLeftForbidden = (*j).lane->getIndex();
    6239              :                 }
    6240              :             } else {
    6241     58355727 :                 (*j).bestLaneOffset = 0;
    6242              :             }
    6243              :         }
    6244     45894287 :         for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
    6245       103585 :             if (clanes[idx].length == clanes[idx].currentLength) {
    6246        97758 :                 clanes[idx].length = 0;
    6247              :             };
    6248              :         }
    6249              : 
    6250              :         //vehicle with elecHybrid device prefers running under an overhead wire
    6251     45790702 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    6252              :             index = 0;
    6253           62 :             std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
    6254           62 :             if (overheadWireID != "") {
    6255          211 :                 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
    6256          153 :                     (*j).bestLaneOffset = bestThisIndex - index;
    6257              :                 }
    6258              :             }
    6259              :         }
    6260              : 
    6261              : #ifdef DEBUG_BESTLANES
    6262              :         if (DEBUG_COND) {
    6263              :             std::cout << "   edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
    6264              :             std::vector<LaneQ>& laneQs = clanes;
    6265              :             for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
    6266              :                 std::cout << "     lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
    6267              :             }
    6268              :         }
    6269              : #endif
    6270              : 
    6271              :     }
    6272     13931436 :     updateOccupancyAndCurrentBestLane(startLane);
    6273              : #ifdef DEBUG_BESTLANES
    6274              :     if (DEBUG_COND) {
    6275              :         std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
    6276              :     }
    6277              : #endif
    6278              : }
    6279              : 
    6280              : void
    6281          245 : MSVehicle::updateLaneBruttoSum() {
    6282          245 :     if (myLane != nullptr) {
    6283          245 :         myLane->markRecalculateBruttoSum();
    6284              :     }
    6285          245 : }
    6286              : 
    6287              : bool
    6288     61835326 : MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
    6289     61835326 :     if (bestConnectedNext == nullptr) {
    6290              :         return true;
    6291      1753349 :     } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
    6292              :         return false;
    6293      1752611 :     } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
    6294              :         return true;
    6295      1752611 :     } else if (bestConnectedNext->length < m.length) {
    6296              :         return true;
    6297      1506059 :     } else if (bestConnectedNext->length == m.length) {
    6298      1131342 :         if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
    6299              :             return true;
    6300              :         }
    6301      1032928 :         const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
    6302              :         if (contRight < 1
    6303              :                 // if we don't check for adjacency, the rightmost line will get
    6304              :                 // multiple chances to be better which leads to an uninituitve distribution
    6305         1000 :                 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
    6306      1033701 :                 && RandHelper::rand(getRNG()) > contRight) {
    6307              :             return true;
    6308              :         }
    6309              :     }
    6310              :     return false;
    6311              : }
    6312              : 
    6313              : 
    6314              : int
    6315    371884006 : MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
    6316    371884006 :     if (conts.size() < 2) {
    6317              :         return -1;
    6318              :     } else {
    6319    342508473 :         const MSLink* const link = conts[0]->getLinkTo(conts[1]);
    6320    342508473 :         if (link != nullptr) {
    6321    342504301 :             return link->havePriority() ? 1 : 0;
    6322              :         } else {
    6323              :             // disconnected route
    6324              :             return -1;
    6325              :         }
    6326              :     }
    6327              : }
    6328              : 
    6329              : 
    6330              : void
    6331    732872059 : MSVehicle::updateOccupancyAndCurrentBestLane(const MSLane* startLane) {
    6332              :     std::vector<LaneQ>& currLanes = *myBestLanes.begin();
    6333              :     std::vector<LaneQ>::iterator i;
    6334   1867029037 :     for (i = currLanes.begin(); i != currLanes.end(); ++i) {
    6335              :         double nextOccupation = 0;
    6336   3438345591 :         for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
    6337   2304188613 :             nextOccupation += (*j)->getBruttoVehLenSum();
    6338              :         }
    6339   1134156978 :         (*i).nextOccupation = nextOccupation;
    6340              : #ifdef DEBUG_BESTLANES
    6341              :         if (DEBUG_COND) {
    6342              :             std::cout << "     lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
    6343              :         }
    6344              : #endif
    6345   1134156978 :         if ((*i).lane == startLane) {
    6346    728732700 :             myCurrentLaneInBestLanes = i;
    6347              :         }
    6348              :     }
    6349    732872059 : }
    6350              : 
    6351              : 
    6352              : const std::vector<MSLane*>&
    6353   1206831261 : MSVehicle::getBestLanesContinuation() const {
    6354   1206831261 :     if (myBestLanes.empty() || myBestLanes[0].empty()) {
    6355              :         return myEmptyLaneVector;
    6356              :     }
    6357   1206831261 :     return (*myCurrentLaneInBestLanes).bestContinuations;
    6358              : }
    6359              : 
    6360              : 
    6361              : const std::vector<MSLane*>&
    6362     53093439 : MSVehicle::getBestLanesContinuation(const MSLane* const l) const {
    6363              :     const MSLane* lane = l;
    6364              :     // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
    6365     53093439 :     if (lane->getEdge().isInternal()) {
    6366              :         // internal edges are not kept inside the bestLanes structure
    6367      4345664 :         lane = lane->getLinkCont()[0]->getLane();
    6368              :     }
    6369     53093439 :     if (myBestLanes.size() == 0) {
    6370              :         return myEmptyLaneVector;
    6371              :     }
    6372     84942304 :     for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
    6373     84928258 :         if ((*i).lane == lane) {
    6374     53079393 :             return (*i).bestContinuations;
    6375              :         }
    6376              :     }
    6377              :     return myEmptyLaneVector;
    6378              : }
    6379              : 
    6380              : const std::vector<const MSLane*>
    6381       144304 : MSVehicle::getUpcomingLanesUntil(double distance) const {
    6382              :     std::vector<const MSLane*> lanes;
    6383              : 
    6384       144304 :     if (distance <= 0. || hasArrived()) {
    6385              :         // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
    6386              :         return lanes;
    6387              :     }
    6388              : 
    6389       144120 :     if (!myLaneChangeModel->isOpposite()) {
    6390       142447 :         distance += getPositionOnLane();
    6391              :     } else {
    6392         1673 :         distance += myLane->getOppositePos(getPositionOnLane());
    6393              :     }
    6394       144120 :     MSLane* lane = myLaneChangeModel->isOpposite() ? myLane->getParallelOpposite() : myLane;
    6395       148848 :     while (lane->isInternal() && (distance > 0.)) {  // include initial internal lanes
    6396         4728 :         lanes.insert(lanes.end(), lane);
    6397         4728 :         distance -= lane->getLength();
    6398         8117 :         lane = lane->getLinkCont().front()->getViaLaneOrLane();
    6399              :     }
    6400              : 
    6401       144120 :     const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
    6402       144120 :     if (contLanes.empty()) {
    6403              :         return lanes;
    6404              :     }
    6405              :     auto contLanesIt = contLanes.begin();
    6406       144120 :     MSRouteIterator routeIt = myCurrEdge;  // keep track of covered edges in myRoute
    6407       315935 :     while (distance > 0.) {
    6408       179579 :         MSLane* l = nullptr;
    6409       179579 :         if (contLanesIt != contLanes.end()) {
    6410       169597 :             l = *contLanesIt;
    6411              :             if (l != nullptr) {
    6412              :                 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
    6413              :             }
    6414              :             ++contLanesIt;
    6415       169597 :             if (l != nullptr || myLane->isInternal()) {
    6416              :                 ++routeIt;
    6417              :             }
    6418       169597 :             if (l == nullptr) {
    6419         3385 :                 continue;
    6420              :             }
    6421         9982 :         } else if (routeIt != myRoute->end()) {  // bestLanes didn't get us far enough
    6422              :             // choose left-most lane as default (avoid sidewalks, bike lanes etc)
    6423         3105 :             l = (*routeIt)->getLanes().back();
    6424              :             ++routeIt;
    6425              :         } else {  // the search distance goes beyond our route
    6426              :             break;
    6427              :         }
    6428              : 
    6429              :         assert(l != nullptr);
    6430              : 
    6431              :         // insert internal lanes if applicable
    6432       169317 :         const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
    6433       203817 :         while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
    6434        34500 :             lanes.insert(lanes.end(), internalLane);
    6435        34500 :             distance -= internalLane->getLength();
    6436        56084 :             internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
    6437              :         }
    6438       169317 :         if (distance <= 0.) {
    6439              :             break;
    6440              :         }
    6441              : 
    6442       168430 :         lanes.insert(lanes.end(), l);
    6443       168430 :         distance -= l->getLength();
    6444              :     }
    6445              : 
    6446              :     return lanes;
    6447            0 : }
    6448              : 
    6449              : const std::vector<const MSLane*>
    6450         7638 : MSVehicle::getPastLanesUntil(double distance) const {
    6451              :     std::vector<const MSLane*> lanes;
    6452              : 
    6453         7638 :     if (distance <= 0.) {
    6454              :         // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
    6455              :         return lanes;
    6456              :     }
    6457              : 
    6458         7530 :     MSRouteIterator routeIt = myCurrEdge;
    6459         7530 :     if (!myLaneChangeModel->isOpposite()) {
    6460         7506 :         distance += myLane->getLength() - getPositionOnLane();
    6461              :     } else {
    6462           24 :         distance += myLane->getParallelOpposite()->getLength() - myLane->getOppositePos(getPositionOnLane());
    6463              :     }
    6464         7530 :     MSLane* lane = myLaneChangeModel->isOpposite() ? myLane->getParallelOpposite() : myLane;
    6465         7948 :     while (lane->isInternal() && (distance > 0.)) {  // include initial internal lanes
    6466          418 :         lanes.insert(lanes.end(), lane);
    6467          418 :         distance -= lane->getLength();
    6468          418 :         lane = lane->getLogicalPredecessorLane();
    6469              :     }
    6470              : 
    6471        12524 :     while (distance > 0.) {
    6472              :         // choose left-most lane as default (avoid sidewalks, bike lanes etc)
    6473        10305 :         MSLane* l = (*routeIt)->getLanes().back();
    6474              : 
    6475              :         // insert internal lanes if applicable
    6476        10305 :         const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
    6477        10723 :         const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
    6478              :         std::vector<const MSLane*> internalLanes;
    6479        13087 :         while ((internalLane != nullptr) && internalLane->isInternal()) {  // collect all internal successor lanes
    6480         2782 :             internalLanes.insert(internalLanes.begin(), internalLane);
    6481         5557 :             internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
    6482              :         }
    6483        13087 :         for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) {  // check remaining distance in correct order
    6484         2782 :             lanes.insert(lanes.end(), *it);
    6485         2782 :             distance -= (*it)->getLength();
    6486              :         }
    6487        10305 :         if (distance <= 0.) {
    6488              :             break;
    6489              :         }
    6490              : 
    6491        10289 :         lanes.insert(lanes.end(), l);
    6492        10289 :         distance -= l->getLength();
    6493              : 
    6494              :         // NOTE: we're going backwards with the (bi-directional) Iterator
    6495              :         // TODO: consider make reverse_iterator() when moving on to C++14 or later
    6496        10289 :         if (routeIt != myRoute->begin()) {
    6497              :             --routeIt;
    6498              :         } else {  // we went backwards to begin() and already processed the first and final element
    6499              :             break;
    6500              :         }
    6501        10305 :     }
    6502              : 
    6503              :     return lanes;
    6504            0 : }
    6505              : 
    6506              : 
    6507              : const std::vector<MSLane*>
    6508         7302 : MSVehicle::getUpstreamOppositeLanes() const {
    6509         7302 :     const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
    6510              :     std::vector<MSLane*> result;
    6511        18922 :     for (const MSLane* lane : routeLanes) {
    6512        12363 :         MSLane* opposite = lane->getOpposite();
    6513        12363 :         if (opposite != nullptr) {
    6514        11620 :             result.push_back(opposite);
    6515              :         } else {
    6516              :             break;
    6517              :         }
    6518              :     }
    6519         7302 :     return result;
    6520         7302 : }
    6521              : 
    6522              : 
    6523              : int
    6524    286072460 : MSVehicle::getBestLaneOffset() const {
    6525    286072460 :     if (myBestLanes.empty() || myBestLanes[0].empty()) {
    6526              :         return 0;
    6527              :     } else {
    6528    285580365 :         return (*myCurrentLaneInBestLanes).bestLaneOffset;
    6529              :     }
    6530              : }
    6531              : 
    6532              : double
    6533        19587 : MSVehicle::getBestLaneDist() const {
    6534        19587 :     if (myBestLanes.empty() || myBestLanes[0].empty()) {
    6535              :         return -1;
    6536              :     } else {
    6537        19587 :         return (*myCurrentLaneInBestLanes).length;
    6538              :     }
    6539              : }
    6540              : 
    6541              : 
    6542              : 
    6543              : void
    6544    316662771 : MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
    6545              :     std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
    6546              :     assert(laneIndex < (int)preb.size());
    6547    316662771 :     preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
    6548    316662771 : }
    6549              : 
    6550              : 
    6551              : void
    6552        54785 : MSVehicle::fixPosition() {
    6553        54785 :     if (MSGlobals::gLaneChangeDuration > 0 && !myLaneChangeModel->isChangingLanes()) {
    6554        33108 :         myState.myPosLat = 0;
    6555              :     }
    6556        54785 : }
    6557              : 
    6558              : std::pair<const MSLane*, double>
    6559          151 : MSVehicle::getLanePosAfterDist(double distance) const {
    6560          151 :     if (distance == 0) {
    6561          135 :         return std::make_pair(myLane, getPositionOnLane());
    6562              :     }
    6563           16 :     const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
    6564           16 :     distance += getPositionOnLane();
    6565           16 :     for (const MSLane* lane : lanes) {
    6566           16 :         if (lane->getLength() > distance) {
    6567              :             return std::make_pair(lane, distance);
    6568              :         }
    6569            0 :         distance -= lane->getLength();
    6570              :     }
    6571            0 :     return std::make_pair(nullptr, -1);
    6572           16 : }
    6573              : 
    6574              : 
    6575              : double
    6576        15965 : MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
    6577        15965 :     if (isOnRoad() && destLane != nullptr) {
    6578        15934 :         return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
    6579              :     }
    6580              :     return std::numeric_limits<double>::max();
    6581              : }
    6582              : 
    6583              : 
    6584              : std::pair<const MSVehicle* const, double>
    6585     76397636 : MSVehicle::getLeader(double dist) const {
    6586     76397636 :     if (myLane == nullptr) {
    6587            0 :         return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
    6588              :     }
    6589     76397636 :     if (dist == 0) {
    6590         2458 :         dist = getCarFollowModel().brakeGap(getSpeed()) + getVehicleType().getMinGap();
    6591              :     }
    6592              :     const MSVehicle* lead = nullptr;
    6593     76397636 :     const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
    6594     76397636 :     const MSLane::VehCont& vehs = lane->getVehiclesSecure();
    6595              :     // vehicle might be outside the road network
    6596     76397636 :     MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
    6597     76397636 :     if (it != vehs.end() && it + 1 != vehs.end()) {
    6598     72693158 :         lead = *(it + 1);
    6599              :     }
    6600     72693158 :     if (lead != nullptr) {
    6601              :         std::pair<const MSVehicle* const, double> result(
    6602     72693158 :             lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
    6603     72693158 :         lane->releaseVehicles();
    6604     72693158 :         return result;
    6605              :     }
    6606      3704478 :     const double seen = myLane->getLength() - getPositionOnLane();
    6607      3704478 :     const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
    6608      3704478 :     std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts);
    6609      3704475 :     lane->releaseVehicles();
    6610      3704475 :     return result;
    6611              : }
    6612              : 
    6613              : 
    6614              : std::pair<const MSVehicle* const, double>
    6615      2396270 : MSVehicle::getFollower(double dist) const {
    6616      2396270 :     if (myLane == nullptr) {
    6617            0 :         return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
    6618              :     }
    6619      2396270 :     if (dist == 0) {
    6620       737070 :         dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
    6621              :     }
    6622      2396270 :     return myLane->getFollower(this, getPositionOnLane(), dist, MSLane::MinorLinkMode::FOLLOW_NEVER);
    6623              : }
    6624              : 
    6625              : 
    6626              : double
    6627            0 : MSVehicle::getTimeGapOnLane() const {
    6628              :     // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
    6629            0 :     std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
    6630            0 :     if (leaderInfo.first == nullptr || getSpeed() == 0) {
    6631            0 :         return -1;
    6632              :     }
    6633            0 :     return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
    6634              : }
    6635              : 
    6636              : 
    6637              : void
    6638        10433 : MSVehicle::addTransportable(MSTransportable* transportable) {
    6639        10433 :     MSBaseVehicle::addTransportable(transportable);
    6640        10433 :     if (myStops.size() > 0 && myStops.front().reached) {
    6641         7483 :         if (transportable->isPerson()) {
    6642         7032 :             if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
    6643         1358 :                 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
    6644              :             }
    6645              :         } else {
    6646          451 :             if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
    6647           20 :                 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
    6648              :             }
    6649              :         }
    6650              :     }
    6651        10433 : }
    6652              : 
    6653              : 
    6654              : void
    6655    537967223 : MSVehicle::setBlinkerInformation() {
    6656              :     switchOffSignal(VEH_SIGNAL_BLINKER_RIGHT | VEH_SIGNAL_BLINKER_LEFT);
    6657    537967223 :     int state = myLaneChangeModel->getOwnState();
    6658              :     // do not set blinker for sublane changes or when blocked from changing to the right
    6659    537967223 :     const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
    6660    454511944 :                                        (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
    6661              :     Signalling left = VEH_SIGNAL_BLINKER_LEFT;
    6662              :     Signalling right = VEH_SIGNAL_BLINKER_RIGHT;
    6663    537967223 :     if (MSGlobals::gLefthand) {
    6664              :         // lane indices increase from left to right
    6665              :         std::swap(left, right);
    6666              :     }
    6667    537967223 :     if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
    6668     14936851 :         switchOnSignal(left);
    6669    523030372 :     } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
    6670      4791406 :         switchOnSignal(right);
    6671    518238966 :     } else if (myLaneChangeModel->isChangingLanes()) {
    6672       242673 :         if (myLaneChangeModel->getLaneChangeDirection() == 1) {
    6673       159559 :             switchOnSignal(left);
    6674              :         } else {
    6675        83114 :             switchOnSignal(right);
    6676              :         }
    6677              :     } else {
    6678    517996293 :         const MSLane* lane = getLane();
    6679    517996293 :         std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
    6680    517996293 :         if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
    6681    145923638 :             switch ((*link)->getDirection()) {
    6682              :                 case LinkDirection::TURN:
    6683              :                 case LinkDirection::LEFT:
    6684              :                 case LinkDirection::PARTLEFT:
    6685              :                     switchOnSignal(VEH_SIGNAL_BLINKER_LEFT);
    6686              :                     break;
    6687              :                 case LinkDirection::RIGHT:
    6688              :                 case LinkDirection::PARTRIGHT:
    6689              :                     switchOnSignal(VEH_SIGNAL_BLINKER_RIGHT);
    6690              :                     break;
    6691              :                 default:
    6692              :                     break;
    6693              :             }
    6694              :         }
    6695              :     }
    6696              :     // stopping related signals
    6697    537967223 :     if (hasStops()
    6698    537967223 :             && (myStops.begin()->reached ||
    6699     10949134 :                 (myStopDist < (myLane->getLength() - getPositionOnLane())
    6700      2351641 :                  && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
    6701     15279310 :         if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
    6702              :             // not stopping on the right. Activate emergency blinkers
    6703              :             switchOnSignal(VEH_SIGNAL_BLINKER_LEFT | VEH_SIGNAL_BLINKER_RIGHT);
    6704     15195395 :         } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
    6705              :             // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
    6706       384414 :             switchOnSignal(MSGlobals::gLefthand ? VEH_SIGNAL_BLINKER_LEFT : VEH_SIGNAL_BLINKER_RIGHT);
    6707              :         }
    6708              :     }
    6709    537967223 :     if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
    6710           15 :         mySignals = myInfluencer->getSignals();
    6711              :         myInfluencer->setSignals(-1); // overwrite computed signals only once
    6712              :     }
    6713    537967223 : }
    6714              : 
    6715              : void
    6716        72477 : MSVehicle::setEmergencyBlueLight(SUMOTime currentTime) {
    6717              : 
    6718              :     //TODO look if timestep ist SIMSTEP
    6719        72477 :     if (currentTime % 1000 == 0) {
    6720        24167 :         if (signalSet(VEH_SIGNAL_EMERGENCY_BLUE)) {
    6721              :             switchOffSignal(VEH_SIGNAL_EMERGENCY_BLUE);
    6722              :         } else {
    6723              :             switchOnSignal(VEH_SIGNAL_EMERGENCY_BLUE);
    6724              :         }
    6725              :     }
    6726        72477 : }
    6727              : 
    6728              : 
    6729              : int
    6730     16703543 : MSVehicle::getLaneIndex() const {
    6731     16703543 :     return myLane == nullptr ? -1 : myLane->getIndex();
    6732              : }
    6733              : 
    6734              : 
    6735              : void
    6736     10944923 : MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
    6737     10944923 :     myLane = lane;
    6738     10944923 :     myState.myPos = pos;
    6739     10944923 :     myState.myPosLat = posLat;
    6740     10944923 :     myState.myBackPos = pos - getVehicleType().getLength();
    6741     10944923 : }
    6742              : 
    6743              : 
    6744              : double
    6745    352205472 : MSVehicle::getRightSideOnLane() const {
    6746    352205472 :     return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
    6747              : }
    6748              : 
    6749              : 
    6750              : double
    6751    346849678 : MSVehicle::getLeftSideOnLane() const {
    6752    346849678 :     return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
    6753              : }
    6754              : 
    6755              : 
    6756              : double
    6757    277672648 : MSVehicle::getRightSideOnLane(const MSLane* lane) const {
    6758    277672648 :     return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
    6759              : }
    6760              : 
    6761              : 
    6762              : double
    6763    277294378 : MSVehicle::getLeftSideOnLane(const MSLane* lane) const {
    6764    277294378 :     return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
    6765              : }
    6766              : 
    6767              : 
    6768              : double
    6769    115295897 : MSVehicle::getRightSideOnEdge(const MSLane* lane) const {
    6770    115295897 :     return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
    6771              : }
    6772              : 
    6773              : 
    6774              : double
    6775     27191409 : MSVehicle::getLeftSideOnEdge(const MSLane* lane) const {
    6776     27191409 :     return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
    6777              : }
    6778              : 
    6779              : 
    6780              : double
    6781    538113190 : MSVehicle::getCenterOnEdge(const MSLane* lane) const {
    6782    538113190 :     if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
    6783    537694764 :         return myLane->getRightSideOnEdge() + myState.myPosLat + 0.5 * myLane->getWidth();
    6784       418426 :     } else if (lane == myLaneChangeModel->getShadowLane()) {
    6785        14023 :         if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
    6786        14019 :             return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
    6787              :         }
    6788            4 :         if (myLaneChangeModel->getShadowDirection() == -1) {
    6789            0 :             return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
    6790              :         } else {
    6791            4 :             return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
    6792              :         }
    6793       404403 :     } else if (lane == myLane->getBidiLane()) {
    6794         1274 :         return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
    6795              :     } else {
    6796              :         assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
    6797       472188 :         for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
    6798       447161 :             if (myFurtherLanes[i] == lane) {
    6799              : #ifdef DEBUG_FURTHER
    6800              :                 if (DEBUG_COND) std::cout << "    getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
    6801              :                                               << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
    6802              :                                               << "\n";
    6803              : #endif
    6804       378042 :                 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
    6805        69119 :             } else if (myFurtherLanes[i]->getBidiLane() == lane) {
    6806              : #ifdef DEBUG_FURTHER
    6807              :                 if (DEBUG_COND) std::cout << "    getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
    6808              :                                               << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
    6809              :                                               << "\n";
    6810              : #endif
    6811           60 :                 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
    6812              :             }
    6813              :         }
    6814              :         //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
    6815        25027 :         const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
    6816        25477 :         for (int i = 0; i < (int)shadowFurther.size(); ++i) {
    6817              :             //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
    6818        25477 :             if (shadowFurther[i] == lane) {
    6819              :                 assert(myLaneChangeModel->getShadowLane() != 0);
    6820        25027 :                 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
    6821        25027 :                         + (myLane->getCenterOnEdge() - myLaneChangeModel->getShadowLane()->getCenterOnEdge()));
    6822              :             }
    6823              :         }
    6824              :         assert(false);
    6825            0 :         throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
    6826              :     }
    6827              : }
    6828              : 
    6829              : 
    6830              : double
    6831   2893885744 : MSVehicle::getLatOffset(const MSLane* lane) const {
    6832              :     assert(lane != 0);
    6833   2893885744 :     if (&lane->getEdge() == &myLane->getEdge()) {
    6834   2850692884 :         return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
    6835     43192860 :     } else if (myLane->getParallelOpposite() == lane) {
    6836      2175142 :         return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
    6837     41017718 :     } else if (myLane->getBidiLane() == lane) {
    6838       182895 :         return -2 * getLateralPositionOnLane();
    6839              :     } else {
    6840              :         // Check whether the lane is a further lane for the vehicle
    6841     46042104 :         for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
    6842     45232545 :             if (myFurtherLanes[i] == lane) {
    6843              : #ifdef DEBUG_FURTHER
    6844              :                 if (DEBUG_COND) {
    6845              :                     std::cout << "    getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
    6846              :                 }
    6847              : #endif
    6848     39991930 :                 return myFurtherLanesPosLat[i] - myState.myPosLat;
    6849      5240615 :             } else if (myFurtherLanes[i]->getBidiLane() == lane) {
    6850              : #ifdef DEBUG_FURTHER
    6851              :                 if (DEBUG_COND) {
    6852              :                     std::cout << "    getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
    6853              :                 }
    6854              : #endif
    6855        33334 :                 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
    6856              :             }
    6857              :         }
    6858              : #ifdef DEBUG_FURTHER
    6859              :         if (DEBUG_COND) {
    6860              :             std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
    6861              :         }
    6862              : #endif
    6863              :         // Check whether the lane is a "shadow further lane" for the vehicle
    6864       809559 :         const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
    6865       821573 :         for (int i = 0; i < (int)shadowFurther.size(); ++i) {
    6866       819497 :             if (shadowFurther[i] == lane) {
    6867              : #ifdef DEBUG_FURTHER
    6868              :                 if (DEBUG_COND) std::cout << "    getLatOffset veh=" << getID()
    6869              :                                               << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
    6870              :                                               << " lane=" << lane->getID()
    6871              :                                               << " i=" << i
    6872              :                                               << " posLat=" << myState.myPosLat
    6873              :                                               << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
    6874              :                                               << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
    6875              :                                               <<  "\n";
    6876              : #endif
    6877       807483 :                 return getLatOffset(myLaneChangeModel->getShadowLane()) + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] - myState.myPosLat;
    6878              :             }
    6879              :         }
    6880              :         // Check whether the vehicle issued a maneuverReservation on the lane.
    6881              :         const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
    6882         2350 :         for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
    6883              :             // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
    6884         2347 :             MSLane* targetLane = furtherTargets[i];
    6885         2347 :             if (targetLane == lane) {
    6886         2073 :                 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
    6887         2073 :                 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
    6888              : #ifdef DEBUG_TARGET_LANE
    6889              :                 if (DEBUG_COND) {
    6890              :                     std::cout << "    getLatOffset veh=" << getID()
    6891              :                               << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
    6892              :                               << "\n    i=" << i
    6893              :                               << " posLat=" << myState.myPosLat
    6894              :                               << " furtherPosLat=" << myFurtherLanesPosLat[i]
    6895              :                               << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
    6896              :                               << " targetDir=" << targetDir
    6897              :                               << " latOffset=" << latOffset
    6898              :                               <<  std::endl;
    6899              :                 }
    6900              : #endif
    6901         2073 :                 return latOffset;
    6902              :             }
    6903              :         }
    6904              :         assert(false);
    6905           15 :         throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
    6906              :     }
    6907              : }
    6908              : 
    6909              : 
    6910              : double
    6911     31357233 : MSVehicle::lateralDistanceToLane(const int offset) const {
    6912              :     // compute the distance when changing to the neighboring lane
    6913              :     // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
    6914              :     assert(offset == 0 || offset == 1 || offset == -1);
    6915              :     assert(myLane != nullptr);
    6916              :     assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
    6917     31357233 :     const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
    6918     31357233 :     const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
    6919     31357233 :     const double latPos = getLateralPositionOnLane();
    6920     31357233 :     const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
    6921     31357233 :     double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
    6922     31357233 :     double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
    6923              :     double latLaneDist = 0;  // minimum distance to move the vehicle fully onto the new lane
    6924     31357233 :     if (offset == 0) {
    6925           10 :         if (latPos + halfVehWidth > halfCurrentLaneWidth) {
    6926              :             // correct overlapping left
    6927            5 :             latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
    6928            5 :         } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
    6929              :             // correct overlapping right
    6930            5 :             latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
    6931              :         }
    6932           10 :         latLaneDist *= oppositeSign;
    6933     31357223 :     } else if (offset == -1) {
    6934     14144247 :         latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
    6935     17212976 :     } else if (offset == 1) {
    6936     17212976 :         latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
    6937              :     }
    6938              : #ifdef DEBUG_ACTIONSTEPS
    6939              :     if (DEBUG_COND) {
    6940              :         std::cout << SIMTIME
    6941              :                   << " veh=" << getID()
    6942              :                   << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
    6943              :                   << " halfVehWidth=" << halfVehWidth
    6944              :                   << " latPos=" << latPos
    6945              :                   << " latLaneDist=" << latLaneDist
    6946              :                   << " leftLimit=" << leftLimit
    6947              :                   << " rightLimit=" << rightLimit
    6948              :                   << "\n";
    6949              :     }
    6950              : #endif
    6951     31357233 :     return latLaneDist;
    6952              : }
    6953              : 
    6954              : 
    6955              : double
    6956   4242186220 : MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
    6957   4242186220 :     return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
    6958   4242186220 :             - 0.5 * lane->getWidth());
    6959              : }
    6960              : 
    6961              : double
    6962            0 : MSVehicle::getLateralOverlap(const MSLane* lane) const {
    6963            0 :     return getLateralOverlap(getLateralPositionOnLane(), lane);
    6964              : }
    6965              : 
    6966              : double
    6967   4069476052 : MSVehicle::getLateralOverlap() const {
    6968   4069476052 :     return getLateralOverlap(getLateralPositionOnLane(), myLane);
    6969              : }
    6970              : 
    6971              : 
    6972              : void
    6973    474689802 : MSVehicle::removeApproachingInformation(const DriveItemVector& lfLinks) const {
    6974   1458231951 :     for (const DriveProcessItem& dpi : lfLinks) {
    6975    983542149 :         if (dpi.myLink != nullptr) {
    6976    766097118 :             dpi.myLink->removeApproaching(this);
    6977              :         }
    6978              :     }
    6979              :     // unregister on all shadow links
    6980    474689802 :     myLaneChangeModel->removeShadowApproachingInformation();
    6981    474689802 : }
    6982              : 
    6983              : 
    6984              : bool
    6985       667945 : MSVehicle::unsafeLinkAhead(const MSLane* lane) const {
    6986              :     // the following links are unsafe:
    6987              :     // - zipper links if they are close enough and have approaching vehicles in the relevant time range
    6988              :     // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
    6989       667945 :     double seen = myLane->getLength() - getPositionOnLane();
    6990       667945 :     const double dist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
    6991       667945 :     if (seen < dist) {
    6992        45476 :         const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
    6993              :         int view = 1;
    6994        45476 :         std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
    6995              :         DriveItemVector::const_iterator di = myLFLinkLanes.begin();
    6996        93513 :         while (!lane->isLinkEnd(link) && seen <= dist) {
    6997              :             if (!lane->getEdge().isInternal()
    6998        48781 :                     && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
    6999        25245 :                         || !(*link)->havePriority())) {
    7000              :                 // find the drive item corresponding to this link
    7001              :                 bool found = false;
    7002         1738 :                 while (di != myLFLinkLanes.end() && !found) {
    7003          874 :                     if ((*di).myLink != nullptr) {
    7004              :                         const MSLane* diPredLane = (*di).myLink->getLaneBefore();
    7005          874 :                         if (diPredLane != nullptr) {
    7006          874 :                             if (&diPredLane->getEdge() == &lane->getEdge()) {
    7007              :                                 found = true;
    7008              :                             }
    7009              :                         }
    7010              :                     }
    7011          874 :                     if (!found) {
    7012              :                         di++;
    7013              :                     }
    7014              :                 }
    7015          864 :                 if (found) {
    7016          864 :                     const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
    7017          864 :                                                (*di).getLeaveSpeed(), getVehicleType().getLength());
    7018          864 :                     if ((*link)->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
    7019              :                         //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
    7020              :                         return true;
    7021              :                     }
    7022              :                 }
    7023              :                 // no drive item is found if the vehicle aborts its request within dist
    7024              :             }
    7025        48037 :             lane = (*link)->getViaLaneOrLane();
    7026        48037 :             if (!lane->getEdge().isInternal()) {
    7027        26949 :                 view++;
    7028              :             }
    7029        48037 :             seen += lane->getLength();
    7030        48037 :             link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
    7031              :         }
    7032              :     }
    7033              :     return false;
    7034              : }
    7035              : 
    7036              : 
    7037              : PositionVector
    7038      5776779 : MSVehicle::getBoundingBox(double offset) const {
    7039      5776779 :     PositionVector centerLine;
    7040      5776779 :     Position pos = getPosition();
    7041      5776779 :     centerLine.push_back(pos);
    7042      5776779 :     switch (myType->getGuiShape()) {
    7043         1730 :         case SUMOVehicleShape::BUS_FLEXIBLE:
    7044              :         case SUMOVehicleShape::RAIL:
    7045              :         case SUMOVehicleShape::RAIL_CAR:
    7046              :         case SUMOVehicleShape::RAIL_CARGO:
    7047              :         case SUMOVehicleShape::TRUCK_SEMITRAILER:
    7048              :         case SUMOVehicleShape::TRUCK_1TRAILER: {
    7049         4460 :             for (MSLane* lane : myFurtherLanes) {
    7050         2730 :                 centerLine.push_back(lane->getShape().back());
    7051              :             }
    7052              :             break;
    7053              :         }
    7054              :         default:
    7055              :             break;
    7056              :     }
    7057      5776779 :     double l = getLength();
    7058      5776779 :     Position backPos = getBackPosition();
    7059      5776779 :     if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
    7060              :         // getBackPosition may not match the visual back in networks without internal lanes
    7061       272627 :         double a = getAngle() + M_PI; // angle pointing backwards
    7062       272627 :         backPos = pos + Position(l * cos(a), l * sin(a));
    7063              :     }
    7064      5776779 :     centerLine.push_back(backPos);
    7065      5776779 :     if (offset != 0) {
    7066         6543 :         centerLine.extrapolate2D(offset);
    7067              :     }
    7068              :     PositionVector result = centerLine;
    7069     11549268 :     result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
    7070     11549268 :     centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
    7071      5776779 :     result.append(centerLine.reverse(), POSITION_EPS);
    7072      5776779 :     return result;
    7073      5776779 : }
    7074              : 
    7075              : 
    7076              : PositionVector
    7077        65817 : MSVehicle::getBoundingPoly(double offset) const {
    7078        65817 :     switch (myType->getGuiShape()) {
    7079        65392 :         case SUMOVehicleShape::PASSENGER:
    7080              :         case SUMOVehicleShape::PASSENGER_SEDAN:
    7081              :         case SUMOVehicleShape::PASSENGER_HATCHBACK:
    7082              :         case SUMOVehicleShape::PASSENGER_WAGON:
    7083              :         case SUMOVehicleShape::PASSENGER_VAN: {
    7084              :             // box with corners cut off
    7085        65392 :             PositionVector result;
    7086        65392 :             PositionVector centerLine;
    7087        65392 :             centerLine.push_back(getPosition());
    7088        65392 :             centerLine.push_back(getBackPosition());
    7089        65392 :             if (offset != 0) {
    7090         1600 :                 centerLine.extrapolate2D(offset);
    7091              :             }
    7092              :             PositionVector line1 = centerLine;
    7093              :             PositionVector line2 = centerLine;
    7094       130784 :             line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
    7095       130784 :             line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
    7096        65392 :             line2.scaleRelative(0.8);
    7097        65392 :             result.push_back(line1[0]);
    7098        65392 :             result.push_back(line2[0]);
    7099        65392 :             result.push_back(line2[1]);
    7100        65392 :             result.push_back(line1[1]);
    7101       130784 :             line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
    7102       130784 :             line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
    7103        65392 :             result.push_back(line1[1]);
    7104        65392 :             result.push_back(line2[1]);
    7105        65392 :             result.push_back(line2[0]);
    7106        65392 :             result.push_back(line1[0]);
    7107              :             return result;
    7108        65392 :         }
    7109          425 :         default:
    7110          425 :             return getBoundingBox();
    7111              :     }
    7112              : }
    7113              : 
    7114              : 
    7115              : bool
    7116     12042412 : MSVehicle::onFurtherEdge(const MSEdge* edge) const {
    7117     15731288 :     for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
    7118      4974469 :         if (&(*i)->getEdge() == edge) {
    7119              :             return true;
    7120              :         }
    7121              :     }
    7122              :     return false;
    7123              : }
    7124              : 
    7125              : 
    7126              : bool
    7127   6519765046 : MSVehicle::isBidiOn(const MSLane* lane) const {
    7128   6520889524 :     return lane->getBidiLane() != nullptr && (
    7129      1124478 :                myLane == lane->getBidiLane()
    7130       560362 :                || onFurtherEdge(&lane->getBidiLane()->getEdge()));
    7131              : }
    7132              : 
    7133              : 
    7134              : bool
    7135           14 : MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
    7136              :     // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
    7137              :     // consistency in the behaviour.
    7138              : 
    7139              :     // get vehicle params
    7140           14 :     MSParkingArea* destParkArea = getNextParkingArea();
    7141           14 :     const MSRoute& route = getRoute();
    7142           14 :     const MSEdge* lastEdge = route.getLastEdge();
    7143              : 
    7144           14 :     if (destParkArea == nullptr) {
    7145              :         // not driving towards a parking area
    7146            0 :         errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
    7147            0 :         return false;
    7148              :     }
    7149              : 
    7150              :     // if the current route ends at the parking area, the new route will also and at the new area
    7151           14 :     bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
    7152            5 :                            && getArrivalPos() >= destParkArea->getBeginLanePosition()
    7153           19 :                            && getArrivalPos() <= destParkArea->getEndLanePosition());
    7154              : 
    7155              :     // retrieve info on the new parking area
    7156           14 :     MSParkingArea* newParkingArea = (MSParkingArea*) MSNet::getInstance()->getStoppingPlace(
    7157              :                                         parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
    7158              : 
    7159           14 :     if (newParkingArea == nullptr) {
    7160            0 :         errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
    7161            0 :         return false;
    7162              :     }
    7163              : 
    7164           14 :     const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
    7165           14 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    7166              : 
    7167              :     // Compute the route from the current edge to the parking area edge
    7168              :     ConstMSEdgeVector edgesToPark;
    7169           14 :     router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
    7170              : 
    7171              :     // Compute the route from the parking area edge to the end of the route
    7172              :     ConstMSEdgeVector edgesFromPark;
    7173           14 :     if (!newDestination) {
    7174            9 :         router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
    7175              :     } else {
    7176              :         // adapt plans of any riders
    7177           10 :         for (MSTransportable* p : getPersons()) {
    7178            5 :             p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
    7179              :         }
    7180              :     }
    7181              : 
    7182              :     // we have a new destination, let's replace the vehicle route
    7183           14 :     ConstMSEdgeVector edges = edgesToPark;
    7184           14 :     if (edgesFromPark.size() > 0) {
    7185            9 :         edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
    7186              :     }
    7187              : 
    7188           14 :     if (newDestination) {
    7189            5 :         SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
    7190            5 :         *newParameter = getParameter();
    7191            5 :         newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
    7192            5 :         newParameter->arrivalPos = newParkingArea->getEndLanePosition();
    7193            5 :         replaceParameter(newParameter);
    7194              :     }
    7195           14 :     const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
    7196           14 :     ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
    7197           14 :     const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
    7198           14 :     if (replaceParkingArea(newParkingArea, errorMsg)) {
    7199           14 :         const bool onInit = myLane == nullptr;
    7200           28 :         replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
    7201              :     } else {
    7202            0 :         WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
    7203              :                       + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
    7204            0 :         return false;
    7205              :     }
    7206           14 :     return true;
    7207           14 : }
    7208              : 
    7209              : 
    7210              : bool
    7211        48197 : MSVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    7212        48197 :     const int numStops = (int)myStops.size();
    7213        48197 :     const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
    7214        48197 :     if (myLane != nullptr && numStops != (int)myStops.size()) {
    7215        46534 :         updateBestLanes(true);
    7216              :     }
    7217        48197 :     return result;
    7218              : }
    7219              : 
    7220              : 
    7221              : bool
    7222         2773 : MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    7223         2773 :     if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
    7224         1228 :         if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
    7225          874 :             double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
    7226              :             //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
    7227              :             //    << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
    7228              :             //    << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
    7229              :             //    << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
    7230              :             //    << " vNew=" << vNew
    7231              :             //    << "\n";
    7232          874 :             myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
    7233          874 :             myState.myPos = MIN2(myState.myPos, stop.pars.endPos);
    7234          874 :             myCachedPosition = Position::INVALID;
    7235          874 :             if (myState.myPos < myType->getLength()) {
    7236          364 :                 computeFurtherLanes(myLane, myState.myPos, true);
    7237          364 :                 myAngle = computeAngle();
    7238          364 :                 if (myLaneChangeModel->isOpposite()) {
    7239            0 :                     myAngle += M_PI;
    7240              :                 }
    7241              :             }
    7242              :         }
    7243              :     }
    7244         2773 :     return true;
    7245              : }
    7246              : 
    7247              : 
    7248              : bool
    7249     20376374 : MSVehicle::resumeFromStopping() {
    7250     20376374 :     if (isStopped()) {
    7251        46927 :         if (myAmRegisteredAsWaiting) {
    7252          126 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    7253          126 :             myAmRegisteredAsWaiting = false;
    7254              :         }
    7255              :         MSStop& stop = myStops.front();
    7256              :         // we have waited long enough and fulfilled any passenger-requirements
    7257        46927 :         if (stop.busstop != nullptr) {
    7258              :             // inform bus stop about leaving it
    7259        15298 :             stop.busstop->leaveFrom(this);
    7260              :         }
    7261              :         // we have waited long enough and fulfilled any container-requirements
    7262        46927 :         if (stop.containerstop != nullptr) {
    7263              :             // inform container stop about leaving it
    7264          346 :             stop.containerstop->leaveFrom(this);
    7265              :         }
    7266        46927 :         if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
    7267              :             // inform parking area about leaving it
    7268         6068 :             stop.parkingarea->leaveFrom(this);
    7269              :         }
    7270        46927 :         if (stop.chargingStation != nullptr) {
    7271              :             // inform charging station about leaving it
    7272         3297 :             stop.chargingStation->leaveFrom(this);
    7273              :         }
    7274              :         // the current stop is no longer valid
    7275        46927 :         myLane->getEdge().removeWaiting(this);
    7276              :         // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
    7277        46927 :         if (stop.pars.started == -1) {
    7278              :             // waypoint edge was passed in a single step
    7279          417 :             stop.pars.started = MSNet::getInstance()->getCurrentTimeStep();
    7280              :         }
    7281        46927 :         if (MSStopOut::active()) {
    7282         2830 :             MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
    7283              :         }
    7284        46927 :         stop.pars.ended = MSNet::getInstance()->getCurrentTimeStep();
    7285        83842 :         for (const auto& rem : myMoveReminders) {
    7286        36915 :             rem.first->notifyStopEnded();
    7287              :         }
    7288        46927 :         if (stop.pars.collision && MSLane::getCollisionAction() == MSLane::COLLISION_ACTION_WARN) {
    7289          366 :             myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
    7290              :         }
    7291        46927 :         if (stop.pars.posLat != INVALID_DOUBLE && MSGlobals::gLateralResolution <= 0) {
    7292              :             // reset lateral position to default
    7293          204 :             myState.myPosLat = 0;
    7294              :         }
    7295        46927 :         myPastStops.push_back(stop.pars);
    7296        46927 :         myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
    7297        46927 :         myStops.pop_front();
    7298        46927 :         myStopDist = std::numeric_limits<double>::max();
    7299              :         // do not count the stopping time towards gridlock time.
    7300              :         // Other outputs use an independent counter and are not affected.
    7301        46927 :         myWaitingTime = 0;
    7302              :         // maybe the next stop is on the same edge; let's rebuild best lanes
    7303        46927 :         updateBestLanes(true);
    7304              :         // continue as wished...
    7305        46927 :         MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::ENDING_STOP);
    7306        46927 :         MSNet::getInstance()->getVehicleControl().registerStopEnded();
    7307        46927 :         return true;
    7308              :     }
    7309              :     return false;
    7310              : }
    7311              : 
    7312              : 
    7313              : MSVehicle::Influencer&
    7314      3944548 : MSVehicle::getInfluencer() {
    7315      3944548 :     if (myInfluencer == nullptr) {
    7316         3419 :         myInfluencer = new Influencer();
    7317              :     }
    7318      3944548 :     return *myInfluencer;
    7319              : }
    7320              : 
    7321              : MSVehicle::BaseInfluencer&
    7322           24 : MSVehicle::getBaseInfluencer() {
    7323           24 :     return getInfluencer();
    7324              : }
    7325              : 
    7326              : 
    7327              : const MSVehicle::Influencer*
    7328            0 : MSVehicle::getInfluencer() const {
    7329            0 :     return myInfluencer;
    7330              : }
    7331              : 
    7332              : const MSVehicle::BaseInfluencer*
    7333       226082 : MSVehicle::getBaseInfluencer() const {
    7334       226082 :     return myInfluencer;
    7335              : }
    7336              : 
    7337              : 
    7338              : double
    7339         4082 : MSVehicle::getSpeedWithoutTraciInfluence() const {
    7340         4082 :     if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
    7341              :         // influencer original speed is -1 on initialization
    7342         1662 :         return myInfluencer->getOriginalSpeed();
    7343              :     }
    7344         2420 :     return myState.mySpeed;
    7345              : }
    7346              : 
    7347              : 
    7348              : int
    7349    577057264 : MSVehicle::influenceChangeDecision(int state) {
    7350    577057264 :     if (hasInfluencer()) {
    7351      2295816 :         state = getInfluencer().influenceChangeDecision(
    7352              :                     MSNet::getInstance()->getCurrentTimeStep(),
    7353      2295816 :                     myLane->getEdge(),
    7354              :                     getLaneIndex(),
    7355              :                     state);
    7356              :     }
    7357    577057264 :     return state;
    7358              : }
    7359              : 
    7360              : 
    7361              : void
    7362         7758 : MSVehicle::setRemoteState(Position xyPos) {
    7363         7758 :     myCachedPosition = xyPos;
    7364         7758 : }
    7365              : 
    7366              : 
    7367              : bool
    7368    626227236 : MSVehicle::isRemoteControlled() const {
    7369    626227236 :     return myInfluencer != nullptr && myInfluencer->isRemoteControlled();
    7370              : }
    7371              : 
    7372              : 
    7373              : bool
    7374        21095 : MSVehicle::wasRemoteControlled(SUMOTime lookBack) const {
    7375        21095 :     return myInfluencer != nullptr && myInfluencer->getLastAccessTimeStep() + lookBack >= MSNet::getInstance()->getCurrentTimeStep();
    7376              : }
    7377              : 
    7378              : 
    7379              : bool
    7380    455948425 : MSVehicle::keepClear(const MSLink* link) const {
    7381    455948425 :     if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
    7382    147450962 :         const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
    7383              :         //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
    7384    148806065 :         return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
    7385              :     } else {
    7386              :         return false;
    7387              :     }
    7388              : }
    7389              : 
    7390              : 
    7391              : bool
    7392    642647835 : MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
    7393    642647835 :     if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
    7394              :         return true;
    7395              :     }
    7396    642487492 :     const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
    7397              : #ifdef DEBUG_IGNORE_RED
    7398              :     if (DEBUG_COND) {
    7399              :         std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
    7400              :     }
    7401              : #endif
    7402    642487492 :     if (ignoreRedTime < 0) {
    7403    642482816 :         const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
    7404    642482816 :         if (ignoreYellowTime > 0 && link->haveYellow()) {
    7405              :             assert(link->getTLLogic() != 0);
    7406           52 :             const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    7407              :             // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
    7408           92 :             return !canBrake || ignoreYellowTime > yellowDuration;
    7409              :         } else {
    7410              :             return false;
    7411              :         }
    7412         4676 :     } else if (link->haveYellow()) {
    7413              :         // always drive at yellow when ignoring red
    7414              :         return true;
    7415         4520 :     } else if (link->haveRed()) {
    7416              :         assert(link->getTLLogic() != 0);
    7417         3156 :         const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    7418              : #ifdef DEBUG_IGNORE_RED
    7419              :         if (DEBUG_COND) {
    7420              :             std::cout
    7421              :             // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
    7422              :                     << "   ignoreRedTime=" << ignoreRedTime
    7423              :                     << " spentRed=" << redDuration
    7424              :                     << " canBrake=" << canBrake << "\n";
    7425              :         }
    7426              : #endif
    7427              :         // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
    7428         5004 :         return !canBrake || ignoreRedTime > redDuration;
    7429              :     } else {
    7430              :         return false;
    7431              :     }
    7432              : }
    7433              : 
    7434              : bool
    7435   1083009433 : MSVehicle::ignoreFoe(const SUMOTrafficObject* foe) const {
    7436   1083009433 :     if (!getParameter().wasSet(VEHPARS_CFMODEL_PARAMS_SET)) {
    7437              :         return false;
    7438              :     }
    7439         2768 :     for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
    7440          398 :         if (typeID == foe->getVehicleType().getID()) {
    7441              :             return true;
    7442              :         }
    7443         1384 :     }
    7444         2381 :     for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
    7445          986 :         if (id == foe->getID()) {
    7446              :             return true;
    7447              :         }
    7448          986 :     }
    7449          409 :     return false;
    7450              : }
    7451              : 
    7452              : bool
    7453    390997741 : MSVehicle::passingMinor() const {
    7454              :     // either on an internal lane that was entered via minor link
    7455              :     // or on approach to minor link below visibility distance
    7456    390997741 :     if (myLane == nullptr) {
    7457              :         return false;
    7458              :     }
    7459    390997741 :     if (myLane->getEdge().isInternal()) {
    7460      7682402 :         return !myLane->getIncomingLanes().front().viaLink->havePriority();
    7461    383315339 :     } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
    7462              :         MSLink* link = myLFLinkLanes.front().myLink;
    7463    247567095 :         return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
    7464              :     }
    7465              :     return false;
    7466              : }
    7467              : 
    7468              : bool
    7469     18070771 : MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
    7470              :     assert(link->fromInternalLane());
    7471     18070771 :     if (veh == nullptr) {
    7472              :         return false;
    7473              :     }
    7474     18070771 :     if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
    7475              :         // if this vehicle is not yet on the junction, every vehicle is a leader
    7476              :         return true;
    7477              :     }
    7478      1567839 :     if (veh->getLaneChangeModel().hasBlueLight()) {
    7479              :         // blue light device automatically gets right of way
    7480              :         return true;
    7481              :     }
    7482      1567238 :     const MSLane* foeLane = veh->getLane();
    7483      1567238 :     if (foeLane->isInternal()) {
    7484      1167243 :         if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
    7485      1154819 :             SUMOTime egoET = myJunctionConflictEntryTime;
    7486      1154819 :             SUMOTime foeET = veh->myJunctionEntryTime;
    7487              :             // check relationship between link and foeLane
    7488      1154819 :             if (foeLane->getNormalPredecessorLane() == link->getInternalLaneBefore()->getNormalPredecessorLane()) {
    7489              :                 // we are entering the junction from the same lane
    7490       293810 :                 egoET = myJunctionEntryTimeNeverYield;
    7491       293810 :                 foeET = veh->myJunctionEntryTimeNeverYield;
    7492       293810 :                 if (link->isExitLinkAfterInternalJunction() && link->getInternalLaneBefore()->getLogicalPredecessorLane()->getEntryLink()->isIndirect()) {
    7493        19764 :                     egoET = myJunctionConflictEntryTime;
    7494              :                 }
    7495              :             } else {
    7496       861009 :                 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
    7497       861009 :                 const MSJunctionLogic* logic = link->getJunction()->getLogic();
    7498              :                 assert(logic != nullptr);
    7499              :                 // determine who has right of way
    7500              :                 bool response; // ego response to foe
    7501              :                 bool response2; // foe response to ego
    7502              :                 // attempt 1: tlLinkState
    7503       861009 :                 const MSLink* entry = link->getCorrespondingEntryLink();
    7504       861009 :                 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
    7505       861009 :                 if (entry->haveRed() || foeEntry->haveRed()) {
    7506              :                     // ensure that vehicles which are stuck on the intersection may exit
    7507       117772 :                     if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
    7508              :                         // foe might be oncoming, don't drive unless foe can still brake safely
    7509        11821 :                         const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
    7510        11821 :                         const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
    7511        11821 :                                                        foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
    7512              :                         // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
    7513              :                         // so the -2* makes it point in the right direction
    7514        11821 :                         const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
    7515              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    7516              :                         if (DEBUG_COND) {
    7517              :                             std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
    7518              : 
    7519              :                         }
    7520              : #endif
    7521        11821 :                         if (foeGap < foeBrakeGap) {
    7522              :                             response = true;
    7523              :                             response2 = false;
    7524              :                         } else {
    7525              :                             response = false;
    7526              :                             response2 = true;
    7527              :                         }
    7528              :                     } else {
    7529              :                         // brake for stuck foe
    7530              :                         response = foeEntry->haveRed();
    7531              :                         response2 = entry->haveRed();
    7532              :                     }
    7533       743237 :                 } else if (entry->havePriority() != foeEntry->havePriority()) {
    7534       541399 :                     response = !entry->havePriority();
    7535       541399 :                     response2 = !foeEntry->havePriority();
    7536       201838 :                 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
    7537              :                     // let the faster vehicle keep moving
    7538         5432 :                     response = veh->getSpeed() >= getSpeed();
    7539         5432 :                     response2 = getSpeed() >= veh->getSpeed();
    7540              :                 } else {
    7541              :                     // fallback if pedestrian crossings are involved
    7542       196406 :                     response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
    7543       196406 :                     response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
    7544              :                 }
    7545              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    7546              :                 if (DEBUG_COND) {
    7547              :                     std::cout << SIMTIME
    7548              :                               << " foeLane=" << foeLane->getID()
    7549              :                               << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
    7550              :                               << " linkIndex=" << link->getIndex()
    7551              :                               << " foeLinkIndex=" << foeLink->getIndex()
    7552              :                               << " entryState=" << toString(entry->getState())
    7553              :                               << " entryState2=" << toString(foeEntry->getState())
    7554              :                               << " response=" << response
    7555              :                               << " response2=" << response2
    7556              :                               << "\n";
    7557              :                 }
    7558              : #endif
    7559       861009 :                 if (!response) {
    7560              :                     // if we have right of way over the foe, entryTime does not matter
    7561       108656 :                     foeET = veh->myJunctionConflictEntryTime;
    7562       108656 :                     egoET = myJunctionEntryTime;
    7563       752353 :                 } else if (response && response2) {
    7564              :                     // in a mutual conflict scenario, use entry time to avoid deadlock
    7565        88294 :                     foeET = veh->myJunctionConflictEntryTime;
    7566        88294 :                     egoET = myJunctionConflictEntryTime;
    7567              :                 }
    7568              :             }
    7569      1154819 :             if (egoET == foeET) {
    7570              :                 // try to use speed as tie braker
    7571       113061 :                 if (getSpeed() == veh->getSpeed()) {
    7572              :                     // use ID as tie braker
    7573              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    7574              :                     if (DEBUG_COND) {
    7575              :                         std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
    7576              :                                   << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
    7577              :                     }
    7578              : #endif
    7579        50448 :                     return getID() < veh->getID();
    7580              :                 } else {
    7581              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    7582              :                     if (DEBUG_COND) {
    7583              :                         std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
    7584              :                                   << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
    7585              :                                   << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
    7586              :                                   << "\n";
    7587              :                     }
    7588              : #endif
    7589        62613 :                     return getSpeed() < veh->getSpeed();
    7590              :                 }
    7591              :             } else {
    7592              :                 // leader was on the junction first
    7593              : #ifdef DEBUG_PLAN_MOVE_LEADERINFO
    7594              :                 if (DEBUG_COND) {
    7595              :                     std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
    7596              :                               << " foeET=" << foeET  << " isLeader=" << (egoET > foeET) << "\n";
    7597              :                 }
    7598              : #endif
    7599      1041758 :                 return egoET > foeET;
    7600              :             }
    7601              :         } else {
    7602              :             // vehicle can only be partially on the junction. Must be a leader
    7603              :             return true;
    7604              :         }
    7605              :     } else {
    7606              :         // vehicle can only be partially on the junction. Must be a leader
    7607              :         return true;
    7608              :     }
    7609              : }
    7610              : 
    7611              : void
    7612         2159 : MSVehicle::saveState(OutputDevice& out) {
    7613         2159 :     MSBaseVehicle::saveState(out);
    7614              :     // here starts the vehicle internal part (see loading)
    7615              :     std::vector<std::string> internals;
    7616         2159 :     internals.push_back(toString(myParameter->parametersSet));
    7617         2159 :     internals.push_back(toString(myDeparture));
    7618         2159 :     internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
    7619         2159 :     internals.push_back(toString(myDepartPos));
    7620         2159 :     internals.push_back(toString(myWaitingTime));
    7621         2159 :     internals.push_back(toString(myTimeLoss));
    7622         2159 :     internals.push_back(toString(myLastActionTime));
    7623         2159 :     internals.push_back(toString(isStopped()));
    7624         4318 :     internals.push_back(toString(myPastStops.size()));
    7625              :     out.writeAttr(SUMO_ATTR_STATE, internals);
    7626         4318 :     out.writeAttr(SUMO_ATTR_POSITION, std::vector<double> { myState.myPos, myState.myBackPos, myState.myLastCoveredDist });
    7627         4318 :     out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
    7628         2159 :     out.writeAttr(SUMO_ATTR_ANGLE, GeomHelper::naviDegree(myAngle));
    7629         2159 :     out.writeAttr(SUMO_ATTR_POSITION_LAT, myState.myPosLat);
    7630         2159 :     out.writeAttr(SUMO_ATTR_WAITINGTIME, myWaitingTimeCollector.getState());
    7631         2159 :     myLaneChangeModel->saveState(out);
    7632              :     // save past stops
    7633         5043 :     for (SUMOVehicleParameter::Stop stop : myPastStops) {
    7634         2884 :         stop.write(out, false);
    7635              :         // do not write started and ended twice
    7636         2884 :         if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
    7637         5758 :             out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
    7638              :         }
    7639         2884 :         if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
    7640         5758 :             out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
    7641              :         }
    7642         2884 :         stop.writeParams(out);
    7643         2884 :         out.closeTag();
    7644         2884 :     }
    7645              :     // save upcoming stops
    7646         2641 :     for (MSStop& stop : myStops) {
    7647          482 :         stop.write(out);
    7648              :     }
    7649              :     // save parameters and device states
    7650         2159 :     myParameter->writeParams(out);
    7651         5030 :     for (MSVehicleDevice* const dev : myDevices) {
    7652         2871 :         dev->saveState(out);
    7653              :     }
    7654         2159 :     out.closeTag();
    7655         2159 : }
    7656              : 
    7657              : void
    7658         3867 : MSVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
    7659         3867 :     if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
    7660            0 :         throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
    7661              :     }
    7662              :     int routeOffset;
    7663              :     bool stopped;
    7664              :     int pastStops;
    7665              : 
    7666         3867 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
    7667         3867 :     bis >> myParameter->parametersSet;
    7668         3867 :     bis >> myDeparture;
    7669         3867 :     bis >> routeOffset;
    7670         3867 :     bis >> myDepartPos;
    7671         3867 :     bis >> myWaitingTime;
    7672         3867 :     bis >> myTimeLoss;
    7673         3867 :     bis >> myLastActionTime;
    7674              :     bis >> stopped;
    7675         3867 :     bis >> pastStops;
    7676              : 
    7677              :     // load stops
    7678              :     myStops.clear();
    7679         3867 :     addStops(!MSGlobals::gCheckRoutes, &myCurrEdge, false);
    7680              : 
    7681         3867 :     if (hasDeparted()) {
    7682         1595 :         myCurrEdge = myRoute->begin() + routeOffset;
    7683         1595 :         myDeparture -= offset;
    7684              :         // fix stops
    7685         4453 :         while (pastStops > 0) {
    7686         2858 :             myPastStops.push_back(myStops.front().pars);
    7687         2858 :             myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
    7688         2858 :             myStops.pop_front();
    7689         2858 :             pastStops--;
    7690              :         }
    7691              :         // see MSBaseVehicle constructor
    7692         1595 :         if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    7693         1334 :             calculateArrivalParams(true);
    7694              :         }
    7695              :     }
    7696         3867 :     if (getActionStepLength() == DELTA_T && !isActionStep(SIMSTEP)) {
    7697            1 :         myLastActionTime -= (myLastActionTime - SIMSTEP) % DELTA_T;
    7698            3 :         WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
    7699              :     }
    7700         3867 :     std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
    7701         3867 :     pis >> myState.myPos >> myState.myBackPos >> myState.myLastCoveredDist;
    7702         3867 :     std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
    7703         3867 :     sis >> myState.mySpeed >> myState.myPreviousSpeed;
    7704         3867 :     myAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
    7705         3867 :     myAngle = GeomHelper::fromNaviDegree(attrs.getFloat(SUMO_ATTR_ANGLE));
    7706         3867 :     myState.myPosLat = attrs.getFloat(SUMO_ATTR_POSITION_LAT);
    7707         3867 :     std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
    7708         3867 :     dis >> myOdometer >> myNumberReroutes;
    7709         3867 :     myWaitingTimeCollector.setState(attrs.getString(SUMO_ATTR_WAITINGTIME));
    7710         3867 :     if (stopped) {
    7711          196 :         myStops.front().startedFromState = true;
    7712          196 :         myStopDist = 0;
    7713              :     }
    7714         3867 :     myLaneChangeModel->loadState(attrs);
    7715              :     // no need to reset myCachedPosition here since state loading happens directly after creation
    7716         3867 : }
    7717              : 
    7718              : void
    7719           37 : MSVehicle::loadPreviousApproaching(MSLink* link, bool setRequest,
    7720              :                                    SUMOTime arrivalTime, double arrivalSpeed,
    7721              :                                    double arrivalSpeedBraking,
    7722              :                                    double dist, double leaveSpeed) {
    7723              :     // ensure that approach information is reset on the next call to setApproachingForAllLinks
    7724           37 :     myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
    7725              :                             arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
    7726              : 
    7727           37 : }
    7728              : 
    7729              : 
    7730              : std::shared_ptr<MSSimpleDriverState>
    7731      1170946 : MSVehicle::getDriverState() const {
    7732      1170946 :     return myDriverState->getDriverState();
    7733              : }
    7734              : 
    7735              : 
    7736              : double
    7737    462499608 : MSVehicle::getFriction() const {
    7738    462499608 :     return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
    7739              : }
    7740              : 
    7741              : 
    7742              : void
    7743          241 : MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
    7744          241 :     myState.mySpeed = MAX2(0., prevSpeed);
    7745              :     // also retcon acceleration
    7746          241 :     if (prevAcceleration != std::numeric_limits<double>::min()) {
    7747            8 :         myAcceleration = prevAcceleration;
    7748              :     } else {
    7749          233 :         myAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
    7750              :     }
    7751          241 : }
    7752              : 
    7753              : 
    7754              : double
    7755   1578290402 : MSVehicle::getCurrentApparentDecel() const {
    7756              :     //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
    7757   1578290402 :     return getCarFollowModel().getApparentDecel();
    7758              : }
    7759              : 
    7760              : /****************************************************************************/
    7761              : bool
    7762           32 : MSVehicle::setExitManoeuvre() {
    7763           32 :     return (myManoeuvre.configureExitManoeuvre(this));
    7764              : }
    7765              : 
    7766              : /* -------------------------------------------------------------------------
    7767              :  * methods of MSVehicle::manoeuvre
    7768              :  * ----------------------------------------------------------------------- */
    7769              : 
    7770      3892667 : MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
    7771              : 
    7772              : 
    7773            0 : MSVehicle::Manoeuvre::Manoeuvre(const Manoeuvre& manoeuvre) {
    7774            0 :     myManoeuvreStop = manoeuvre.myManoeuvreStop;
    7775            0 :     myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
    7776            0 :     myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
    7777            0 :     myManoeuvreType = manoeuvre.myManoeuvreType;
    7778            0 :     myGUIIncrement = manoeuvre.myGUIIncrement;
    7779            0 : }
    7780              : 
    7781              : 
    7782              : MSVehicle::Manoeuvre&
    7783            0 : MSVehicle::Manoeuvre::operator=(const Manoeuvre& manoeuvre) {
    7784            0 :     myManoeuvreStop = manoeuvre.myManoeuvreStop;
    7785            0 :     myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
    7786            0 :     myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
    7787            0 :     myManoeuvreType = manoeuvre.myManoeuvreType;
    7788            0 :     myGUIIncrement = manoeuvre.myGUIIncrement;
    7789            0 :     return *this;
    7790              : }
    7791              : 
    7792              : 
    7793              : bool
    7794            0 : MSVehicle::Manoeuvre::operator!=(const Manoeuvre& manoeuvre) {
    7795            0 :     return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
    7796            0 :             myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
    7797            0 :             myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
    7798            0 :             myManoeuvreType != manoeuvre.myManoeuvreType ||
    7799            0 :             myGUIIncrement != manoeuvre.myGUIIncrement
    7800            0 :            );
    7801              : }
    7802              : 
    7803              : 
    7804              : double
    7805          450 : MSVehicle::Manoeuvre::getGUIIncrement() const {
    7806          450 :     return (myGUIIncrement);
    7807              : }
    7808              : 
    7809              : 
    7810              : MSVehicle::ManoeuvreType
    7811         2971 : MSVehicle::Manoeuvre::getManoeuvreType() const {
    7812         2971 :     return (myManoeuvreType);
    7813              : }
    7814              : 
    7815              : 
    7816              : MSVehicle::ManoeuvreType
    7817         2971 : MSVehicle::getManoeuvreType() const {
    7818         2971 :     return (myManoeuvre.getManoeuvreType());
    7819              : }
    7820              : 
    7821              : 
    7822              : void
    7823           30 : MSVehicle::setManoeuvreType(const MSVehicle::ManoeuvreType mType) {
    7824           30 :     myManoeuvre.setManoeuvreType(mType);
    7825           30 : }
    7826              : 
    7827              : 
    7828              : void
    7829           30 : MSVehicle::Manoeuvre::setManoeuvreType(const MSVehicle::ManoeuvreType mType) {
    7830           30 :     myManoeuvreType = mType;
    7831           30 : }
    7832              : 
    7833              : 
    7834              : bool
    7835           30 : MSVehicle::Manoeuvre::configureEntryManoeuvre(MSVehicle* veh) {
    7836           30 :     if (!veh->hasStops()) {
    7837              :         return false;    // should never happen - checked before call
    7838              :     }
    7839              : 
    7840           30 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
    7841           30 :     const MSStop& stop = veh->getNextStop();
    7842              : 
    7843           30 :     int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
    7844           30 :     double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
    7845           30 :     if (abs(GUIAngle) < 0.1) {
    7846              :         GUIAngle = -0.1;    // Wiggle vehicle on parallel entry
    7847              :     }
    7848           30 :     myManoeuvreVehicleID = veh->getID();
    7849           30 :     myManoeuvreStop = stop.parkingarea->getID();
    7850           30 :     myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
    7851           30 :     myManoeuvreStartTime = currentTime;
    7852           30 :     myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
    7853           30 :     myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
    7854              : 
    7855              : #ifdef DEBUG_STOPS
    7856              :     if (veh->isSelected()) {
    7857              :         std::cout << "ENTRY manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " Rotation angle=" << RAD2DEG(GUIAngle) << " Road Angle" << RAD2DEG(veh->getAngle()) << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime <<
    7858              :                   " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
    7859              :     }
    7860              : #endif
    7861              : 
    7862           30 :     return (true);
    7863              : }
    7864              : 
    7865              : 
    7866              : bool
    7867           32 : MSVehicle::Manoeuvre::configureExitManoeuvre(MSVehicle* veh) {
    7868              :     // At the moment we only want to set for parking areas
    7869           32 :     if (!veh->hasStops()) {
    7870              :         return true;
    7871              :     }
    7872           32 :     if (veh->getNextStop().parkingarea == nullptr) {
    7873              :         return true;
    7874              :     }
    7875              : 
    7876           30 :     if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
    7877              :         return (false);
    7878              :     }
    7879              : 
    7880           30 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
    7881              : 
    7882           30 :     int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
    7883           30 :     double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
    7884           30 :     if (abs(GUIAngle) < 0.1) {
    7885              :         GUIAngle = 0.1;    // Wiggle vehicle on parallel exit
    7886              :     }
    7887              : 
    7888           30 :     myManoeuvreVehicleID = veh->getID();
    7889           30 :     myManoeuvreStop = veh->getCurrentParkingArea()->getID();
    7890           30 :     myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
    7891           30 :     myManoeuvreStartTime = currentTime;
    7892           30 :     myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
    7893           30 :     myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
    7894           30 :     if (veh->remainingStopDuration() > 0) {
    7895           20 :         myManoeuvreCompleteTime += veh->remainingStopDuration();
    7896              :     }
    7897              : 
    7898              : #ifdef DEBUG_STOPS
    7899              :     if (veh->isSelected()) {
    7900              :         std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle  << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
    7901              :                   << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
    7902              :     }
    7903              : #endif
    7904              : 
    7905              :     return (true);
    7906              : }
    7907              : 
    7908              : 
    7909              : bool
    7910          222 : MSVehicle::Manoeuvre::entryManoeuvreIsComplete(MSVehicle* veh) {
    7911              :     // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
    7912          222 :     if (!veh->hasStops()) {
    7913              :         return (true);
    7914              :     }
    7915              :     MSStop* currentStop = &veh->myStops.front();
    7916          222 :     if (currentStop->parkingarea == nullptr) {
    7917              :         return true;
    7918          220 :     } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
    7919           30 :         if (configureEntryManoeuvre(veh)) {
    7920           30 :             MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::MANEUVERING);
    7921           30 :             return (false);
    7922              :         } else { // cannot configure entry so stop trying
    7923              :             return true;
    7924              :         }
    7925          190 :     } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
    7926              :         return false;
    7927              :     } else { // manoeuvre complete
    7928           30 :         myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
    7929           30 :         return true;
    7930              :     }
    7931              : }
    7932              : 
    7933              : 
    7934              : bool
    7935            0 : MSVehicle::Manoeuvre::manoeuvreIsComplete(const ManoeuvreType checkType) const {
    7936            0 :     if (checkType != myManoeuvreType) {
    7937              :         return true;    // we're not maneuvering / wrong manoeuvre
    7938              :     }
    7939              : 
    7940            0 :     if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
    7941              :         return false;
    7942              :     } else {
    7943              :         return true;
    7944              :     }
    7945              : }
    7946              : 
    7947              : 
    7948              : bool
    7949         6266 : MSVehicle::Manoeuvre::manoeuvreIsComplete() const {
    7950         6266 :     return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
    7951              : }
    7952              : 
    7953              : 
    7954              : bool
    7955         6266 : MSVehicle::manoeuvreIsComplete() const {
    7956         6266 :     return (myManoeuvre.manoeuvreIsComplete());
    7957              : }
    7958              : 
    7959              : 
    7960              : std::pair<double, double>
    7961         6690 : MSVehicle::estimateTimeToNextStop() const {
    7962         6690 :     if (hasStops()) {
    7963         6690 :         MSLane* lane = myLane;
    7964         6690 :         if (lane == nullptr) {
    7965              :             // not in network
    7966           66 :             lane = getEdge()->getLanes()[0];
    7967              :         }
    7968              :         const MSStop& stop = myStops.front();
    7969              :         auto it = myCurrEdge + 1;
    7970              :         // drive to end of current edge
    7971         6690 :         double dist = (lane->getLength() - getPositionOnLane());
    7972         6690 :         double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
    7973              :         // drive until stop edge
    7974         7734 :         while (it != myRoute->end() && it < stop.edge) {
    7975         1044 :             travelTime += (*it)->getMinimumTravelTime(this);
    7976         1044 :             dist += (*it)->getLength();
    7977              :             it++;
    7978              :         }
    7979              :         // drive up to the stop position
    7980         6690 :         const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
    7981         6690 :         dist += stopEdgeDist;
    7982         6690 :         travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
    7983              :         // estimate time loss due to acceleration and deceleration
    7984              :         // maximum speed is limited by available distance:
    7985              :         const double a = getCarFollowModel().getMaxAccel();
    7986              :         const double b = getCarFollowModel().getMaxDecel();
    7987         6690 :         const double c = getSpeed();
    7988              :         const double d = dist;
    7989         6690 :         const double len = getVehicleType().getLength();
    7990         6690 :         const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
    7991              :         // distAccel = (v - c)^2 / (2a)
    7992              :         // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
    7993              :         // distAccel + distDecel < d
    7994         6690 :         const double maxVD = MAX2(c, ((sqrt(MAX2(0.0, pow(2 * c * b, 2) + (4 * ((b * ((a * (2 * d * (b + a) + (vs * vs) - (c * c))) - (b * (c * c))))
    7995        13142 :                                             + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
    7996         6690 :         it = myCurrEdge;
    7997              :         double v0 = c;
    7998         6690 :         bool v0Stable = getAcceleration() == 0 && v0 > 0;
    7999              :         double timeLossAccel = 0;
    8000              :         double timeLossDecel = 0;
    8001              :         double timeLossLength = 0;
    8002        15576 :         while (it != myRoute->end() && it <= stop.edge) {
    8003         8886 :             double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
    8004         8886 :             double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
    8005         8886 :             if (edgeLength <= len && v0Stable && v0 < v) {
    8006              :                 const double lengthDist = MIN2(len, edgeLength);
    8007           20 :                 const double dTL = lengthDist / v0 - lengthDist / v;
    8008              :                 //std::cout << "   e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
    8009           20 :                 timeLossLength += dTL;
    8010              :             }
    8011         8886 :             if (edgeLength > len) {
    8012         7950 :                 const double dv = v - v0;
    8013         7950 :                 if (dv > 0) {
    8014              :                     // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
    8015         6083 :                     const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
    8016              :                     //std::cout << "   e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
    8017         6083 :                     timeLossAccel += dTA;
    8018              :                     // time loss from vehicle length
    8019         1867 :                 } else if (dv < 0) {
    8020              :                     // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
    8021          540 :                     const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
    8022              :                     //std::cout << "   e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
    8023          540 :                     timeLossDecel += dTD;
    8024              :                 }
    8025              :                 v0 = v;
    8026              :                 v0Stable = true;
    8027              :             }
    8028              :             it++;
    8029              :         }
    8030              :         // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
    8031              :         double v = vs;
    8032         6690 :         const double dv = v - v0;
    8033         6690 :         if (dv > 0) {
    8034              :             // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
    8035          144 :             const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
    8036              :             //std::cout << "  final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
    8037          144 :             timeLossAccel += dTA;
    8038              :             // time loss from vehicle length
    8039         6546 :         } else if (dv < 0) {
    8040              :             // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
    8041         6522 :             const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
    8042              :             //std::cout << "  final  e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
    8043         6522 :             timeLossDecel += dTD;
    8044              :         }
    8045         6690 :         const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
    8046              :         //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
    8047              :         //    << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
    8048         6690 :         return {MAX2(0.0, result), dist};
    8049              :     } else {
    8050            0 :         return {INVALID_DOUBLE, INVALID_DOUBLE};
    8051              :     }
    8052              : }
    8053              : 
    8054              : 
    8055              : double
    8056         1413 : MSVehicle::getStopDelay() const {
    8057         1413 :     if (hasStops() && myStops.front().pars.until >= 0) {
    8058              :         const MSStop& stop = myStops.front();
    8059         1196 :         SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
    8060         1196 :         if (stop.reached) {
    8061          664 :             return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
    8062              :         }
    8063          532 :         if (stop.pars.duration > 0) {
    8064          460 :             estimatedDepart += stop.pars.duration;
    8065              :         }
    8066          532 :         estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
    8067          532 :         const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
    8068          532 :         return result;
    8069              :     } else {
    8070              :         // vehicles cannot drive before 'until' so stop delay can never be
    8071              :         // negative and we can use -1 to signal "undefined"
    8072              :         return -1;
    8073              :     }
    8074              : }
    8075              : 
    8076              : 
    8077              : double
    8078         5184 : MSVehicle::getStopArrivalDelay() const {
    8079         5184 :     if (hasStops() && myStops.front().pars.arrival >= 0) {
    8080              :         const MSStop& stop = myStops.front();
    8081         4076 :         if (stop.reached) {
    8082         1236 :             return STEPS2TIME(stop.pars.started - stop.pars.arrival);
    8083              :         } else {
    8084         2840 :             return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
    8085              :         }
    8086              :     } else {
    8087              :         // vehicles can arrival earlier than planned so arrival delay can be negative
    8088              :         return INVALID_DOUBLE;
    8089              :     }
    8090              : }
    8091              : 
    8092              : 
    8093              : const MSEdge*
    8094           29 : MSVehicle::getCurrentEdge() const {
    8095           29 :     return myLane != nullptr ? &myLane->getEdge() : getEdge();
    8096              : }
    8097              : 
    8098              : 
    8099              : const MSEdge*
    8100         3896 : MSVehicle::getNextEdgePtr() const {
    8101         3896 :     if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
    8102            8 :         return nullptr;
    8103              :     }
    8104         3888 :     if (myLane->isInternal()) {
    8105          568 :         return &myLane->getCanonicalSuccessorLane()->getEdge();
    8106              :     } else {
    8107         3320 :         const MSEdge* nextNormal = succEdge(1);
    8108         3320 :         const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
    8109         3320 :         return nextInternal ? nextInternal : nextNormal;
    8110              :     }
    8111              : }
    8112              : 
    8113              : 
    8114              : const MSLane*
    8115         2229 : MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
    8116         2229 :     if (furtherIndex < (int)myFurtherLanes.size()) {
    8117         1852 :         return myFurtherLanes[furtherIndex++];
    8118              :     } else {
    8119              :         // try to use route information
    8120          377 :         int routeIndex = getRoutePosition();
    8121              :         bool resultInternal;
    8122          377 :         if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
    8123            0 :             if (myLane->isInternal()) {
    8124            0 :                 if (furtherIndex % 2 == 0) {
    8125            0 :                     routeIndex -= (furtherIndex + 0) / 2;
    8126              :                     resultInternal = false;
    8127              :                 } else {
    8128            0 :                     routeIndex -= (furtherIndex + 1) / 2;
    8129              :                     resultInternal = false;
    8130              :                 }
    8131              :             } else {
    8132            0 :                 if (furtherIndex % 2 != 0) {
    8133            0 :                     routeIndex -= (furtherIndex + 1) / 2;
    8134              :                     resultInternal = false;
    8135              :                 } else {
    8136            0 :                     routeIndex -= (furtherIndex + 2) / 2;
    8137              :                     resultInternal = true;
    8138              :                 }
    8139              :             }
    8140              :         } else {
    8141          377 :             routeIndex -= furtherIndex;
    8142              :             resultInternal = false;
    8143              :         }
    8144          377 :         furtherIndex++;
    8145          377 :         if (routeIndex >= 0) {
    8146          237 :             if (resultInternal) {
    8147            0 :                 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
    8148            0 :                 for (MSLane* cand : prevNormal->getLanes()) {
    8149            0 :                     for (MSLink* link : cand->getLinkCont()) {
    8150            0 :                         if (link->getLane() == current) {
    8151            0 :                             if (link->getViaLane() != nullptr) {
    8152              :                                 return link->getViaLane();
    8153              :                             } else {
    8154            0 :                                 return const_cast<MSLane*>(link->getLaneBefore());
    8155              :                             }
    8156              :                         }
    8157              :                     }
    8158              :                 }
    8159              :             } else {
    8160          237 :                 return myRoute->getEdges()[routeIndex]->getLanes()[0];
    8161              :             }
    8162              :         }
    8163              :     }
    8164              :     return current;
    8165              : }
    8166              : 
    8167              : 
    8168              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1