LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.7 % 1414 1268
Test Date: 2026-05-06 15:47:47 Functions: 89.5 % 124 111

            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    MSBaseVehicle.cpp
      15              : /// @author  Michael Behrisch
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Mirko Barthauer
      19              : /// @date    Mon, 8 Nov 2010
      20              : ///
      21              : // A base class for vehicle implementations
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <iostream>
      26              : #include <cassert>
      27              : #include <algorithm>
      28              : #include <functional>
      29              : #include <utils/common/StdDefs.h>
      30              : #include <utils/common/MsgHandler.h>
      31              : #include <utils/options/OptionsCont.h>
      32              : #include <utils/iodevices/OutputDevice.h>
      33              : #include <utils/emissions/PollutantsInterface.h>
      34              : #include <utils/emissions/HelpersHarmonoise.h>
      35              : #include <libsumo/TraCIConstants.h>
      36              : #include <mesosim/MELoop.h>
      37              : #include <mesosim/MEVehicle.h>
      38              : #include <microsim/devices/MSRoutingEngine.h>
      39              : #include <microsim/devices/MSDevice_Transportable.h>
      40              : #include <microsim/devices/MSDevice_Emissions.h>
      41              : #include <microsim/devices/MSDevice_Battery.h>
      42              : #include <microsim/devices/MSDevice_ElecHybrid.h>
      43              : #include <microsim/devices/MSDevice_Taxi.h>
      44              : #include <microsim/devices/MSDevice_Routing.h>
      45              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      46              : #include <microsim/transportables/MSPerson.h>
      47              : #include <microsim/transportables/MSStageDriving.h>
      48              : #include <microsim/trigger/MSChargingStation.h>
      49              : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
      50              : #include <microsim/trigger/MSTriggeredRerouter.h>
      51              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      52              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      53              : #include "MSEventControl.h"
      54              : #include "MSGlobals.h"
      55              : #include "MSVehicleControl.h"
      56              : #include "MSVehicleType.h"
      57              : #include "MSEdge.h"
      58              : #include "MSLane.h"
      59              : #include "MSMoveReminder.h"
      60              : #include "MSEdgeWeightsStorage.h"
      61              : #include "MSNet.h"
      62              : #include "MSStop.h"
      63              : #include "MSParkingArea.h"
      64              : #include "MSInsertionControl.h"
      65              : #include "MSStopOptimizer.h"
      66              : #include "MSBaseVehicle.h"
      67              : 
      68              : //#define DEBUG_REROUTE
      69              : //#define DEBUG_ADD_STOP
      70              : //#define DEBUG_COND (getID() == "")
      71              : //#define DEBUG_COND (true)
      72              : //#define DEBUG_REPLACE_ROUTE
      73              : #define DEBUG_COND (isSelected())
      74              : 
      75              : // ===========================================================================
      76              : // static members
      77              : // ===========================================================================
      78              : const SUMOTime MSBaseVehicle::NOT_YET_DEPARTED = SUMOTime_MAX;
      79              : std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
      80              : #ifdef _DEBUG
      81              : std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
      82              : #endif
      83              : SUMOTrafficObject::NumericalID MSBaseVehicle::myCurrentNumericalIndex = 0;
      84              : 
      85              : // ===========================================================================
      86              : // Influencer method definitions
      87              : // ===========================================================================
      88              : 
      89         3480 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
      90         3480 : {}
      91              : 
      92              : // ===========================================================================
      93              : // method definitions
      94              : // ===========================================================================
      95              : 
      96              : double
      97            0 : MSBaseVehicle::getPreviousSpeed() const {
      98            0 :     throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
      99              : }
     100              : 
     101              : 
     102      5232272 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
     103      5232272 :                              MSVehicleType* type, const double speedFactor) :
     104              :     SUMOVehicle(pars->id),
     105      5232272 :     myParameter(pars),
     106              :     myRoute(route),
     107      5232272 :     myType(type),
     108      5232272 :     myCurrEdge(route->begin()),
     109      5243365 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     110      5232272 :     myMoveReminders(0),
     111      5232272 :     myPersonDevice(nullptr),
     112      5232272 :     myContainerDevice(nullptr),
     113      5232272 :     myEnergyParams(nullptr),
     114      5232272 :     myDeparture(NOT_YET_DEPARTED),
     115      5232272 :     myDepartPos(-1),
     116      5232272 :     myArrivalPos(-1),
     117      5232272 :     myArrivalLane(-1),
     118      5232272 :     myNumberReroutes(0),
     119      5232272 :     myStopUntilOffset(0),
     120      5232272 :     myOdometer(0.),
     121      5232272 :     myRouteValidity(ROUTE_UNCHECKED),
     122      5232272 :     myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
     123      5232272 :     myNumericalID(myCurrentNumericalIndex++),
     124     10464544 :     myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
     125     10464544 :     myEdgeWeights(nullptr)
     126              : #ifdef _DEBUG
     127              :     , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
     128              : #endif
     129              : {
     130      5232272 :     if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
     131       465880 :         pars->parametersSet |= VEHPARS_FORCE_REROUTE;
     132              :     }
     133      5232272 :     if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
     134      3863070 :         setDepartAndArrivalEdge();
     135              :     }
     136      5232272 :     calculateArrivalParams(true);
     137      5232272 :     initTransientModelParams();
     138      5232272 : }
     139              : 
     140              : 
     141      5232168 : MSBaseVehicle::~MSBaseVehicle() {
     142      5232168 :     delete myEdgeWeights;
     143      5232168 :     if (myParameter->repetitionNumber == -1) {
     144              :         // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
     145       460828 :         MSRoute::checkDist(myParameter->routeid);
     146              :     }
     147      9190292 :     for (MSVehicleDevice* dev : myDevices) {
     148      3958124 :         delete dev;
     149              :     }
     150      5232168 :     delete myEnergyParams;
     151      5232168 :     delete myParkingMemory;
     152      5232168 :     delete myChargingMemory;
     153      5232168 :     checkRouteRemoval();
     154      5232168 :     delete myParameter;
     155      5232168 : }
     156              : 
     157              : 
     158              : void
     159     14260150 : MSBaseVehicle::checkRouteRemoval() {
     160              :     // the check for an instance is needed for the unit tests which do not construct a network
     161              :     // TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
     162     14260148 :     if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
     163       810320 :         myRoute->checkRemoval();
     164              :     }
     165      7130075 : }
     166              : 
     167              : 
     168              : std::string
     169      7130073 : MSBaseVehicle::getFlowID() const {
     170      7130073 :     return getID().substr(0, getID().rfind('.'));
     171              : }
     172              : 
     173              : 
     174              : void
     175      5232272 : MSBaseVehicle::initDevices() {
     176      5232272 :     MSDevice::buildVehicleDevices(*this, myDevices);
     177      9185230 :     for (MSVehicleDevice* dev : myDevices) {
     178      3952975 :         myMoveReminders.push_back(std::make_pair(dev, 0.));
     179              :     }
     180      5232255 :     if (MSGlobals::gHaveEmissions) {
     181              :         // ensure we have the emission parameters even if we don't have the device
     182      1041426 :         getEmissionParameters();
     183              :     }
     184      5232255 : }
     185              : 
     186              : 
     187              : void
     188            0 : MSBaseVehicle::setID(const std::string& /*newID*/) {
     189            0 :     throw ProcessError(TL("Changing a vehicle ID is not permitted"));
     190              : }
     191              : 
     192              : const SUMOVehicleParameter&
     193  15460741355 : MSBaseVehicle::getParameter() const {
     194  15460741355 :     return *myParameter;
     195              : }
     196              : 
     197              : 
     198              : void
     199           54 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
     200           54 :     delete myParameter;
     201           54 :     myParameter = newParameter;
     202           54 : }
     203              : 
     204              : 
     205              : bool
     206   2829310314 : MSBaseVehicle::ignoreTransientPermissions() const {
     207   2829310314 :     return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
     208              : }
     209              : 
     210              : double
     211   7713064910 : MSBaseVehicle::getMaxSpeed() const {
     212   7713064910 :     return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
     213              : }
     214              : 
     215              : 
     216              : const MSEdge*
     217   2193582341 : MSBaseVehicle::succEdge(int nSuccs) const {
     218   2193582341 :     if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
     219   1569731178 :         return *(myCurrEdge + nSuccs);
     220              :     } else {
     221    623851163 :         return nullptr;
     222              :     }
     223              : }
     224              : 
     225              : 
     226              : const MSEdge*
     227   3015207902 : MSBaseVehicle::getEdge() const {
     228   3015207902 :     return *myCurrEdge;
     229              : }
     230              : 
     231              : 
     232              : const std::set<SUMOTrafficObject::NumericalID>
     233        69668 : MSBaseVehicle::getUpcomingEdgeIDs() const {
     234              :     std::set<SUMOTrafficObject::NumericalID> result;
     235       313887 :     for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
     236       244219 :         result.insert((*e)->getNumericalID());
     237              :     }
     238        69668 :     return result;
     239              : }
     240              : 
     241              : 
     242              : bool
     243      3801979 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
     244      3801979 :     if (stop == nullptr) {
     245              :         return false;
     246              :     }
     247      7564817 :     for (const MSStop& s : myStops) {
     248      7563399 :         if (s.busstop == stop
     249      7524672 :                 || s.containerstop == stop
     250      3762854 :                 || s.parkingarea == stop
     251      3762848 :                 || s.chargingStation == stop) {
     252              :             return true;
     253              :         }
     254              :     }
     255              :     return false;
     256              : }
     257              : 
     258              : bool
     259       190436 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
     260       401382 :     for (const MSStop& s : myStops) {
     261       370056 :         if (&s.lane->getEdge() == edge) {
     262              :             return true;
     263              :         }
     264              :     }
     265        31326 :     return myRoute->getLastEdge() == edge;
     266              : }
     267              : 
     268              : 
     269              : bool
     270      2750783 : MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
     271              :     // check whether to reroute
     272      2750783 :     const MSEdge* source = nullptr;
     273      2750783 :     if (onInit) {
     274      2566754 :         if (withTaz) {
     275          529 :             source = MSEdge::dictionary(myParameter->fromTaz + "-source");
     276          529 :             if (source == nullptr) {
     277            5 :                 source = myRoute->getEdges().front();
     278              :             }
     279              :         } else {
     280      2566225 :             source = myRoute->getEdges().front();
     281              :         }
     282              :     } else {
     283       184029 :         source = *getRerouteOrigin();
     284              :     }
     285      2750783 :     if (sink == nullptr) {
     286      2724589 :         sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
     287      2724589 :         if (sink == nullptr) {
     288            5 :             sink = myRoute->getLastEdge();
     289              :         }
     290              :     }
     291      2758784 :     ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
     292              :     ConstMSEdgeVector edges;
     293      2750783 :     if (source != sink || !sink->prohibits(this)) {
     294      2750777 :         edges.push_back(source);
     295              :     }
     296              :     std::vector<StopEdgeInfo> stops;
     297              :     std::set<int> jumps;
     298              : 
     299              : 
     300      2750783 :     double sourcePos = onInit ? 0 : getPositionOnLane();
     301              : #ifdef DEBUG_REROUTE
     302              :     if (DEBUG_COND) {
     303              :         std::cout << " curEdge=" << (*myCurrEdge)->getID() << " source=" << source->getID() << " sourcePos=" << sourcePos << " lane=" << Named::getIDSecure(getLane()) << " departPos=" << myParameter->departPos << " oldEdgesRemaining=" << toString(oldEdgesRemaining) << "\n";
     304              :     }
     305              : #endif
     306      2566754 :     if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
     307        46964 :         sourcePos = myParameter->departPos;
     308      2703819 :     } else if (getLane() != nullptr && source != &getLane()->getEdge()) {
     309              :         // routing starts on the next edge
     310              :         sourcePos = 0;
     311              :     }
     312      2750783 :     if (myParameter->via.size() == 0) {
     313      2740686 :         double firstPos = INVALID_DOUBLE;
     314      2740686 :         double lastPos = INVALID_DOUBLE;
     315      2740686 :         stops = getStopEdges(firstPos, lastPos, jumps);
     316      2740686 :         if (stops.size() > 0) {
     317        39385 :             if (MSGlobals::gUseMesoSim && isStopped()) {
     318          415 :                 sourcePos = getNextStop().pars.endPos;
     319              :             }
     320        39385 :             if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
     321        36060 :                 sourcePos += getBrakeGap();
     322              :             }
     323              :             // avoid superfluous waypoints for first and last edge
     324        39385 :             const bool skipFirst = stops.front().edge == source && (source != getEdge() || sourcePos <= firstPos + NUMERICAL_EPS);
     325              : #ifdef DEBUG_REROUTE
     326              :             if (DEBUG_COND) {
     327              :                 std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
     328              :                           << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
     329              :                           << " route=" << toString(myRoute->getEdges()) << " skipFirst=" << skipFirst << "\n";
     330              :             }
     331              : #endif
     332        39385 :             if (stops.size() == 1 && skipFirst) {
     333              :                 stops.clear();
     334        31924 :             } else if (skipFirst) {
     335         8183 :                 sourcePos = stops.front().pos;
     336              :                 stops.erase(stops.begin());
     337              :             }
     338              :         }
     339              :     } else {
     340              :         std::set<const MSEdge*> jumpEdges;
     341              :         std::map<const MSEdge*, StopEdgeInfo> stopsOnVia;
     342        26473 :         for (const MSStop& stop : myStops) {
     343        16376 :             if (stop.pars.jump >= 0) {
     344              :                 jumpEdges.insert(*stop.edge);
     345              :             }
     346              :             auto itsov = stopsOnVia.find(*stop.edge);
     347        16376 :             if (itsov == stopsOnVia.end()) {
     348        31006 :                 stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
     349              :             } else {
     350          873 :                 itsov->second.priority = addStopPriority(itsov->second.priority, stop.pars.priority);
     351              :             }
     352              :         }
     353              :         // via takes precedence over stop edges
     354              :         // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
     355        32818 :         for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
     356        22729 :             MSEdge* viaEdge = MSEdge::dictionary(*it);
     357        22729 :             if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
     358              :                 continue;
     359              :             }
     360              :             assert(viaEdge != 0);
     361        18733 :             if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
     362           24 :                 throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
     363              :             }
     364              :             auto itsov = stopsOnVia.find(viaEdge);
     365        18725 :             const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
     366        18725 :             const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
     367        18725 :             const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
     368        18725 :             stops.push_back(StopEdgeInfo(viaEdge, priority, arrival, pos));
     369              :             // @todo determine wether the viaEdge is also used by a stop and then use the stop priority here
     370              :             if (jumpEdges.count(viaEdge) != 0) {
     371           15 :                 jumps.insert((int)stops.size());
     372              :             }
     373              :         }
     374              :     }
     375      2712657 :     if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
     376      2808904 :             || ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
     377      5346026 :         stops.push_back(StopEdgeInfo(sink, -1, -1, myArrivalPos, true));
     378              :     }
     379              : #ifdef DEBUG_REROUTE
     380              :     if (DEBUG_COND) {
     381              :         std::cout << SIMTIME << " reroute veh=" << getID() << " onInit=" << onInit << " source=" << source->getID() << " sink=" << sink->getID() << " sourcePos=" << sourcePos << " arrivalPos=" << myArrivalPos << " stops:\n";
     382              :         for (auto item : stops) {
     383              :             std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << " isSink=" << item.isSink << "\n";
     384              :         }
     385              :     }
     386              : #endif
     387              :     int stopIndex = -1;
     388              :     auto stopIt = myStops.begin();
     389              :     SUMOTime startTime = t;
     390              :     bool hasSkipped = false;
     391              :     const double origSourcePos = sourcePos;
     392      2750775 :     const MSEdge* origSource = source;
     393     13753875 :     const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
     394      5492930 :     for (auto& stopEdgeInfo : stops) {
     395      2742161 :         const MSEdge* const stopEdge = stopEdgeInfo.edge;
     396      2742161 :         const double priority = stopEdgeInfo.priority;
     397      2742161 :         stopIndex++;
     398              :         ConstMSEdgeVector into;
     399         1185 :         if (jumps.count(stopIndex) != 0) {
     400         1185 :             edges.push_back(stopEdge);
     401         1185 :             source = stopEdge;
     402         1185 :             continue;
     403              :         }
     404              :         // !!! need to adapt t here
     405      2743135 :         router.compute(source, sourcePos, stopEdge, stopEdgeInfo.pos, this, t, into, silent || priority >= 0);
     406              : #ifdef DEBUG_REROUTE
     407              :         if (DEBUG_COND) {
     408              :             std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " sourcePos=" << sourcePos << " target=" << stopEdgeInfo.edge->getID() << " targetPos=" << stopEdgeInfo.pos << " edges=" << toString(into) << "\n";
     409              :         }
     410              : #endif
     411      2740976 :         if (into.size() > 0) {
     412              :             // stopIt->edge may be invalid when trying to reroute for novel stops
     413      2807857 :             while (stopIt != myStops.end() && stopIt->lane->getNextNormal()->getID() != stopEdge->getID()) {
     414              :                 stopIt++;
     415              :             }
     416              : 
     417      2740167 :             startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
     418      2740167 :             if (stopIt != myStops.end()) {
     419        65059 :                 if (stopIt->pars.priority >= 0 && info != "device.rerouting") {
     420              :                     // consider skipping this stop if it cannot be reached in a timely manner
     421              :                     if (stopIt != myStops.end()) {
     422          189 :                         SUMOTime arrival = stopEdgeInfo.arrival;
     423          189 :                         if (arrival > 0) {
     424           42 :                             SUMOTime delay = startTime - arrival;
     425              :                             //std::cout << " t=" << time2string(t) << " veh=" << getID() << " info=" << info << " stopIndex=" << stopIndex
     426              :                             //   << " into=" << toString(into) << " sourcePos=" << sourcePos << " stopPos=" << stopPos
     427              :                             //   << " startTime=" << time2string(startTime) << " arrival=" << time2string(arrival) << " delay=" << time2string(delay) << "\n";
     428           42 :                             if (delay > 0) {
     429           24 :                                 if (delay > maxDelay) {
     430            9 :                                     stopEdgeInfo.skipped = true;
     431            9 :                                     stopEdgeInfo.delay = delay;
     432              :                                     hasSkipped = true;
     433            9 :                                     continue;
     434              :                                 }
     435              :                             }
     436              :                         }
     437              :                     }
     438              :                 }
     439        65050 :                 sourcePos = stopEdgeInfo.pos;
     440        65050 :                 startTime += stopIt->getMinDuration(startTime);
     441              :             }
     442              :             edges.pop_back();
     443      2740158 :             edges.insert(edges.end(), into.begin(), into.end());
     444      2740158 :             if (edges.back()->isTazConnector()) {
     445              :                 edges.pop_back();
     446              :             }
     447      2740158 :             source = edges.back();
     448      2740158 :             stopEdgeInfo.routeIndex = (int)edges.size() - 1;
     449              :         } else {
     450          809 :             if (priority >= 0) {
     451           53 :                 stopEdgeInfo.skipped = true;
     452              :                 hasSkipped = true;
     453           53 :                 continue;
     454          756 :             } else if (stopEdgeInfo.isSink) {
     455              :                 //error = TLF("Vehicle '%' has no valid route from edge '%' to destination edge '%'.", getID(), source->getID(), stopEdge->getID());
     456              :                 edges.clear();
     457          732 :                 if (onInit && source == stopEdge && stops.size() == 1 && sourcePos > myArrivalPos) {
     458           52 :                     edges.push_back(stopEdge);
     459          208 :                     WRITE_WARNING(TLF("Vehicle '%' ignores arrivalPos % when driving from edge '%' to edge '%'.", getID(), myArrivalPos, source->getID(), stopEdge->getID()));
     460              :                 }
     461           24 :             } else if (source == stopEdge && stopEdgeInfo.stopPar != nullptr && stopEdgeInfo.stopPar->endPos >= sourcePos) {
     462              :                 // special case: no failure on dynamically computed stop position
     463              :                 edges.clear();
     464              :             } else {
     465           16 :                 std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
     466            8 :                 if (MSGlobals::gCheckRoutes || silent) {
     467            6 :                     throw ProcessError(error);
     468              :                 } else {
     469           10 :                     WRITE_WARNING(error);
     470            2 :                     edges.push_back(source);
     471            2 :                     source = stopEdge;
     472              :                 }
     473              :             }
     474              :         }
     475      2742161 :     }
     476      2750769 :     if (hasSkipped) {
     477              :         MSStopOptimizer opti(this, router, t, maxDelay);
     478          180 :         edges = opti.optimizeSkipped(origSource, origSourcePos, stops, edges);
     479          316 :         for (auto stop : stops) {
     480          261 :             if (stop.skipped || stop.origEdge != nullptr) {
     481           62 :                 const MSEdge* origEdge = stop.origEdge == nullptr ? stop.edge : stop.origEdge;
     482           62 :                 if (stop.delay > 0) {
     483           27 :                     WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with delay % at time %.", getID(), origEdge->getID(), time2string(stop.delay), time2string(SIMSTEP)));
     484           53 :                 } else if (stop.backtracked) {
     485            9 :                     WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
     486              :                 } else {
     487          150 :                     WRITE_WARNING(TLF("Vehicle '%' skips unreachable stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
     488              :                 }
     489              :             }
     490              :         }
     491              :     }
     492              : 
     493              :     // router.setHint(myCurrEdge, myRoute->end(), this, t);
     494      2750769 :     if (edges.empty() && silent) {
     495              :         return false;
     496              :     }
     497      2750645 :     if (!edges.empty() && edges.front()->isTazConnector()) {
     498              :         edges.erase(edges.begin());
     499              :     }
     500      2750645 :     if (!edges.empty() && edges.back()->isTazConnector()) {
     501              :         edges.pop_back();
     502              :     }
     503      2750645 :     const double routeCost = router.recomputeCosts(edges, this, t);
     504      2750645 :     const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
     505      2750645 :     const double savings = previousCost - routeCost;
     506      2750645 :     bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
     507              :     if (!savingsOk) {
     508       154638 :         MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
     509              :         assert(routingDevice != 0);
     510       154638 :         savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
     511       154638 :         if (!savingsOk) {
     512              :             std::string dummyMsg;
     513       142658 :             if (!hasValidRoute(dummyMsg, oldEdgesRemaining.begin(), oldEdgesRemaining.end(), true)) {
     514              :                 // the old route is prohibted (i.e. due to temporary permission changes)
     515              :                 savingsOk = true;
     516              :             }
     517              :         }
     518              :     }
     519              :     //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     520              :     //    << " onInit=" << onInit
     521              :     //        << " prevEdges=" << toString(oldEdgesRemaining)
     522              :     //        << " newEdges=" << toString(edges)
     523              :     //        << "\n";
     524       142658 :     if (savingsOk) {
     525      2607994 :         replaceRouteEdges(edges, routeCost, savings, info, onInit, false, hasSkipped);
     526              :     }
     527              :     // this must be called even if the route could not be replaced
     528      2750645 :     if (onInit) {
     529      2566746 :         if (edges.empty()) {
     530          188 :             if (MSGlobals::gCheckRoutes) {
     531          333 :                 throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
     532           77 :             } else if (source->isTazConnector()) {
     533          206 :                 WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
     534           27 :                 MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
     535              :                 return false;
     536              :             }
     537              :         }
     538      2566608 :         setDepartAndArrivalEdge();
     539      2566608 :         calculateArrivalParams(onInit);
     540              :     }
     541      2750507 :     return !edges.empty();
     542      2751033 : }
     543              : 
     544              : 
     545              : bool
     546      2659314 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
     547      2659314 :     if (edges.empty()) {
     548         1734 :         WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
     549          578 :         if (msgReturn != nullptr) {
     550              :             *msgReturn = "No route found";
     551              :         }
     552          578 :         return false;
     553              :     }
     554              :     // build a new id, first
     555              :     std::string id = getID();
     556      2658736 :     if (id[0] != '!') {
     557      5317472 :         id = "!" + id;
     558              :     }
     559      2658736 :     const std::string idSuffix = id + "!var#";
     560      2658736 :     int varIndex = 1;
     561      2658736 :     id = idSuffix + toString(varIndex);
     562      6435252 :     while (MSRoute::hasRoute(id)) {
     563      7553032 :         id = idSuffix + toString(++varIndex);
     564              :     }
     565      2658736 :     int oldSize = (int)edges.size();
     566      2658736 :     if (!onInit) {
     567        90472 :         const MSEdge* const origin = *getRerouteOrigin();
     568        90472 :         if (origin != *myCurrEdge && edges.front() == origin) {
     569          954 :             edges.insert(edges.begin(), *myCurrEdge);
     570          954 :             oldSize = (int)edges.size();
     571              :         }
     572       180944 :         edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
     573              :     }
     574      2658736 :     if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
     575              :         // re-assign stop iterators when rerouting to a new parkingArea / insertStop
     576              :         return true;
     577              :     }
     578      1369270 :     const RGBColor& c = myRoute->getColor();
     579      1369270 :     MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), StopParVector());
     580              :     newRoute->setCosts(cost);
     581              :     newRoute->setSavings(savings);
     582      1369270 :     ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
     583      2738540 :     if (!MSRoute::dictionary(id, constRoute)) {
     584            0 :         delete newRoute;
     585            0 :         if (msgReturn != nullptr) {
     586            0 :             *msgReturn = "duplicate routeID '" + id + "'";
     587              :         }
     588            0 :         return false;
     589              :     }
     590              : 
     591              :     std::string msg;
     592      1369303 :     if (check && !hasValidRoute(msg, constRoute)) {
     593            3 :         WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
     594            1 :         if (MSGlobals::gCheckRoutes) {
     595            1 :             if (msgReturn != nullptr) {
     596              :                 *msgReturn = msg;
     597              :             }
     598            1 :             return false;
     599              :         }
     600              :     }
     601      2738538 :     if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
     602              :         return false;
     603              :     }
     604              :     return true;
     605              : }
     606              : 
     607              : 
     608              : bool
     609      1897925 : MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     610              :     const ConstMSEdgeVector& edges = newRoute->getEdges();
     611              :     // rebuild in-vehicle route information
     612      1897925 :     if (onInit) {
     613      1299341 :         myCurrEdge = newRoute->begin();
     614              :     } else {
     615       598584 :         MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
     616       598584 :         if (newCurrEdge == edges.end()) {
     617            2 :             if (msgReturn != nullptr) {
     618            6 :                 *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
     619              :             }
     620              : #ifdef DEBUG_REPLACE_ROUTE
     621              :             if (DEBUG_COND) {
     622              :                 std::cout << "  newCurrEdge not found\n";
     623              :             }
     624              : #endif
     625            2 :             return false;
     626              :         }
     627       598582 :         if (getLane() != nullptr) {
     628       460979 :             if (getLane()->getEdge().isInternal() && (
     629       460988 :                         (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
     630            9 :                 if (msgReturn != nullptr) {
     631            1 :                     *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
     632              :                 }
     633              : #ifdef DEBUG_REPLACE_ROUTE
     634              :                 if (DEBUG_COND) {
     635              :                     std::cout << "  Vehicle is on junction-internal edge leading elsewhere\n";
     636              :                 }
     637              : #endif
     638            9 :                 return false;
     639       460970 :             } else if (getPositionOnLane() > getLane()->getLength()
     640       460975 :                        && (myCurrEdge + 1) != myRoute->end()
     641           12 :                        && (newCurrEdge + 1) != edges.end()
     642       460982 :                        && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
     643            7 :                 if (msgReturn != nullptr) {
     644            0 :                     *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
     645              :                 }
     646              : #ifdef DEBUG_REPLACE_ROUTE
     647              :                 if (DEBUG_COND) {
     648              :                     std::cout << "  Vehicle is moving past junction and committed to move to another successor edge\n";
     649              :                 }
     650              : #endif
     651            7 :                 return false;
     652              :             }
     653              :         }
     654       598566 :         myCurrEdge = newCurrEdge;
     655              :     }
     656      1897907 :     const bool stopsFromScratch = onInit && myRoute->getStops().empty();
     657              :     // assign new route
     658      1897907 :     checkRouteRemoval();
     659              :     myRoute = newRoute;
     660              :     // update arrival definition
     661      1897907 :     calculateArrivalParams(onInit);
     662              :     // save information that the vehicle was rerouted
     663      1897907 :     myNumberReroutes++;
     664      1897907 :     myStopUntilOffset += myRoute->getPeriod();
     665      1897907 :     MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
     666      1897907 :     if (!onInit && isRail() && MSRailSignalControl::hasInstance()) {
     667              :         // we need to update driveways (add/remove reminders) before the next call to MSRailSignalControl::updateSignals
     668              :         //
     669              :         // rerouting may be triggered through
     670              :         // - MoveReminders (executeMove->activateReminders)
     671              :         //   - rerouters
     672              :         //   - devices (MSDevice_Stationfinder)
     673              :         // - TraCI (changeTarget, replaceStop, ...
     674              :         // - events (MSDevice_Routing::myRerouteCommand, MSDevice_Taxi::triggerDispatch)
     675              :         //
     676              :         // Since activateReminders actively modifies reminders, adding/deleting reminders would create a mess
     677              :         // hence, we use an event to be safe for all case
     678              : 
     679         1496 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new WrappingCommand<MSBaseVehicle>(this,
     680          748 :                 &MSBaseVehicle::activateRemindersOnReroute), SIMSTEP);
     681              :     }
     682              : #ifdef DEBUG_REPLACE_ROUTE
     683              :     if (DEBUG_COND) {
     684              :         std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
     685              :                   << " lane=" << Named::getIDSecure(getLane())
     686              :                   << " stopsFromScratch=" << stopsFromScratch
     687              :                   << "  newSize=" << newRoute->getEdges().size()
     688              :                   << " newIndex=" << (myCurrEdge - newRoute->begin())
     689              :                   << " edges=" << toString(newRoute->getEdges())
     690              :                   << "\n";
     691              :     }
     692              : #endif
     693              :     // remove past stops which are not on the route anymore
     694      1980083 :     for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
     695       131900 :         const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
     696        82176 :         if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
     697            4 :             it = myPastStops.erase(it);
     698              :         } else {
     699              :             ++it;
     700              :         }
     701              :     }
     702              :     // if we did not drive yet it may be best to simply reassign the stops from scratch
     703      1897907 :     if (stopsFromScratch) {
     704              :         myStops.clear();
     705      1299279 :         addStops(!MSGlobals::gCheckRoutes);
     706              :     } else {
     707              :         // recheck old stops
     708       598628 :         MSRouteIterator searchStart = myCurrEdge;
     709       598628 :         double lastPos = getPositionOnLane() + getBrakeGap();
     710      1059591 :         if (getLane() != nullptr && getLane()->isInternal()
     711       599518 :                 && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
     712              :             // searchStart is still incoming to the intersection so lastPos
     713              :             // relative to that edge must be adapted
     714          164 :             lastPos += (*myCurrEdge)->getLength();
     715              :         }
     716              :         int stopIndex = 0;
     717       649412 :         for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
     718              :             int lastToSkip = 0;
     719        50784 :             double endPos = iter->getEndPos(*this);
     720              : #ifdef DEBUG_REPLACE_ROUTE
     721              :             if (DEBUG_COND) {
     722              :                 std::cout << "     stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
     723              :             }
     724              : #endif
     725        50784 :             if (*searchStart != &iter->lane->getEdge()
     726              :                     // loop required to reach upstream position
     727        20857 :                     || endPos + NUMERICAL_EPS < lastPos
     728              :                     // loop requested at duplicate pos
     729        14228 :                     || (endPos == lastPos && iter->pars.index == STOP_INDEX_REPEAT)
     730              :                     // index encodes a skip
     731        64987 :                     || (iter->pars.index > (int)myPastStops.size() + stopIndex
     732              :                         // and we are not already past the skipped edge
     733           16 :                         && lastToSkip < (int)iter->skips.size()
     734        50784 :                         && searchStart - myRoute->begin() <= iter->skips[lastToSkip])) {
     735        36586 :                 if (searchStart != edges.end() && !iter->reached) {
     736              : #ifdef DEBUG_REPLACE_ROUTE
     737              :                     if (DEBUG_COND) {
     738              :                         std::cout << "        skip "  << (*searchStart)->getID() << "\n";
     739              :                     }
     740              : #endif
     741              :                     lastToSkip++;
     742              :                     searchStart++;
     743              :                 }
     744              :             }
     745              :             lastPos = endPos;
     746              : 
     747        50784 :             iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
     748              : #ifdef DEBUG_REPLACE_ROUTE
     749              :             if (DEBUG_COND) {
     750              :                 std::cout << "        foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
     751              :             }
     752              : #endif
     753        50784 :             if (iter->edge == edges.end() && iter->pars.priority >= 0) {
     754              :                 const std::string oldEdge = iter->pars.edge;
     755          124 :                 const std::string oldName = iter->getStoppingPlaceName().first;
     756           62 :                 if (replaceWithAlternative(iter, searchStart, edges.end())) {
     757          164 :                     WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
     758              :                                    getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
     759              :                 }
     760              :             }
     761        50784 :             if (iter->edge == edges.end()) {
     762           76 :                 if (!removeStops) {
     763            4 :                     WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
     764              :                 }
     765           76 :                 iter = myStops.erase(iter);
     766           76 :                 continue;
     767              :             } else {
     768        50708 :                 setSkips(*iter, stopIndex);
     769        50708 :                 searchStart = iter->edge;
     770              :             }
     771              :             ++iter;
     772        50708 :             stopIndex++;
     773              :         }
     774              :         // add new stops
     775       598628 :         if (addRouteStops) {
     776       528922 :             for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
     777              :                 std::string error;
     778          307 :                 addStop(*i, error, myParameter->depart + myStopUntilOffset);
     779          307 :                 if (error != "") {
     780            0 :                     WRITE_WARNING(error);
     781              :                 }
     782              :             }
     783              :         }
     784              :     }
     785              :     return true;
     786              : }
     787              : 
     788              : 
     789              : bool
     790           62 : MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
     791           62 :     std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
     792           62 :     if (!nameTag.first.empty()) {
     793           41 :         const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
     794          110 :         for (MSStoppingPlace* alt : alternatives) {
     795              :             //std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
     796          110 :             if (&alt->getLane().getEdge() == &iter->lane->getEdge()
     797          110 :                     || !alt->getLane().allowsVehicleClass(getVClass())) {
     798           62 :                 continue;
     799              :             }
     800           48 :             iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
     801           48 :             if (iter->edge != end) {
     802           41 :                 iter->replaceStoppingPlace(alt);
     803              :                 return true;
     804              :             }
     805              :         }
     806              :     }
     807              :     return false;
     808              : }
     809              : 
     810              : 
     811              : double
     812       173821 : MSBaseVehicle::getAcceleration() const {
     813       173821 :     return 0;
     814              : }
     815              : 
     816              : 
     817              : void
     818      4145042 : MSBaseVehicle::onDepart() {
     819      4145042 :     myDeparture = MSNet::getInstance()->getCurrentTimeStep();
     820      4145042 :     myDepartPos = getPositionOnLane();
     821      4145042 :     MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
     822      4145042 : }
     823              : 
     824              : 
     825              : SUMOTime
     826      3307398 : MSBaseVehicle:: getDepartDelay() const {
     827      3307398 :     const SUMOTime dep = getParameter().depart;
     828      3307398 :     if (dep < 0) {
     829              :         return 0;
     830              :     }
     831      3307291 :     return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
     832              : }
     833              : 
     834              : 
     835              : bool
     836            0 : MSBaseVehicle::hasArrived() const {
     837            0 :     return succEdge(1) == nullptr;
     838              : }
     839              : 
     840              : 
     841              : int
     842     33841979 : MSBaseVehicle::getRoutePosition() const {
     843     33841979 :     return (int) std::distance(myRoute->begin(), myCurrEdge);
     844              : }
     845              : 
     846              : 
     847              : int
     848       384822 : MSBaseVehicle::getNumRemainingEdges() const {
     849       384822 :     if (myParameter->arrivalEdge >= 0) {
     850            0 :         return myParameter->arrivalEdge - getRoutePosition() + 1;
     851              :     } else {
     852       384822 :         return myRoute->size() - getRoutePosition();
     853              :     }
     854              : }
     855              : 
     856              : 
     857              : void
     858       104044 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
     859       104044 :     myCurrEdge = myRoute->begin() + index;
     860       104044 :     const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
     861              :     // !!! hack
     862       104044 :     myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
     863       104044 : }
     864              : 
     865              : double
     866        27574 : MSBaseVehicle::getOdometer() const {
     867        27574 :     return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
     868              : }
     869              : 
     870              : bool
     871      4005367 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
     872      4005367 :     if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
     873              :         return false;
     874      3901379 :     } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
     875              :         return false;
     876              :     }
     877      7685847 :     if (isStopped() && myStops.begin()->pars.permitted.size() > 0
     878      3842979 :             && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
     879         6244 :         return false;
     880              :     }
     881      3836735 :     MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     882              :     if (taxiDevice != nullptr) {
     883        29249 :         return taxiDevice->allowsBoarding(t);
     884              :     }
     885              :     return true;
     886              : }
     887              : 
     888              : 
     889              : void
     890      3699394 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
     891      3699394 :     if (transportable->isPerson()) {
     892        13380 :         if (myPersonDevice == nullptr) {
     893         4718 :             initTransportableDevice(true);
     894         4718 :             if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
     895         1962 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     896              :             }
     897              :         }
     898        13380 :         myPersonDevice->addTransportable(transportable);
     899              :     } else {
     900      3686014 :         if (myContainerDevice == nullptr) {
     901      3685580 :             initTransportableDevice(false);
     902          424 :             if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
     903           79 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     904              :             }
     905              :         }
     906          858 :         myContainerDevice->addTransportable(transportable);
     907              :     }
     908        14238 :     if (myEnergyParams != nullptr) {
     909         8908 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
     910              :     }
     911        14238 : }
     912              : 
     913              : 
     914              : void
     915      3690325 : MSBaseVehicle::initTransportableDevice(bool isPerson) {
     916      3690325 :     if (isPerson) {
     917         4745 :         myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
     918         4745 :         myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
     919              :     } else {
     920      3685580 :         myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
     921          424 :         myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
     922              :     }
     923         5169 : }
     924              : 
     925              : 
     926              : bool
     927         3111 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
     928         3569 :     for (const MSStop& stop : myStops) {
     929         1094 :         if (stop.edge == it && stop.pars.jump >= 0) {
     930              :             return true;
     931          974 :         } else if (stop.edge > it) {
     932              :             return false;
     933              :         }
     934              :     }
     935              :     return false;
     936              : }
     937              : 
     938              : 
     939              : bool
     940      4519090 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
     941      4519090 :     MSRouteIterator start = myCurrEdge;
     942      4519090 :     if (route == nullptr) {
     943              :         route = myRoute;
     944              :     } else {
     945      3819536 :         start = route->begin();
     946              :     }
     947              :     const bool checkJumps = route == myRoute;  // the edge iterators in the stops are invalid otherwise
     948      4519090 :     return hasValidRoute(msg, start, route->end(), checkJumps);
     949              : }
     950              : 
     951              : 
     952              : bool
     953      4661748 : MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
     954              :     MSRouteIterator lastValid = last - 1;
     955              :     // check connectivity, first
     956     21729998 :     for (MSRouteIterator e = start; e != lastValid; ++e) {
     957     17117497 :         const MSEdge& next = **(e + 1);
     958     17117497 :         if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
     959        50205 :             if (!checkJumps || !hasJump(e)) {
     960        50085 :                 if (!ignoreTransientPermissions()
     961        50085 :                         || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
     962       147741 :                     msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
     963        49247 :                     return false;
     964              :                 }
     965              :             }
     966              :         }
     967              :     }
     968              :     // check usable lanes, then
     969     26292298 :     for (MSRouteIterator e = start; e != last; ++e) {
     970     21679797 :         if ((*e)->prohibits(this)) {
     971            0 :             msg = TLF("Edge '%' prohibits.", (*e)->getID());
     972              :             return false;
     973              :         }
     974              :     }
     975              :     return true;
     976              : }
     977              : 
     978              : 
     979              : bool
     980    509700172 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
     981    509700172 :     if (!(*myCurrEdge)->isTazConnector()) {
     982    509562697 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
     983           12 :             msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
     984            6 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
     985            6 :             return false;
     986              :         }
     987              :     }
     988    509700166 :     if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
     989    509700105 :         myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
     990    509700105 :         return true;
     991              :     } else {
     992          183 :         msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
     993           61 :         myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
     994           61 :         return false;
     995              :     }
     996              : }
     997              : 
     998              : 
     999              : int
    1000   4772997620 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
    1001   4772997620 :     if (!update) {
    1002   2042484013 :         return myRouteValidity;
    1003              :     }
    1004              :     // insertion check must be done in any case
    1005              :     std::string msg;
    1006   2730513607 :     if (!hasValidRouteStart(msg)) {
    1007          188 :         if (MSGlobals::gCheckRoutes) {
    1008          116 :             throw ProcessError(msg);
    1009           72 :         } else if (!silent) {
    1010              :             // vehicle will be discarded
    1011          138 :             WRITE_WARNING(msg);
    1012           26 :         } else if (msgReturn != nullptr) {
    1013              :             *msgReturn = msg;
    1014              :         }
    1015              :     }
    1016        29533 :     if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
    1017   2730483964 :             && (myRouteValidity & ROUTE_UNCHECKED) != 0
    1018              :             // we could check after the first rerouting
    1019   2735614382 :             && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
    1020      7540412 :         if (!hasValidRoute(msg, myRoute)) {
    1021           70 :             myRouteValidity |= ROUTE_INVALID;
    1022          210 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
    1023              :         }
    1024              :     }
    1025   2730513421 :     myRouteValidity &= ~ROUTE_UNCHECKED;
    1026              :     return myRouteValidity;
    1027              : }
    1028              : 
    1029              : 
    1030              : bool
    1031          768 : MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
    1032         3436 :     for (auto item : myMoveReminders) {
    1033         2706 :         if (item.first == rem) {
    1034              :             return true;
    1035              :         }
    1036              :     }
    1037          730 :     return false;
    1038              : }
    1039              : 
    1040              : 
    1041              : void
    1042     26903125 : MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
    1043              : #ifdef _DEBUG
    1044              :     if (myTraceMoveReminders) {
    1045              :         traceMoveReminder("add", rem, pos, true);
    1046              :     }
    1047              : #endif
    1048     26903125 :     myMoveReminders.push_back(std::make_pair(rem, pos));
    1049     26903125 : }
    1050              : 
    1051              : 
    1052              : void
    1053            0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
    1054            0 :     for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
    1055            0 :         if (r->first == rem) {
    1056              : #ifdef _DEBUG
    1057              :             if (myTraceMoveReminders) {
    1058              :                 traceMoveReminder("remove", rem, 0, false);
    1059              :             }
    1060              : #endif
    1061              :             myMoveReminders.erase(r);
    1062              :             return;
    1063              :         }
    1064              :     }
    1065              : }
    1066              : 
    1067              : 
    1068              : void
    1069     49854004 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
    1070              :     // notifyEnter may cause new reminders to be added so we cannot use an iterator
    1071    139783856 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1072     89929855 :         MSMoveReminder* rem = myMoveReminders[i].first;
    1073     89929855 :         const double remPos = myMoveReminders[i].second;
    1074              :         // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
    1075     89929855 :         if (rem->getLane() != nullptr && remPos > 0.) {
    1076              : #ifdef _DEBUG
    1077              :             if (myTraceMoveReminders) {
    1078              :                 traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
    1079              :             }
    1080              : #endif
    1081     18229781 :             ++i;
    1082              :         } else {
    1083     71700074 :             if (rem->notifyEnter(*this, reason, enteredLane)) {
    1084              : #ifdef _DEBUG
    1085              :                 if (myTraceMoveReminders) {
    1086              :                     traceMoveReminder("notifyEnter", rem, remPos, true);
    1087              :                 }
    1088              : #endif
    1089     69746967 :                 ++i;
    1090              :             } else {
    1091              : #ifdef _DEBUG
    1092              :                 if (myTraceMoveReminders) {
    1093              :                     traceMoveReminder("notifyEnter", rem, remPos, false);
    1094              :                 }
    1095              : #endif
    1096              :                 myMoveReminders.erase(myMoveReminders.begin() + i);
    1097              :             }
    1098              :         }
    1099              :     }
    1100     49854001 : }
    1101              : 
    1102              : 
    1103              : bool
    1104   2864954734 : MSBaseVehicle::isRail() const {
    1105   2864954734 :     return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
    1106              : }
    1107              : 
    1108              : void
    1109      9698351 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
    1110      9698351 :     if (myRoute->getLastEdge()->isTazConnector()) {
    1111              :         return;
    1112              :     }
    1113      9232485 :     const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
    1114      9232485 :     if (arrivalEdgeIndex != myParameter->arrivalEdge) {
    1115           21 :         if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
    1116           42 :             WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
    1117              :                            getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
    1118              :         }
    1119              :     }
    1120      9232485 :     const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
    1121      9232485 :     if (!onInit) {
    1122       598566 :         arrivalEdge = myRoute->getLastEdge();
    1123              :         // ignore arrivalEdge parameter after rerouting
    1124       598566 :         const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
    1125              :     }
    1126              :     const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
    1127      9232485 :     const double lastLaneLength = lanes[0]->getLength();
    1128      9232485 :     switch (myParameter->arrivalPosProcedure) {
    1129       217808 :         case ArrivalPosDefinition::GIVEN:
    1130       217808 :             if (fabs(myParameter->arrivalPos) > lastLaneLength) {
    1131         4209 :                 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
    1132              :             }
    1133              :             // Maybe we should warn the user about invalid inputs!
    1134       217808 :             myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
    1135       217808 :             if (myArrivalPos < 0) {
    1136        28170 :                 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
    1137              :             }
    1138              :             break;
    1139              :         case ArrivalPosDefinition::RANDOM:
    1140        72168 :             myArrivalPos = RandHelper::rand(lastLaneLength);
    1141        72168 :             break;
    1142            0 :         case ArrivalPosDefinition::CENTER:
    1143            0 :             myArrivalPos = lastLaneLength / 2.;
    1144            0 :             break;
    1145      8942509 :         default:
    1146      8942509 :             myArrivalPos = lastLaneLength;
    1147      8942509 :             break;
    1148              :     }
    1149      9232485 :     if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
    1150       129670 :         if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
    1151       289557 :             WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
    1152              :         }
    1153       129670 :         myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
    1154      9102815 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
    1155            7 :         myArrivalLane = -1;
    1156            7 :         for (MSLane* lane : lanes) {
    1157            7 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1158            7 :                 myArrivalLane = lane->getIndex();
    1159            7 :                 break;
    1160              :             }
    1161              :         }
    1162            7 :         if (myArrivalLane == -1) {
    1163            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1164            0 :             myArrivalLane = 0;
    1165              :         }
    1166      9102808 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
    1167              :         // pick random lane among all usable lanes
    1168              :         std::vector<MSLane*> usable;
    1169       388321 :         for (MSLane* lane : lanes) {
    1170       295527 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1171       270417 :                 usable.push_back(lane);
    1172              :             }
    1173              :         }
    1174        92794 :         if (usable.empty()) {
    1175            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1176            0 :             myArrivalLane = 0;
    1177              :         } else {
    1178        92794 :             myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
    1179              :         }
    1180        92794 :     }
    1181      9232485 :     if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
    1182       257287 :         for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
    1183       191332 :             if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
    1184              :                 return;
    1185              :             }
    1186              :         }
    1187       197865 :         WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
    1188              :     }
    1189              : }
    1190              : 
    1191              : void
    1192      6429678 : MSBaseVehicle::setDepartAndArrivalEdge() {
    1193      6429678 :     SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
    1194      6429678 :     if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
    1195         8148 :         const int routeEdges = (int)myRoute->getEdges().size();
    1196         8148 :         if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1197              :             // write specific edge in vehroute output for reproducibility
    1198         4185 :             pars->departEdge = RandHelper::rand(0, routeEdges);
    1199         4185 :             pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
    1200              :         }
    1201              :         assert(pars->departEdge >= 0);
    1202         8148 :         if (pars->departEdge >= routeEdges) {
    1203            0 :             WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
    1204              :         } else {
    1205         8148 :             myCurrEdge = myRoute->begin() + pars->departEdge;
    1206              :         }
    1207              :     }
    1208      6429678 :     if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1209          147 :         const int routeEdges = (int)myRoute->getEdges().size();
    1210          147 :         const int begin = (int)(myCurrEdge - myRoute->begin());
    1211              :         // write specific edge in vehroute output for reproducibility
    1212          147 :         pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
    1213          147 :         pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
    1214              :         assert(pars->arrivalEdge >= begin);
    1215              :         assert(pars->arrivalEdge < routeEdges);
    1216              :     }
    1217      6429678 : }
    1218              : 
    1219              : int
    1220         4393 : MSBaseVehicle::getDepartEdge() const {
    1221         4393 :     return myParameter->departEdge < myRoute->size() ? myParameter->departEdge : 0;
    1222              : }
    1223              : 
    1224              : int
    1225     30673837 : MSBaseVehicle::getInsertionChecks() const {
    1226     30673837 :     if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
    1227       269945 :         return getParameter().insertionChecks;
    1228              :     } else {
    1229     30403892 :         return MSGlobals::gInsertionChecks;
    1230              :     }
    1231              : }
    1232              : 
    1233              : double
    1234    647219167 : MSBaseVehicle::getImpatience() const {
    1235   1294438334 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
    1236    647219167 :                          + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
    1237    647219167 :                          + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
    1238              : }
    1239              : 
    1240              : 
    1241              : MSDevice*
    1242   1008770450 : MSBaseVehicle::getDevice(const std::type_info& type) const {
    1243   1755291315 :     for (MSVehicleDevice* const dev : myDevices) {
    1244    848679300 :         if (typeid(*dev) == type) {
    1245    102158435 :             return dev;
    1246              :         }
    1247              :     }
    1248              :     return nullptr;
    1249              : }
    1250              : 
    1251              : 
    1252              : void
    1253         4348 : MSBaseVehicle::saveState(OutputDevice& out) {
    1254              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
    1255         4348 :     const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
    1256         4348 :     myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
    1257              :     // params and stops must be written in child classes since they may wish to add additional attributes first
    1258         4348 :     out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
    1259         4348 :     std::ostringstream os;
    1260         8696 :     os << myOdometer << " " << myNumberReroutes;
    1261         4348 :     out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
    1262         4348 :     if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
    1263           13 :         out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
    1264              :     }
    1265         4348 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
    1266              :         const int precision = out.getPrecision();
    1267         4346 :         out.setPrecision(MAX2(gPrecisionRandom, precision));
    1268         4346 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
    1269         4346 :         out.setPrecision(precision);
    1270              :     }
    1271         4348 :     if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    1272         2918 :         out.writeAttr(SUMO_ATTR_REROUTE, true);
    1273              :     }
    1274         4348 :     if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
    1275              :         // could be set from stop
    1276           33 :         out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
    1277              :     }
    1278              :     // here starts the vehicle internal part (see loading)
    1279              :     // @note: remember to close the vehicle tag when calling this in a subclass!
    1280         8696 : }
    1281              : 
    1282              : 
    1283              : bool
    1284            0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    1285              :     UNUSED_PARAMETER(stop);
    1286              :     UNUSED_PARAMETER(distToStop);
    1287            0 :     return true;
    1288              : }
    1289              : 
    1290              : 
    1291              : bool
    1292   9607624917 : MSBaseVehicle::isStopped() const {
    1293   9607624917 :     return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
    1294              : }
    1295              : 
    1296              : 
    1297              : bool
    1298   2677114531 : MSBaseVehicle::isParking() const {
    1299   2733931453 :     return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
    1300      5132199 :             && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
    1301   2681187432 :             && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
    1302              : }
    1303              : 
    1304              : 
    1305              : bool
    1306    678717721 : MSBaseVehicle::isJumping() const {
    1307    678717721 :     return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
    1308              : }
    1309              : 
    1310              : 
    1311              : bool
    1312     16041320 : MSBaseVehicle::isStoppedTriggered() const {
    1313     16041320 :     return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
    1314              : }
    1315              : 
    1316              : 
    1317              : bool
    1318     12049747 : MSBaseVehicle::isStoppedParking() const {
    1319     12049747 :     return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
    1320              : }
    1321              : 
    1322              : 
    1323              : bool
    1324      3703843 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
    1325      3703843 :     if (isStopped() || (checkFuture && hasStops())) {
    1326              :         const MSStop& stop = myStops.front();
    1327      3705065 :         return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
    1328              :     }
    1329              :     return false;
    1330              : }
    1331              : 
    1332              : bool
    1333        28900 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
    1334              :     // Check if there is a parking area to be replaced
    1335        28900 :     if (parkingArea == 0) {
    1336              :         errorMsg = "new parkingArea is NULL";
    1337            0 :         return false;
    1338              :     }
    1339        28900 :     if (myStops.size() == 0) {
    1340              :         errorMsg = "vehicle has no stops";
    1341            0 :         return false;
    1342              :     }
    1343        28900 :     if (myStops.front().parkingarea == 0) {
    1344              :         errorMsg = "first stop is not at parkingArea";
    1345            0 :         return false;
    1346              :     }
    1347              :     MSStop& first = myStops.front();
    1348              :     SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
    1349        28900 :     std::string oldStopEdgeID = first.lane->getEdge().getID();
    1350              :     // merge subsequent duplicate stops equals to parking area
    1351        28916 :     for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
    1352          288 :         if (iter->parkingarea == parkingArea) {
    1353           16 :             stopPar.duration += iter->duration;
    1354           16 :             myStops.erase(iter++);
    1355              :         } else {
    1356              :             break;
    1357              :         }
    1358              :     }
    1359        28900 :     stopPar.lane = parkingArea->getLane().getID();
    1360        28900 :     stopPar.parkingarea = parkingArea->getID();
    1361        28900 :     stopPar.startPos = parkingArea->getBeginLanePosition();
    1362        28900 :     stopPar.endPos = parkingArea->getEndLanePosition();
    1363        28900 :     stopPar.index = STOP_INDEX_FIT;
    1364        28900 :     first.edge = myRoute->end(); // will be patched in replaceRoute
    1365        28900 :     first.lane = &parkingArea->getLane();
    1366        28900 :     first.parkingarea = parkingArea;
    1367              : 
    1368              :     // patch via edges
    1369        28900 :     std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
    1370        28900 :     if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
    1371          194 :         if (myParameter->via.front() == oldStopEdgeID) {
    1372          110 :             myParameter->via.erase(myParameter->via.begin());
    1373              :         }
    1374          194 :         myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
    1375              :     }
    1376              :     return true;
    1377              : }
    1378              : 
    1379              : 
    1380              : MSParkingArea*
    1381       208552 : MSBaseVehicle::getNextParkingArea() {
    1382              :     MSParkingArea* nextParkingArea = nullptr;
    1383       208552 :     if (!myStops.empty()) {
    1384       204916 :         SUMOVehicleParameter::Stop stopPar;
    1385       204916 :         MSStop stop = myStops.front();
    1386       204916 :         if (!stop.reached && stop.parkingarea != nullptr) {
    1387              :             nextParkingArea = stop.parkingarea;
    1388              :         }
    1389       204916 :     }
    1390       208552 :     return nextParkingArea;
    1391              : }
    1392              : 
    1393              : 
    1394              : MSParkingArea*
    1395        80934 : MSBaseVehicle::getCurrentParkingArea() {
    1396              :     MSParkingArea* currentParkingArea = nullptr;
    1397        80934 :     if (isParking()) {
    1398        80861 :         currentParkingArea = myStops.begin()->parkingarea;
    1399              :     }
    1400        80934 :     return currentParkingArea;
    1401              : }
    1402              : 
    1403              : 
    1404              : const std::vector<std::string>&
    1405         1656 : MSBaseVehicle::getParkingBadges() const {
    1406         1656 :     if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
    1407            7 :         return myParameter->parkingBadges;
    1408              :     } else {
    1409         1649 :         return getVehicleType().getParkingBadges();
    1410              :     }
    1411              : }
    1412              : 
    1413              : 
    1414              : double
    1415     11167455 : MSBaseVehicle::basePos(const MSEdge* edge) const {
    1416     11167455 :     double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
    1417     11167455 :     if (hasStops()
    1418     11192086 :             && myStops.front().edge == myRoute->begin()
    1419     11192086 :             && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
    1420        24587 :         result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
    1421              :     }
    1422     11167455 :     return result;
    1423              : }
    1424              : 
    1425              : 
    1426              : MSLane*
    1427          298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
    1428          298 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
    1429          298 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
    1430          298 :     if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
    1431            8 :         return nullptr;
    1432              :     }
    1433          580 :     const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
    1434          290 :     if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
    1435          290 :         const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
    1436          290 :         stop.edge = edgeID;
    1437          290 :         return edge->getOppositeEdge()->getLanes()[oppositeIndex];
    1438              :     }
    1439              :     return nullptr;
    1440              : }
    1441              : 
    1442              : 
    1443              : bool
    1444       141467 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
    1445              :                        MSRouteIterator* searchStart) {
    1446       141467 :     MSStop stop(stopPar);
    1447       141467 :     if (stopPar.lane == "") {
    1448         3236 :         MSEdge* e = MSEdge::dictionary(stopPar.edge);
    1449         3236 :         stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
    1450         3236 :         if (stop.lane == nullptr) {
    1451            0 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
    1452            0 :             return false;
    1453              :         }
    1454              :     } else {
    1455       138231 :         stop.lane = MSLane::dictionary(stopPar.lane);
    1456       138231 :         if (stop.lane == nullptr) {
    1457              :             // must be an opposite stop
    1458          145 :             SUMOVehicleParameter::Stop tmp = stopPar;
    1459          145 :             stop.lane = interpretOppositeStop(tmp);
    1460              :             assert(stop.lane != nullptr);
    1461          145 :         }
    1462       138231 :         if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
    1463           24 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
    1464           12 :             return false;
    1465              :         }
    1466              :     }
    1467       141455 :     if (MSGlobals::gUseMesoSim) {
    1468        29602 :         stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
    1469        29602 :         if (stop.lane->isInternal()) {
    1470           90 :             errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
    1471           45 :             return false;
    1472              :         }
    1473              :     }
    1474       141410 :     stop.initPars(stopPar);
    1475       141410 :     if (stopPar.until != -1) {
    1476              :         // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
    1477        53617 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
    1478              :     }
    1479       141410 :     if (stopPar.arrival != -1) {
    1480          689 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
    1481              :     }
    1482       141410 :     std::string stopType = "stop";
    1483       141410 :     std::string stopID = "";
    1484       141410 :     double parkingLength = stop.pars.endPos - stop.pars.startPos;
    1485       141410 :     if (stop.busstop != nullptr) {
    1486              :         stopType = "busStop";
    1487        38065 :         stopID = stop.busstop->getID();
    1488        38065 :         parkingLength = stop.busstop->getParkingLength();
    1489       103345 :     } else if (stop.containerstop != nullptr) {
    1490              :         stopType = "containerStop";
    1491         1050 :         stopID = stop.containerstop->getID();
    1492         1050 :         parkingLength = stop.containerstop->getParkingLength();
    1493       102295 :     } else if (stop.chargingStation != nullptr) {
    1494              :         stopType = "chargingStation";
    1495         8310 :         stopID = stop.chargingStation->getID();
    1496         8310 :         parkingLength = stop.chargingStation->getParkingLength();
    1497        93985 :     } else if (stop.overheadWireSegment != nullptr) {
    1498              :         stopType = "overheadWireSegment";
    1499            0 :         stopID = stop.overheadWireSegment->getID();
    1500            0 :         parkingLength = stop.overheadWireSegment->getParkingLength();
    1501        93985 :     } else if (stop.parkingarea != nullptr) {
    1502              :         stopType = "parkingArea";
    1503        29807 :         stopID = stop.parkingarea->getID();
    1504              :     }
    1505       282820 :     const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
    1506              : 
    1507       141410 :     if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
    1508            0 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
    1509            0 :         return false;
    1510              :     }
    1511        77232 :     if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
    1512              :             // do not warn for stops that fill the whole lane
    1513          331 :             && parkingLength < stop.lane->getLength()
    1514              :             // do not warn twice for the same stop
    1515       219551 :             && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
    1516          909 :         errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
    1517              :     }
    1518       141410 :     if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
    1519              :         // forbid access in case the parking requests other badges
    1520           14 :         errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
    1521            7 :         return false;
    1522              :     }
    1523       141403 :     const MSEdge* stopLaneEdge = &stop.lane->getEdge();
    1524              :     const MSEdge* stopEdge;
    1525       141403 :     if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
    1526              :         // stop lane is on the opposite side
    1527          145 :         stopEdge = stopLaneEdge->getOppositeEdge();
    1528          145 :         stop.isOpposite = true;
    1529              :     } else {
    1530              :         // if stop is on an internal edge the normal edge before the intersection is used
    1531       141258 :         stopEdge = stopLaneEdge->getNormalBefore();
    1532              :     }
    1533       141403 :     MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
    1534       141403 :     if (searchStart == nullptr) {
    1535       134032 :         searchStart = &myCurrEdge;
    1536       134032 :         if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
    1537              :             // already on the intersection but myCurrEdge is before it
    1538              :             searchStart = &succ;
    1539              :         }
    1540              :     }
    1541              : #ifdef DEBUG_ADD_STOP
    1542              :     if (DEBUG_COND) {
    1543              :         std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
    1544              :                   << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
    1545              :                   << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
    1546              :                   << " stopParIndex=" << stopPar.index
    1547              :                   << "\n";
    1548              :     }
    1549              : #endif
    1550       141403 :     stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
    1551       141403 :     MSRouteIterator prevStopEdge = myCurrEdge;
    1552       141403 :     const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
    1553       141403 :     double prevStopPos = getPositionOnLane();
    1554              :     // where to insert the stop
    1555              :     std::list<MSStop>::iterator iter = myStops.begin();
    1556       141403 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
    1557              :         iter = myStops.end();
    1558       118699 :         if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
    1559              :             prevStopEdge = myStops.back().edge;
    1560        50234 :             prevEdge = &myStops.back().lane->getEdge();
    1561        50234 :             prevStopPos = myStops.back().pars.endPos;
    1562        50234 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1563              :             if (prevStopEdge == stop.edge                // laneEdge check is insufficient for looped routes
    1564         8086 :                     && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
    1565        58308 :                     && (prevStopPos > stop.pars.endPos ||
    1566         2248 :                         (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
    1567          455 :                 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
    1568              :             }
    1569              : #ifdef DEBUG_ADD_STOP
    1570              :             if (DEBUG_COND) {
    1571              :                 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
    1572              :                           << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
    1573              :             }
    1574              : #endif
    1575              :         }
    1576              :         // skip a number of occurences of stopEdge in looped route
    1577       118699 :         int skipLooped = stopPar.index - static_cast<int>(myStops.size());
    1578       119283 :         for (int j = 0; j < skipLooped; j++) {
    1579          730 :             auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
    1580          730 :             if (nextIt == myRoute->end()) {
    1581          146 :                 if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
    1582              :                     // only warn if the route loops over the stop edge at least once
    1583           28 :                     errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
    1584              :                 }
    1585          146 :                 break;
    1586              :             } else {
    1587          584 :                 stop.edge = nextIt;
    1588              :             }
    1589              :         }
    1590              :     } else {
    1591        22704 :         if (stopPar.index == STOP_INDEX_FIT) {
    1592        34282 :             while (iter != myStops.end() && (iter->edge < stop.edge ||
    1593         1922 :                                              (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
    1594         1922 :                                              (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
    1595              :                 prevStopEdge = iter->edge;
    1596        11681 :                 prevStopPos = iter->pars.endPos;
    1597              :                 ++iter;
    1598              :             }
    1599              :         } else {
    1600              :             int index = stopPar.index;
    1601          103 :             while (index > 0) {
    1602            0 :                 prevStopEdge = iter->edge;
    1603            0 :                 prevStopPos = iter->pars.endPos;
    1604              :                 ++iter;
    1605            0 :                 --index;
    1606              :             }
    1607              : #ifdef DEBUG_ADD_STOP
    1608              :             if (DEBUG_COND) {
    1609              :                 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
    1610              :             }
    1611              : #endif
    1612          103 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1613              :         }
    1614              :     }
    1615       141780 :     const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
    1616       141403 :     if (stop.edge == myRoute->end()) {
    1617           89 :         if (!wasTooClose) {
    1618          207 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
    1619              :         }
    1620           89 :         return false;
    1621              :     }
    1622              : 
    1623       141314 :     const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
    1624        43693 :                            prevStopPos + (iter == myStops.begin() && !instantStopping() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
    1625              : 
    1626       141314 :     if (prevStopEdge > stop.edge ||
    1627              :             // a collision-stop happens after vehicle movement and may move the
    1628              :             // vehicle backwards on its lane (prevStopPos is the vehicle position)
    1629         1889 :             (tooClose && !stop.pars.collision)
    1630       282579 :             || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
    1631              :         // check if the edge occurs again later in the route
    1632              :         //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges())  << "\n";
    1633           49 :         if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
    1634          141 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
    1635              :         }
    1636           49 :         MSRouteIterator next = stop.edge + 1;
    1637           49 :         return addStop(stopPar, errorMsg, untilOffset, &next);
    1638              :     }
    1639              :     // David.C:
    1640              :     //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
    1641       141265 :     const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
    1642       141265 :     const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
    1643       141265 :     if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
    1644              :         return false;
    1645              :     }
    1646       141265 :     if (!hasDeparted() && myCurrEdge == stop.edge) {
    1647              :         double pos = -1;
    1648        26781 :         if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
    1649         5011 :             pos = myParameter->departPos;
    1650         5011 :             if (pos < 0.) {
    1651          219 :                 pos += (*myCurrEdge)->getLength();
    1652              :             }
    1653              :         }
    1654        26781 :         if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
    1655        18606 :             pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
    1656              :         }
    1657        26781 :         if (pos > stop.pars.endPos + endPosOffset) {
    1658           20 :             if (stop.edge != myRoute->end()) {
    1659              :                 // check if the edge occurs again later in the route
    1660           20 :                 MSRouteIterator next = stop.edge + 1;
    1661           20 :                 return addStop(stopPar, errorMsg, untilOffset, &next);
    1662              :             }
    1663            0 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
    1664            0 :             return false;
    1665              :         }
    1666              :     }
    1667       141245 :     if (iter != myStops.begin()) {
    1668              :         std::list<MSStop>::iterator iter2 = iter;
    1669              :         iter2--;
    1670        97437 :         if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
    1671        61858 :                 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
    1672            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1673           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1674           24 :                        + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
    1675              :         }
    1676        61841 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1677            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1678           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1679           24 :                        + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
    1680              :         }
    1681        61841 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1682            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1683           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1684           24 :                        + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
    1685              :         }
    1686              :     } else {
    1687        97421 :         if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
    1688        79416 :                 && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
    1689            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1690           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1691           24 :                        + " earlier than departure at " + time2string(getParameter().depart) + ".";
    1692              :         }
    1693              :     }
    1694       141245 :     if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
    1695           18 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1696           54 :                    + "' set to end at " + time2string(stop.getUntil())
    1697           72 :                    + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
    1698              :     }
    1699       141245 :     setSkips(stop, (int)myStops.size());
    1700       141245 :     myStops.insert(iter, stop);
    1701       141245 :     if (stopPar.tripId != "") {
    1702         2664 :         MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
    1703              :     }
    1704              : #ifdef DEBUG_ADD_STOP
    1705              :     if (DEBUG_COND) {
    1706              :         std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size()
    1707              :             << " routeIndex=" << (stop.edge - myRoute->begin())
    1708              :             << " stopIndex=" << std::distance(myStops.begin(), iter)
    1709              :             //<< " searchStart=" << (*searchStart - myRoute->begin())
    1710              :             //<< " route=" << toString(myRoute->getEdges())
    1711              :             << "\n";
    1712              :     }
    1713              : #endif
    1714              :     return true;
    1715              : }
    1716              : 
    1717              : 
    1718              : void
    1719       191953 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
    1720       191953 :     if (hasDeparted() && stop.edge > myRoute->begin()) {
    1721              :         // if the route is looped we must patch the index to ensure that state
    1722              :         // loading (and vehroute-output) encode the correct number of skips
    1723              :         stop.skips.clear();
    1724              :         MSRouteIterator itPrev;
    1725              :         double prevEndPos;
    1726        85716 :         if (prevActiveStops > 0) {
    1727              :             assert((int)myStops.size() >= prevActiveStops);
    1728              :             auto prevStopIt = myStops.begin();
    1729        37575 :             std::advance(prevStopIt, prevActiveStops - 1);
    1730              :             const MSStop& prev = *prevStopIt;
    1731        37575 :             itPrev = prev.edge;
    1732        37575 :             prevEndPos = prev.pars.endPos;
    1733        48141 :         } else if (myPastStops.size() > 0) {
    1734        12534 :             itPrev = myRoute->begin() + myPastStops.back().routeIndex;
    1735        12534 :             prevEndPos = myPastStops.back().endPos;
    1736              :         } else {
    1737        35607 :             itPrev = myRoute->begin() + myParameter->departEdge;
    1738        35607 :             prevEndPos = myDepartPos;
    1739              :         }
    1740              :         //auto itPrevOrig = itPrev;
    1741        85716 :         if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
    1742              :             itPrev++;
    1743              :         }
    1744              :         //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
    1745       758753 :         while (itPrev < stop.edge) {
    1746       673037 :             if (*itPrev == *stop.edge) {
    1747        49827 :                 stop.skips.push_back((int)(itPrev - myRoute->begin()));
    1748              :             }
    1749              :             itPrev++;
    1750              :         }
    1751              :         int newIndex = STOP_INDEX_END;
    1752        85716 :         if (!stop.skips.empty()) {
    1753              :             //if (getID() == "77_0_0") {
    1754              :             //    std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
    1755              :             //        << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
    1756              :             //        << " prevEdge=" << (*itPrevOrig)->getID()
    1757              :             //        << " prevIndex=" << (itPrevOrig - myRoute->begin())
    1758              :             //        << " skips=" << foundSkips << "\n";
    1759              :             //}
    1760        21510 :             newIndex = (int)myPastStops.size() + prevActiveStops + (int)stop.skips.size();
    1761              :         }
    1762        85716 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
    1763              :     }
    1764       191953 : }
    1765              : 
    1766              : 
    1767              : SUMOTime
    1768          743 : MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
    1769         3969 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1770         3226 :         auto rem = &myMoveReminders[i];
    1771         3226 :         if (rem->first->notifyReroute(*this)) {
    1772              : #ifdef _DEBUG
    1773              :             if (myTraceMoveReminders) {
    1774              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, true);
    1775              :             }
    1776              : #endif
    1777         2464 :             ++i;
    1778              :         } else {
    1779              : #ifdef _DEBUG
    1780              :             if (myTraceMoveReminders) {
    1781              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, false);
    1782              :             }
    1783              : #endif
    1784              :             myMoveReminders.erase(myMoveReminders.begin() + i);
    1785              :         }
    1786              :     }
    1787          743 :     resetApproachOnReroute();
    1788              :     // event only called once
    1789          743 :     return 0;
    1790              : }
    1791              : 
    1792              : 
    1793              : void
    1794      6531512 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
    1795      6531512 :     if (addRouteStops) {
    1796      6536787 :         for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    1797              :             std::string errorMsg;
    1798        10075 :             if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
    1799            6 :                 throw ProcessError(errorMsg);
    1800              :             }
    1801        10069 :             if (errorMsg != "") {
    1802          687 :                 WRITE_WARNING(errorMsg);
    1803              :             }
    1804              :         }
    1805              :     }
    1806      6531506 :     const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
    1807      6631157 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    1808              :         std::string errorMsg;
    1809        99723 :         if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
    1810           72 :             throw ProcessError(errorMsg);
    1811              :         }
    1812        99651 :         if (errorMsg != "") {
    1813          507 :             WRITE_WARNING(errorMsg);
    1814              :         }
    1815              :     }
    1816      6531434 : }
    1817              : 
    1818              : 
    1819              : bool
    1820      1298876 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
    1821      1298876 :     MSRouteIterator start = myCurrEdge;
    1822              :     int i = 0;
    1823              :     bool ok = true;
    1824      1326651 :     for (const MSStop& stop : myStops) {
    1825              :         MSRouteIterator it;
    1826        27775 :         if (stop.lane->isInternal()) {
    1827              :             // find the normal predecessor and ensure that the next route edge
    1828              :             // matches the successor of the internal edge successor
    1829            0 :             it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
    1830            0 :             if (it != myRoute->end() && (
    1831            0 :                         it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
    1832            0 :                 it = myRoute->end(); // signal failure
    1833              :             }
    1834              :         } else {
    1835        27775 :             it = std::find(start, myRoute->end(), &stop.lane->getEdge());
    1836              :         }
    1837        27775 :         if (it == myRoute->end()) {
    1838            0 :             if (!silent) {
    1839            0 :                 WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
    1840              :                              i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1841              :             }
    1842              :             ok = false;
    1843              :         } else {
    1844              :             MSRouteIterator it2;
    1845      1118465 :             for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
    1846      1109055 :                 if (it2 == stop.edge) {
    1847              :                     break;
    1848              :                 }
    1849              :             }
    1850        27775 :             if (it2 == myRoute->end()) {
    1851         9410 :                 if (!silent) {
    1852            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
    1853              :                                  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
    1854              :                 }
    1855              :                 ok = false;
    1856        18365 :             } else if (it2 < start) {
    1857            0 :                 if (!silent) {
    1858            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
    1859              :                                  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1860              :                 }
    1861              :                 ok = false;
    1862              :             } else {
    1863        18365 :                 start = stop.edge;
    1864              :             }
    1865              :         }
    1866        27775 :         i++;
    1867              :     }
    1868      1298876 :     return ok;
    1869              : }
    1870              : 
    1871              : 
    1872              : std::vector<MSBaseVehicle::StopEdgeInfo>
    1873      2740686 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
    1874              :     assert(haveValidStopEdges());
    1875              :     std::vector<StopEdgeInfo> result;
    1876              :     const MSStop* prev = nullptr;
    1877              :     const MSEdge* internalSuccessor = nullptr;
    1878      2818127 :     for (const MSStop& stop : myStops) {
    1879        77441 :         if (stop.reached) {
    1880        10118 :             if (stop.pars.jump >= 0) {
    1881            0 :                 jumps.insert((int)result.size());
    1882              :             }
    1883        10118 :             continue;
    1884              :         }
    1885        67323 :         double stopPos = stop.getEndPos(*this);
    1886              :         if ((prev == nullptr
    1887        27938 :                 || prev->edge != stop.edge
    1888         1259 :                 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
    1889        94002 :                 && *stop.edge != internalSuccessor) {
    1890        66064 :             if (stop.lane->isInternal()) {
    1891            9 :                 stopPos = (*stop.edge)->getLength();
    1892              :             }
    1893        66064 :             result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
    1894        66064 :             result.back().nameTag = stop.getStoppingPlaceName();
    1895        66064 :             result.back().stopPar = &stop.pars;
    1896        66064 :             if (stop.lane->isInternal()) {
    1897            9 :                 internalSuccessor = stop.lane->getNextNormal();
    1898           18 :                 result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
    1899              :             } else {
    1900              :                 internalSuccessor = nullptr;
    1901              :             }
    1902         1259 :         } else if (prev != nullptr && prev->edge == stop.edge) {
    1903         1259 :             result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
    1904              :         }
    1905              :         prev = &stop;
    1906        67323 :         if (firstPos == INVALID_DOUBLE) {
    1907        39385 :             if (stop.parkingarea != nullptr) {
    1908         3542 :                 firstPos = MAX2(0., stopPos);
    1909              :             } else {
    1910        35843 :                 firstPos = stopPos;
    1911              :             }
    1912              :         }
    1913        67323 :         lastPos = stopPos;
    1914        67323 :         if (stop.pars.jump >= 0) {
    1915         1208 :             jumps.insert((int)result.size() - 1);
    1916              :         }
    1917              :     }
    1918              :     //std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
    1919              :     //for (auto item : result) {
    1920              :     //    std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
    1921              :     //}
    1922      2740686 :     return result;
    1923            0 : }
    1924              : 
    1925              : 
    1926              : double
    1927         2132 : MSBaseVehicle::addStopPriority(double p1, double p2) {
    1928         2132 :     if (p1 < 0 || p2 < 0) {
    1929              :         return p1;
    1930              :     }
    1931            0 :     return p1 + p2;
    1932              : }
    1933              : 
    1934              : std::vector<std::pair<int, double> >
    1935        41265 : MSBaseVehicle::getStopIndices() const {
    1936              :     std::vector<std::pair<int, double> > result;
    1937        83708 :     for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
    1938        84886 :         result.push_back(std::make_pair(
    1939        42443 :                              (int)(iter->edge - myRoute->begin()),
    1940        42443 :                              iter->getEndPos(*this)));
    1941              :     }
    1942        41265 :     return result;
    1943            0 : }
    1944              : 
    1945              : 
    1946              : const MSStop&
    1947     15955707 : MSBaseVehicle::getNextStop() const {
    1948              :     assert(myStops.size() > 0);
    1949     15955707 :     return myStops.front();
    1950              : }
    1951              : 
    1952              : MSStop&
    1953       107525 : MSBaseVehicle::getNextStopMutable() {
    1954              :     assert(myStops.size() > 0);
    1955       107525 :     return myStops.front();
    1956              : }
    1957              : 
    1958              : SUMOTime
    1959      3632703 : MSBaseVehicle::getStopDuration() const {
    1960      3632703 :     if (isStopped()) {
    1961      1181951 :         return myStops.front().duration;
    1962              :     } else {
    1963              :         return 0;
    1964              :     }
    1965              : }
    1966              : 
    1967              : 
    1968              : MSStop&
    1969       325217 : MSBaseVehicle::getStop(int nextStopIndex) {
    1970       325217 :     if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
    1971            0 :         throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
    1972              :     }
    1973              :     auto stopIt = myStops.begin();
    1974              :     std::advance(stopIt, nextStopIndex);
    1975       325217 :     return *stopIt;
    1976              : }
    1977              : 
    1978              : 
    1979              : const SUMOVehicleParameter::Stop*
    1980       287051 : MSBaseVehicle::getNextStopParameter() const {
    1981       287051 :     if (hasStops()) {
    1982       128132 :         return &myStops.front().pars;
    1983              :     }
    1984              :     return nullptr;
    1985              : }
    1986              : 
    1987              : 
    1988              : bool
    1989        45050 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    1990              :     //if the stop exists update the duration
    1991        69771 :     for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
    1992        46898 :         if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
    1993              :             // update existing stop
    1994        22177 :             if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
    1995        20659 :                 myStops.erase(iter);
    1996              :             } else {
    1997         1518 :                 iter->duration = stop.duration;
    1998         1518 :                 iter->triggered = stop.triggered;
    1999         1518 :                 iter->containerTriggered = stop.containerTriggered;
    2000         1518 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
    2001         1518 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
    2002              :             }
    2003              :             return true;
    2004              :         }
    2005              :     }
    2006        22873 :     const bool result = addStop(stop, errorMsg);
    2007        22873 :     if (result) {
    2008              :         /// XXX handle stops added out of order
    2009        22850 :         myParameter->stops.push_back(stop);
    2010              :     }
    2011              :     return result;
    2012              : }
    2013              : 
    2014              : 
    2015              : void
    2016          994 : MSBaseVehicle::unregisterWaiting() {
    2017          994 :     if (myAmRegisteredAsWaiting) {
    2018          975 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    2019          975 :         myAmRegisteredAsWaiting = false;
    2020              :     }
    2021          994 : }
    2022              : 
    2023              : 
    2024              : bool
    2025         1687 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
    2026         1687 :     if (hasStops() && nextStopIndex < (int)myStops.size()) {
    2027         1687 :         if (nextStopIndex == 0 && isStopped()) {
    2028          677 :             resumeFromStopping();
    2029              :         } else {
    2030              :             auto stopIt = myStops.begin();
    2031              :             std::advance(stopIt, nextStopIndex);
    2032         1010 :             if (stopIt->parkingarea != nullptr && stopIt->parkingarea->isReservable()) {
    2033            0 :                 stopIt->parkingarea->removeSpaceReservation(this);
    2034              :             }
    2035         1010 :             myStops.erase(stopIt);
    2036              :         }
    2037         1687 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2038              :             // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
    2039              :             auto stopIt2 = myParameter->stops.begin();
    2040              :             std::advance(stopIt2, nextStopIndex);
    2041            8 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
    2042              :         }
    2043         1687 :         return true;
    2044              :     } else {
    2045              :         return false;
    2046              :     }
    2047              : }
    2048              : 
    2049              : 
    2050              : bool
    2051          147 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2052          147 :     const int n = (int)myStops.size();
    2053          147 :     if (nextStopIndex < 0 || nextStopIndex >= n) {
    2054            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2055            5 :         return false;
    2056              :     }
    2057          142 :     if (nextStopIndex == 0 && isStopped()) {
    2058            7 :         errorMsg = TL("cannot replace reached stop");
    2059            7 :         return false;
    2060              :     }
    2061          135 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2062          135 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2063          135 :     MSEdge* stopEdge = &stopLane->getEdge();
    2064              : 
    2065              :     auto itStop = myStops.begin();
    2066              :     std::advance(itStop, nextStopIndex);
    2067              :     MSStop& replacedStop = *itStop;
    2068              : 
    2069              :     // check parking access rights
    2070          135 :     if (stop.parkingarea != "") {
    2071            0 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2072            0 :         if (pa != nullptr && !pa->accepts(this)) {
    2073            0 :             errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
    2074            0 :             return false;
    2075              :         }
    2076              :     }
    2077              : 
    2078          135 :     if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
    2079              :         // only replace stop attributes
    2080           10 :         const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2081           10 :         replacedStop.initPars(stop);
    2082           10 :         return true;
    2083              :     }
    2084              : 
    2085          125 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2086            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2087            0 :         return false;
    2088              :     }
    2089              : 
    2090          125 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2091          125 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2092          125 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2093          125 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2094          125 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2095          125 :     MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
    2096          125 :     auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
    2097          125 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2098              : 
    2099          125 :     bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
    2100              : 
    2101              :     ConstMSEdgeVector toNewStop;
    2102          125 :     if (!teleport) {
    2103           98 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2104           98 :         if (toNewStop.size() == 0) {
    2105           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2106            5 :             return false;
    2107              :         }
    2108              :     }
    2109              : 
    2110              :     ConstMSEdgeVector fromNewStop;
    2111          120 :     if (!newDestination) {
    2112          115 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2113          115 :         if (fromNewStop.size() == 0) {
    2114            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2115            0 :             return false;
    2116              :         }
    2117              :     }
    2118              : 
    2119          120 :     cleanupParkingReservation();
    2120          120 :     const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2121          120 :     replacedStop.initPars(stop);
    2122          120 :     replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
    2123          120 :     replacedStop.lane = stopLane;
    2124          120 :     if (MSGlobals::gUseMesoSim) {
    2125           21 :         replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
    2126           21 :         if (replacedStop.lane->isInternal()) {
    2127            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2128            0 :             return false;
    2129              :         }
    2130              :     }
    2131              : 
    2132          120 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2133              :     ConstMSEdgeVector newEdges; // only remaining
    2134          120 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2135          120 :     if (!teleport) {
    2136           93 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2137              :     } else {
    2138           27 :         newEdges.push_back(*itStart);
    2139              :     }
    2140          120 :     if (!newDestination) {
    2141          115 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2142          115 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2143              :     } else {
    2144            5 :         newEdges.push_back(stopEdge);
    2145              :     }
    2146              :     //std::cout << SIMTIME << " replaceStop veh=" << getID()
    2147              :     //    << " teleport=" << teleport
    2148              :     //    << " busStop=" << stop.busstop
    2149              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2150              :     //    << " newEdges=" << newEdges.size()
    2151              :     //    << " toNewStop=" << toNewStop.size()
    2152              :     //    << " fromNewStop=" << fromNewStop.size()
    2153              :     //    << "\n";
    2154              : 
    2155          120 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2156          120 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2157          120 :     const double savings = previousCost - routeCost;
    2158          120 :     if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2159              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2160            5 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
    2161              :     }
    2162          120 :     if (teleport) {
    2163              :         // let the vehicle jump rather than teleport
    2164              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2165              :         // already configure to jump before the replaced stop)
    2166           27 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2167              :             return false;
    2168              :         };
    2169              :     }
    2170          120 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2171          125 : }
    2172              : 
    2173              : 
    2174              : bool
    2175           52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
    2176           52 :     const int n = (int)myStops.size();
    2177           52 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2178            0 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2179            0 :         return false;
    2180              :     }
    2181           52 :     if (nextStopIndex == 0 && isStopped()) {
    2182            0 :         errorMsg = TL("cannot reroute towards reached stop");
    2183            0 :         return false;
    2184              :     }
    2185           52 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2186              : 
    2187           52 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2188           52 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2189           52 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2190           52 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2191           52 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2192           52 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2193           52 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2194           52 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2195              : 
    2196              :     ConstMSEdgeVector newBetween;
    2197           52 :     if (!teleport) {
    2198           15 :         router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
    2199           15 :         if (newBetween.size() == 0) {
    2200            0 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
    2201            0 :             return false;
    2202              :         }
    2203              :     }
    2204              : 
    2205           52 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2206              :     ConstMSEdgeVector newEdges; // only remaining
    2207           52 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2208           52 :     if (!teleport) {
    2209           15 :         newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
    2210              :     } else {
    2211           37 :         newEdges.push_back(*itStart);
    2212              :     }
    2213           52 :     newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2214              :     //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
    2215              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2216              :     //    << " newEdges=" << newEdges.size()
    2217              :     //    << " toNewStop=" << toNewStop.size()
    2218              :     //    << " fromNewStop=" << fromNewStop.size()
    2219              :     //    << "\n";
    2220              : 
    2221           52 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2222           52 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2223           52 :     const double savings = previousCost - routeCost;
    2224              : 
    2225           52 :     if (teleport) {
    2226              :         // let the vehicle jump rather than teleport
    2227              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2228              :         // already configure to jump before the replaced stop)
    2229           37 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2230              :             return false;
    2231              :         };
    2232              :     }
    2233           52 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2234           52 : }
    2235              : 
    2236              : 
    2237              : bool
    2238           64 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
    2239              :     bool needJump = true;
    2240           64 :     if (nextStopIndex > 0) {
    2241              :         auto itPriorStop = myStops.begin();
    2242           46 :         std::advance(itPriorStop, nextStopIndex - 1);
    2243              :         const MSStop& priorStop = *itPriorStop;
    2244           46 :         if (priorStop.pars.jump >= 0) {
    2245              :             needJump = false;
    2246              :         }
    2247              :     }
    2248              :     if (needJump) {
    2249           47 :         SUMOVehicleParameter::Stop jumpStopPars;
    2250           47 :         jumpStopPars.endPos = (*itStart)->getLength();
    2251           47 :         jumpStopPars.speed = 1000;
    2252           47 :         jumpStopPars.jump = 0;
    2253              :         jumpStopPars.edge = (*itStart)->getID();
    2254           47 :         jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
    2255              :         MSLane* jumpStopLane = nullptr;
    2256           47 :         for (MSLane* cand : (*itStart)->getLanes()) {
    2257           47 :             if (cand->allowsVehicleClass(getVClass())) {
    2258              :                 jumpStopLane = cand;
    2259              :                 break;
    2260              :             }
    2261              :         }
    2262           47 :         if (jumpStopLane == nullptr) {
    2263            0 :             errorMsg = TL("unable to replace stop with teleporting");
    2264              :             return false;
    2265              :         }
    2266              :         auto itStop = myStops.begin();
    2267              :         std::advance(itStop, nextStopIndex);
    2268           47 :         MSStop jumpStop(jumpStopPars);
    2269           47 :         jumpStop.initPars(jumpStopPars);
    2270           47 :         jumpStop.lane = jumpStopLane;
    2271           47 :         jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
    2272           47 :         myStops.insert(itStop, jumpStop);
    2273           47 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2274              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2275              :             auto it = myParameter->stops.begin() + nextStopIndex;
    2276            0 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
    2277              :         }
    2278           47 :     }
    2279              :     return true;
    2280              : }
    2281              : 
    2282              : 
    2283              : bool
    2284          873 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2285          873 :     const int n = (int)myStops.size();
    2286          873 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2287            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2288            5 :         return false;
    2289              :     }
    2290          868 :     if (nextStopIndex == 0 && isStopped()) {
    2291            6 :         errorMsg = TL("cannot insert stop before the currently reached stop");
    2292            6 :         return false;
    2293              :     }
    2294          862 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2295          862 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2296          862 :     MSEdge* stopEdge = &stopLane->getEdge();
    2297              : 
    2298          862 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2299            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2300            0 :         return false;
    2301              :     }
    2302              : 
    2303              :     // check parking access rights
    2304          862 :     if (stop.parkingarea != "") {
    2305          555 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2306          555 :         if (pa != nullptr && !pa->accepts(this)) {
    2307            0 :             errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
    2308            0 :             return false;
    2309              :         }
    2310              :     }
    2311              : 
    2312          862 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2313          862 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2314         1524 :     const int junctionOffset = ((getLane() != nullptr && getLane()->isInternal())
    2315         1520 :             || getRerouteOrigin() != getCurrentRouteEdge()) ? 1 : 0;
    2316          862 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2317          862 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2318          862 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2319          862 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2320          862 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2321              : 
    2322          862 :     const bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
    2323          862 :     const bool needLoop = nextStopIndex > 0 && *itStart == stopEdge && startPos >= stop.endPos;
    2324           93 :     if (needLoop && startPos == stop.endPos) {
    2325              :         // assume that two stops at the same position indicate a looped route
    2326           85 :         startPos += POSITION_EPS;
    2327           85 :         stop.index = STOP_INDEX_REPEAT;
    2328          777 :     } else if (!hasDeparted()) {
    2329           50 :         stop.index = STOP_INDEX_END;
    2330              :     }
    2331              : 
    2332              :     MSRouteIterator itSentintel = itEnd + 1;
    2333          862 :     MSRouteIterator onRouteStart = itStart + (needLoop ? 1 : 0);
    2334          862 :     const bool onRoute = std::find(onRouteStart, itSentintel, stopEdge) != itSentintel;
    2335          862 :     if (onRoute) {
    2336          364 :         if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2337              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2338              :             auto it = myParameter->stops.begin() + nextStopIndex;
    2339           20 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2340              :         }
    2341          364 :         const bool ok = addStop(stop, errorMsg, 0, &onRouteStart);
    2342          364 :         if (ok) {
    2343          362 :             updateBestLanes(true, !hasDeparted() ? (*myCurrEdge)->getLanes().front() : 0);
    2344              :         }
    2345          364 :         return ok;
    2346              :     }
    2347              : 
    2348              :     ConstMSEdgeVector toNewStop;
    2349          498 :     if (!teleport) {
    2350          470 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2351          470 :         if (toNewStop.size() == 0) {
    2352           12 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2353            4 :             return false;
    2354              :         }
    2355              :     }
    2356              : 
    2357              :     ConstMSEdgeVector fromNewStop;
    2358          494 :     if (!newDestination) {
    2359          444 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2360          444 :         if (fromNewStop.size() == 0) {
    2361            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2362            0 :             return false;
    2363              :         }
    2364              :     }
    2365              : 
    2366              :     auto itStop = myStops.begin();
    2367              :     std::advance(itStop, nextStopIndex);
    2368          494 :     MSStop newStop(stop);
    2369          494 :     newStop.initPars(stop);
    2370          494 :     newStop.edge = myRoute->end(); // will be patched in replaceRoute
    2371          494 :     newStop.lane = stopLane;
    2372          494 :     if (MSGlobals::gUseMesoSim) {
    2373          114 :         newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
    2374          114 :         if (newStop.lane->isInternal()) {
    2375            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2376            0 :             return false;
    2377              :         }
    2378              :     }
    2379          494 :     myStops.insert(itStop, newStop);
    2380              : 
    2381          494 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2382              :     ConstMSEdgeVector newEdges; // only remaining
    2383          494 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2384          494 :     if (!teleport) {
    2385          466 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2386              :     } else {
    2387           28 :         newEdges.push_back(*itStart);
    2388              :     }
    2389          494 :     if (!newDestination) {
    2390          444 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2391          444 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2392              :     } else {
    2393           50 :         newEdges.push_back(stopEdge);
    2394              :     }
    2395              :     //std::cout << SIMTIME << " insertStop veh=" << getID()
    2396              :     //    << " teleport=" << teleport
    2397              :     //    << " busStop=" << stop.busstop
    2398              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2399              :     //    << " newEdges=" << newEdges.size()
    2400              :     //    << " toNewStop=" << toNewStop.size()
    2401              :     //    << " fromNewStop=" << fromNewStop.size()
    2402              :     //    << "\n";
    2403              : 
    2404          494 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2405          494 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2406          494 :     const double savings = previousCost - routeCost;
    2407              : 
    2408          494 :     if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2409              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2410              :         auto it = myParameter->stops.begin() + nextStopIndex;
    2411           40 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2412              :     }
    2413          494 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2414         1356 : }
    2415              : 
    2416              : 
    2417              : EnergyParams*
    2418    106103285 : MSBaseVehicle::getEmissionParameters() const {
    2419    106103285 :     if (myEnergyParams == nullptr) {
    2420      1045268 :         myEnergyParams = new EnergyParams(getVehicleType().getEmissionParameters());
    2421              :         double tMass = 0;
    2422      1045268 :         if (myPersonDevice != nullptr) {
    2423           16 :             for (MSTransportable* t : myPersonDevice->getTransportables()) {
    2424           16 :                 tMass += t->getVehicleType().getMass();
    2425              :             }
    2426              :         }
    2427      1045268 :         if (myContainerDevice != nullptr) {
    2428            0 :             for (MSTransportable* t : myContainerDevice->getTransportables()) {
    2429            0 :                 tMass += t->getVehicleType().getMass();
    2430              :             }
    2431              :         }
    2432      1045268 :         myEnergyParams->setTransportableMass(tMass);
    2433              :     }
    2434    106103285 :     return myEnergyParams;
    2435              : }
    2436              : 
    2437              : 
    2438              : double
    2439            0 : MSBaseVehicle::getStateOfCharge() const {
    2440            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2441            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2442            0 :         return batteryOfVehicle->getActualBatteryCapacity();
    2443              :     } else {
    2444            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2445            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2446            0 :             return batteryOfVehicle->getActualBatteryCapacity();
    2447              :         }
    2448              :     }
    2449              :     return -1;
    2450              : }
    2451              : 
    2452              : 
    2453              : double
    2454            0 : MSBaseVehicle::getRelativeStateOfCharge() const {
    2455            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2456            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2457            0 :         return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2458              :     } else {
    2459            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2460            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2461            0 :             return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2462              :         }
    2463              :     }
    2464              :     return -1;
    2465              : }
    2466              : 
    2467              : 
    2468              : double
    2469            0 : MSBaseVehicle::getChargedEnergy() const {
    2470            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2471            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2472            0 :         return batteryOfVehicle->getEnergyCharged();
    2473              :     } else {
    2474            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2475            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2476            0 :             return batteryOfVehicle->getEnergyCharged();
    2477              :         }
    2478              :     }
    2479              :     return -1;
    2480              : }
    2481              : 
    2482              : 
    2483              : double
    2484            0 : MSBaseVehicle::getMaxChargeRate() const {
    2485            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2486            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2487            0 :         return batteryOfVehicle->getMaximumChargeRate();
    2488              :     }
    2489              :     return -1;
    2490              : }
    2491              : 
    2492              : 
    2493              : double
    2494            0 : MSBaseVehicle::getElecHybridCurrent() const {
    2495            0 :     if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2496            0 :         MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2497            0 :         return elecHybridDevice->getCurrentFromOverheadWire();
    2498              :     }
    2499              : 
    2500              :     return NAN;
    2501              : }
    2502              : 
    2503              : double
    2504          762 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
    2505          762 :     if (isOnRoad() || isIdling()) {
    2506          762 :         return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
    2507              :     } else {
    2508              :         return 0.;
    2509              :     }
    2510              : }
    2511              : 
    2512              : 
    2513              : const MSEdgeWeightsStorage&
    2514      6711167 : MSBaseVehicle::getWeightsStorage() const {
    2515      6711167 :     return _getWeightsStorage();
    2516              : }
    2517              : 
    2518              : 
    2519              : MSEdgeWeightsStorage&
    2520          666 : MSBaseVehicle::getWeightsStorage() {
    2521          666 :     return _getWeightsStorage();
    2522              : }
    2523              : 
    2524              : 
    2525              : MSEdgeWeightsStorage&
    2526      6711833 : MSBaseVehicle::_getWeightsStorage() const {
    2527      6711833 :     if (myEdgeWeights == nullptr) {
    2528        13931 :         myEdgeWeights = new MSEdgeWeightsStorage();
    2529              :     }
    2530      6711833 :     return *myEdgeWeights;
    2531              : }
    2532              : 
    2533              : 
    2534              : 
    2535              : 
    2536              : int
    2537     12300875 : MSBaseVehicle::getPersonNumber() const {
    2538     12300875 :     int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
    2539     12300875 :     return boarded + myParameter->personNumber;
    2540              : }
    2541              : 
    2542              : int
    2543            0 : MSBaseVehicle::getLeavingPersonNumber() const {
    2544              :     int leavingPersonNumber = 0;
    2545            0 :     const std::vector<MSTransportable*>& persons = getPersons();
    2546            0 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2547            0 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
    2548              :         const MSStop* stop = &myStops.front();
    2549            0 :         const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
    2550            0 :         if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
    2551            0 :             leavingPersonNumber++;
    2552              :         }
    2553              :     }
    2554            0 :     return leavingPersonNumber;
    2555              : }
    2556              : 
    2557              : std::vector<std::string>
    2558          194 : MSBaseVehicle::getPersonIDList() const {
    2559              :     std::vector<std::string> ret;
    2560          194 :     const std::vector<MSTransportable*>& persons = getPersons();
    2561          669 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2562          475 :         ret.push_back((*it_p)->getID());
    2563              :     }
    2564          194 :     return ret;
    2565            0 : }
    2566              : 
    2567              : int
    2568     12353189 : MSBaseVehicle::getContainerNumber() const {
    2569     12353189 :     int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
    2570     12353189 :     return loaded + myParameter->containerNumber;
    2571              : }
    2572              : 
    2573              : 
    2574              : void
    2575          171 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
    2576              :     // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
    2577          171 :     if (myPersonDevice != nullptr) {
    2578          151 :         myPersonDevice->removeTransportable(t);
    2579              :     }
    2580          171 :     if (myContainerDevice != nullptr) {
    2581           20 :         myContainerDevice->removeTransportable(t);
    2582              :     }
    2583          171 :     if (myEnergyParams != nullptr) {
    2584           88 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2585              :     }
    2586          171 : }
    2587              : 
    2588              : 
    2589              : void
    2590         9785 : MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
    2591         9785 :     if (myEnergyParams != nullptr) {
    2592         6034 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2593              :     }
    2594         9785 : }
    2595              : 
    2596              : 
    2597              : const std::vector<MSTransportable*>&
    2598      9732956 : MSBaseVehicle::getPersons() const {
    2599      9732956 :     if (myPersonDevice == nullptr) {
    2600              :         return myEmptyTransportableVector;
    2601              :     } else {
    2602        13692 :         return myPersonDevice->getTransportables();
    2603              :     }
    2604              : }
    2605              : 
    2606              : 
    2607              : const std::vector<MSTransportable*>&
    2608      8479760 : MSBaseVehicle::getContainers() const {
    2609      8479760 :     if (myContainerDevice == nullptr) {
    2610              :         return myEmptyTransportableVector;
    2611              :     } else {
    2612         3372 :         return myContainerDevice->getTransportables();
    2613              :     }
    2614              : }
    2615              : 
    2616              : 
    2617              : bool
    2618          213 : MSBaseVehicle::isLineStop(double position) const {
    2619          213 :     if (myParameter->line == "") {
    2620              :         // not a public transport line
    2621              :         return false;
    2622              :     }
    2623          367 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    2624          218 :         if (stop.startPos <= position && position <= stop.endPos) {
    2625              :             return true;
    2626              :         }
    2627              :     }
    2628          176 :     for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    2629           38 :         if (stop.startPos <= position && position <= stop.endPos) {
    2630              :             return true;
    2631              :         }
    2632              :     }
    2633              :     return false;
    2634              : }
    2635              : 
    2636              : 
    2637              : bool
    2638           45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
    2639          144 :     for (MSDevice* const dev : myDevices) {
    2640          126 :         if (dev->deviceName() == deviceName) {
    2641              :             return true;
    2642              :         }
    2643              :     }
    2644              :     return false;
    2645              : }
    2646              : 
    2647              : 
    2648              : void
    2649            9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
    2650            9 :     if (!hasDevice(deviceName)) {
    2651            9 :         if (deviceName == "rerouting") {
    2652           27 :             ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
    2653            9 :             MSDevice_Routing::buildVehicleDevices(*this, myDevices);
    2654            9 :             if (hasDeparted()) {
    2655              :                 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
    2656            0 :                 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
    2657              :                 assert(routingDevice != 0);
    2658            0 :                 routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
    2659              :             }
    2660              :         } else {
    2661            0 :             throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
    2662              :         }
    2663              :     }
    2664            9 : }
    2665              : 
    2666              : 
    2667              : std::string
    2668        49789 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
    2669        58785 :     for (MSVehicleDevice* const dev : myDevices) {
    2670        58776 :         if (dev->deviceName() == deviceName) {
    2671        49780 :             return dev->getParameter(key);
    2672              :         }
    2673              :     }
    2674           27 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2675              : }
    2676              : 
    2677              : 
    2678              : void
    2679          208 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
    2680          355 :     for (MSVehicleDevice* const dev : myDevices) {
    2681          355 :         if (dev->deviceName() == deviceName) {
    2682          208 :             dev->setParameter(key, value);
    2683          208 :             return;
    2684              :         }
    2685              :     }
    2686            0 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2687              : }
    2688              : 
    2689              : 
    2690              : void
    2691          842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
    2692         1669 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
    2693          837 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
    2694          837 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2695              :         // checked in MSLink::ignoreFoe
    2696              :     } else {
    2697           15 :         throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
    2698              :     }
    2699          837 : }
    2700              : 
    2701              : 
    2702              : void
    2703           33 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
    2704              :     // handle some generic params first and then delegate to the carFollowModel itself
    2705           57 :     if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
    2706           17 :         getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
    2707           17 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2708              :         // checked in MSVehicle::planMove
    2709              :     } else {
    2710           16 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
    2711           16 :         if (microVeh) {
    2712              :             // remove 'carFollowModel.' prefix
    2713           16 :             const std::string attrName = key.substr(15);
    2714           16 :             microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
    2715              :         }
    2716              :     }
    2717           29 : }
    2718              : 
    2719              : 
    2720              : void
    2721      5232272 : MSBaseVehicle::initTransientModelParams() {
    2722              :     /* Design idea for additional junction model parameters:
    2723              :        We can distinguish between 3 levels of parameters
    2724              :        1. typically shared by multiple vehicles -> vType parameter
    2725              :        2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
    2726              :        3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
    2727              :        */
    2728      5409188 :     for (auto item : getParameter().getParametersMap()) {
    2729       353832 :         if (StringUtils::startsWith(item.first, "junctionModel.")) {
    2730          832 :             setJunctionModelParameter(item.first, item.second);
    2731       352168 :         } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
    2732           17 :             setCarFollowModelParameter(item.first, item.second);
    2733              :         }
    2734              :     }
    2735     10464544 :     const std::string routingModeStr = getStringParam("device.rerouting.mode");
    2736              :     try {
    2737      5232272 :         int routingMode = StringUtils::toInt(routingModeStr);
    2738      5232272 :         if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
    2739              :             setRoutingMode(routingMode);
    2740          256 :             if ((routingMode & (libsumo::ROUTING_MODE_AGGREGATED | libsumo::ROUTING_MODE_AGGREGATED_CUSTOM)) != 0) {
    2741              :                 // vehicles wishes to use traffic-dependent routing weights on triggere rerouting
    2742              :                 // (initWeightUpdate would be triggered anyway when equipped with device.rerouting)
    2743           56 :                 MSRoutingEngine::initWeightUpdate();
    2744           56 :                 MSRoutingEngine::initEdgeWeights(getVClass());
    2745              :             }
    2746              :         }
    2747            0 :     } catch (NumberFormatException&) {
    2748              :         // @todo interpret symbolic constants
    2749            0 :         throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
    2750            0 :     }
    2751      5232272 : }
    2752              : 
    2753              : 
    2754              : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
    2755        23075 : MSBaseVehicle::getRouterTT() const {
    2756        23075 :     if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
    2757          204 :         return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
    2758              :     } else {
    2759        45946 :         return MSNet::getInstance()->getRouterTT(getRNGIndex());
    2760              :     }
    2761              : }
    2762              : 
    2763              : 
    2764              : void
    2765        30683 : MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
    2766              :     assert(type != nullptr);
    2767              :     // save old parameters before possible type deletion
    2768        30683 :     const double oldMu = myType->getSpeedFactor().getParameter(0);
    2769              :     const double oldDev = myType->getSpeedFactor().getParameter(1);
    2770        30683 :     if (myType->isVehicleSpecific() && type != myType) {
    2771          942 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    2772              :     }
    2773              :     // adapt myChosenSpeedFactor to the new type
    2774        30683 :     if (oldDev == 0.) {
    2775              :         // old type had speedDev 0, reroll
    2776        22817 :         myChosenSpeedFactor = type->computeChosenSpeedDeviation(getParameter().speedFactor, getRNG());
    2777              :     } else {
    2778              :         // map old speedFactor onto new distribution
    2779         7866 :         const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
    2780              :         const double newMu = type->getSpeedFactor().getParameter(0);
    2781              :         const double newDev = type->getSpeedFactor().getParameter(1);
    2782         7866 :         myChosenSpeedFactor = newMu + distPoint * newDev;
    2783              :         // respect distribution limits
    2784         7866 :         myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
    2785         7871 :         myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
    2786              :     }
    2787        30683 :     myType = type;
    2788        30683 :     if (myEnergyParams != nullptr) {
    2789              :         myEnergyParams->setSecondary(type->getEmissionParameters());
    2790              :     }
    2791        30683 : }
    2792              : 
    2793              : 
    2794              : MSVehicleType&
    2795       145238 : MSBaseVehicle::getSingularType() {
    2796       145238 :     if (myType->isVehicleSpecific()) {
    2797              :         return *const_cast<MSVehicleType*>(myType);
    2798              :     }
    2799         2540 :     MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
    2800         1270 :     replaceVehicleType(type);
    2801         1270 :     return *type;
    2802              : }
    2803              : 
    2804              : 
    2805              : int
    2806       727608 : MSBaseVehicle::getRNGIndex() const {
    2807       727608 :     const MSLane* const lane = getLane();
    2808       727608 :     if (lane == nullptr) {
    2809        20886 :         return getEdge()->getLanes()[0]->getRNGIndex();
    2810              :     } else {
    2811       706722 :         return lane->getRNGIndex();
    2812              :     }
    2813              : }
    2814              : 
    2815              : 
    2816              : SumoRNG*
    2817    746744767 : MSBaseVehicle::getRNG() const {
    2818    746744767 :     const MSLane* lane = getLane();
    2819    746744767 :     if (lane == nullptr) {
    2820         6522 :         return getEdge()->getLanes()[0]->getRNG();
    2821              :     } else {
    2822    746738245 :         return lane->getRNG();
    2823              :     }
    2824              : }
    2825              : 
    2826              : std::string
    2827        68715 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
    2828        68715 :     const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
    2829       137430 :     if (StringUtils::startsWith(key, "device.")) {
    2830       149367 :         StringTokenizer tok(key, ".");
    2831        49789 :         if (tok.size() < 3) {
    2832            0 :             error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
    2833            0 :             return "";
    2834              :         }
    2835              :         try {
    2836       149367 :             return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
    2837           18 :         } catch (InvalidArgument& e) {
    2838           54 :             error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
    2839           18 :             return "";
    2840           18 :         }
    2841        87641 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2842          322 :         if (microVeh == nullptr) {
    2843           40 :             error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
    2844           20 :             return "";
    2845              :         }
    2846          302 :         const std::string attrName = key.substr(16);
    2847              :         try {
    2848          302 :             return microVeh->getLaneChangeModel().getParameter(attrName);
    2849           42 :         } catch (InvalidArgument& e) {
    2850          126 :             error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
    2851           42 :             return "";
    2852           42 :         }
    2853        37208 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2854           12 :         if (microVeh == nullptr) {
    2855            0 :             error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
    2856            0 :             return "";
    2857              :         }
    2858           12 :         const std::string attrName = key.substr(15);
    2859              :         try {
    2860           12 :             return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
    2861            0 :         } catch (InvalidArgument& e) {
    2862            0 :             error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
    2863            0 :             return "";
    2864            0 :         }
    2865        18628 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2866          108 :         StringTokenizer tok(key, ".");
    2867           36 :         if (tok.size() != 3) {
    2868            0 :             error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
    2869            0 :             return "";
    2870              :         }
    2871           81 :         return hasDevice(tok.get(1)) ? "true" : "false";
    2872              :         // parking related parameters start here
    2873        18592 :     } else if (key == "parking.rerouteCount") {
    2874           15 :         return toString(getNumberParkingReroutes());
    2875        37082 :     } else if (StringUtils::startsWith(key, "parking.memory.")) {
    2876              :         std::vector<std::string> values;
    2877           65 :         if (getParkingMemory()) {
    2878           20 :             if (key == "parking.memory.IDList") {
    2879           24 :                 for (const auto& item : *getParkingMemory()) {
    2880           20 :                     values.push_back(item.first->getID());
    2881              :                 }
    2882           16 :             } else if (key == "parking.memory.score") {
    2883           24 :                 for (const auto& item : *getParkingMemory()) {
    2884           20 :                     values.push_back(item.second.score);
    2885              :                 }
    2886           12 :             } else if (key == "parking.memory.blockedAtTime") {
    2887           24 :                 for (const auto& item : *getParkingMemory()) {
    2888           40 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
    2889              :                 }
    2890            8 :             } else if (key == "parking.memory.blockedAtTimeLocal") {
    2891           24 :                 for (const auto& item : *getParkingMemory()) {
    2892           40 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
    2893              :                 }
    2894              :             } else {
    2895            8 :                 error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
    2896              :             }
    2897              :         }
    2898           65 :         return toString(values);
    2899           65 :     } else {
    2900              :         // default: custom user parameter
    2901        36952 :         return getParameter().getParameter(key, "");
    2902              :     }
    2903              : }
    2904              : 
    2905              : 
    2906              : void
    2907        89299 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
    2908        89299 :     if (myParkingMemory == nullptr) {
    2909            0 :         myParkingMemory = new StoppingPlaceMemory();
    2910              :     }
    2911        89299 :     myParkingMemory->rememberBlockedStoppingPlace(pa, local);
    2912        89299 : }
    2913              : 
    2914              : 
    2915              : void
    2916        29700 : MSBaseVehicle::resetParkingAreaScores() {
    2917        29700 :     if (myParkingMemory != nullptr) {
    2918        27868 :         myParkingMemory->resetStoppingPlaceScores();
    2919              :     }
    2920        29700 : }
    2921              : 
    2922              : 
    2923              : void
    2924          360 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
    2925          360 :     if (myChargingMemory == nullptr) {
    2926           80 :         myChargingMemory = new StoppingPlaceMemory();
    2927              :     }
    2928          360 :     myChargingMemory->rememberStoppingPlaceScore(cs, score);
    2929          360 : }
    2930              : 
    2931              : 
    2932              : void
    2933          127 : MSBaseVehicle::resetChargingStationScores() {
    2934          127 :     if (myChargingMemory != nullptr) {
    2935           11 :         myChargingMemory->resetStoppingPlaceScores();
    2936              :     }
    2937          127 : }
    2938              : 
    2939              : 
    2940              : void
    2941       131888 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
    2942       131888 :     if (myParkingMemory == nullptr) {
    2943         2340 :         myParkingMemory = new StoppingPlaceMemory();
    2944              :     }
    2945       131888 :     myParkingMemory->rememberStoppingPlaceScore(pa, score);
    2946       131888 : }
    2947              : 
    2948              : 
    2949              : SUMOTime
    2950        71648 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
    2951        71648 :     if (myParkingMemory == nullptr) {
    2952              :         return -1;
    2953              :     }
    2954        71624 :     return myParkingMemory->sawBlockedStoppingPlace(pa, local);
    2955              : }
    2956              : 
    2957              : 
    2958            0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
    2959            0 :     if (myChargingMemory == nullptr) {
    2960            0 :         myChargingMemory = new StoppingPlaceMemory();
    2961              :     }
    2962            0 :     myChargingMemory->rememberBlockedStoppingPlace(cs, local);
    2963            0 : }
    2964              : 
    2965              : 
    2966              : SUMOTime
    2967          548 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
    2968          548 :     if (myChargingMemory == nullptr) {
    2969              :         return -1;
    2970              :     }
    2971           72 :     return myChargingMemory->sawBlockedStoppingPlace(cs, local);
    2972              : }
    2973              : 
    2974              : 
    2975              : void
    2976      4487947 : MSBaseVehicle::cleanupParkingReservation() {
    2977      4487947 :     if (hasStops() && myStops.front().parkingarea != nullptr && myStops.front().parkingarea->isReservable()) {
    2978            0 :         myStops.front().parkingarea->removeSpaceReservation(this);
    2979              :     }
    2980      4487947 : }
    2981              : 
    2982              : 
    2983              : #ifdef _DEBUG
    2984              : void
    2985              : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
    2986              :     if (oc.isSet("movereminder-output.vehicles")) {
    2987              :         const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
    2988              :         myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
    2989              :     }
    2990              : }
    2991              : 
    2992              : 
    2993              : void
    2994              : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
    2995              :     OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
    2996              :     od.openTag("movereminder");
    2997              :     od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
    2998              :     od.writeAttr("veh", getID());
    2999              :     od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
    3000              :     od.writeAttr("type", type);
    3001              :     od.writeAttr("pos", toString(pos));
    3002              :     od.writeAttr("keep", toString(keep));
    3003              :     od.closeTag();
    3004              : }
    3005              : #endif
    3006              : 
    3007              : 
    3008              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1