LCOV - code coverage report
Current view: top level - src/microsim - MSVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.2 % 3392 3264
Test Date: 2026-09-20 15:45:03 Functions: 95.2 % 227 216

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

Generated by: LCOV version 2.0-1