LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.5 % 1386 1240
Test Date: 2026-03-02 16:00:03 Functions: 89.4 % 123 110

            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         3570 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
      90         3570 : {}
      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      5537930 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
     103      5537930 :                              MSVehicleType* type, const double speedFactor) :
     104              :     SUMOVehicle(pars->id),
     105      5537930 :     myParameter(pars),
     106              :     myRoute(route),
     107      5537930 :     myType(type),
     108      5537930 :     myCurrEdge(route->begin()),
     109      5549590 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     110      5537930 :     myMoveReminders(0),
     111      5537930 :     myPersonDevice(nullptr),
     112      5537930 :     myContainerDevice(nullptr),
     113      5537930 :     myEnergyParams(nullptr),
     114      5537930 :     myDeparture(NOT_YET_DEPARTED),
     115      5537930 :     myDepartPos(-1),
     116      5537930 :     myArrivalPos(-1),
     117      5537930 :     myArrivalLane(-1),
     118      5537930 :     myNumberReroutes(0),
     119      5537930 :     myStopUntilOffset(0),
     120      5537930 :     myOdometer(0.),
     121      5537930 :     myRouteValidity(ROUTE_UNCHECKED),
     122      5537930 :     myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
     123      5537930 :     myNumericalID(myCurrentNumericalIndex++),
     124     11075860 :     myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
     125     11075860 :     myEdgeWeights(nullptr)
     126              : #ifdef _DEBUG
     127              :     , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
     128              : #endif
     129              : {
     130      5537930 :     if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
     131       577706 :         pars->parametersSet |= VEHPARS_FORCE_REROUTE;
     132              :     }
     133      5537930 :     if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
     134      3986299 :         setDepartAndArrivalEdge();
     135              :     }
     136      5537930 :     calculateArrivalParams(true);
     137      5537930 :     initTransientModelParams();
     138      5537930 : }
     139              : 
     140              : 
     141      5537832 : MSBaseVehicle::~MSBaseVehicle() {
     142      5537832 :     delete myEdgeWeights;
     143      5537832 :     if (myParameter->repetitionNumber == -1) {
     144              :         // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
     145       459697 :         MSRoute::checkDist(myParameter->routeid);
     146              :     }
     147      9684842 :     for (MSVehicleDevice* dev : myDevices) {
     148      4147010 :         delete dev;
     149              :     }
     150      5537832 :     delete myEnergyParams;
     151      5537832 :     delete myParkingMemory;
     152      5537832 :     delete myChargingMemory;
     153      5537832 :     checkRouteRemoval();
     154      5537832 :     delete myParameter;
     155      5537832 : }
     156              : 
     157              : 
     158              : void
     159     15196340 : 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     15196338 :     if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
     163       826798 :         myRoute->checkRemoval();
     164              :     }
     165      7598170 : }
     166              : 
     167              : 
     168              : std::string
     169      7598168 : MSBaseVehicle::getFlowID() const {
     170      7598168 :     return getID().substr(0, getID().rfind('.'));
     171              : }
     172              : 
     173              : 
     174              : void
     175      5537930 : MSBaseVehicle::initDevices() {
     176      5537930 :     MSDevice::buildVehicleDevices(*this, myDevices);
     177      9679924 :     for (MSVehicleDevice* dev : myDevices) {
     178      4142011 :         myMoveReminders.push_back(std::make_pair(dev, 0.));
     179              :     }
     180      5537913 :     if (MSGlobals::gHaveEmissions) {
     181              :         // ensure we have the emission parameters even if we don't have the device
     182      1061783 :         getEmissionParameters();
     183              :     }
     184      5537913 : }
     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  39175852183 : MSBaseVehicle::getParameter() const {
     194  39175852183 :     return *myParameter;
     195              : }
     196              : 
     197              : 
     198              : void
     199           55 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
     200           55 :     delete myParameter;
     201           55 :     myParameter = newParameter;
     202           55 : }
     203              : 
     204              : 
     205              : bool
     206   7687862163 : MSBaseVehicle::ignoreTransientPermissions() const {
     207   7687862163 :     return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
     208              : }
     209              : 
     210              : double
     211   6152196552 : MSBaseVehicle::getMaxSpeed() const {
     212   6152196552 :     return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
     213              : }
     214              : 
     215              : 
     216              : const MSEdge*
     217   2147158278 : MSBaseVehicle::succEdge(int nSuccs) const {
     218   2147158278 :     if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
     219   1525660170 :         return *(myCurrEdge + nSuccs);
     220              :     } else {
     221    621498108 :         return nullptr;
     222              :     }
     223              : }
     224              : 
     225              : 
     226              : const MSEdge*
     227   7817410944 : MSBaseVehicle::getEdge() const {
     228   7817410944 :     return *myCurrEdge;
     229              : }
     230              : 
     231              : 
     232              : const std::set<SUMOTrafficObject::NumericalID>
     233        69549 : MSBaseVehicle::getUpcomingEdgeIDs() const {
     234              :     std::set<SUMOTrafficObject::NumericalID> result;
     235       314405 :     for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
     236       244856 :         result.insert((*e)->getNumericalID());
     237              :     }
     238        69549 :     return result;
     239              : }
     240              : 
     241              : 
     242              : bool
     243      4429629 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
     244      4429629 :     if (stop == nullptr) {
     245              :         return false;
     246              :     }
     247      8820945 :     for (const MSStop& s : myStops) {
     248      8819160 :         if (s.busstop == stop
     249      8780341 :                 || s.containerstop == stop
     250      4391332 :                 || s.parkingarea == stop
     251      4391326 :                 || s.chargingStation == stop) {
     252              :             return true;
     253              :         }
     254              :     }
     255              :     return false;
     256              : }
     257              : 
     258              : bool
     259       189015 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
     260       398428 :     for (const MSStop& s : myStops) {
     261       368166 :         if (&s.lane->getEdge() == edge) {
     262              :             return true;
     263              :         }
     264              :     }
     265        30262 :     return myRoute->getLastEdge() == edge;
     266              : }
     267              : 
     268              : 
     269              : bool
     270      3129118 : 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      3129118 :     const MSEdge* source = nullptr;
     273      3129118 :     if (onInit) {
     274      2947392 :         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      2946863 :             source = myRoute->getEdges().front();
     281              :         }
     282              :     } else {
     283       181726 :         source = *getRerouteOrigin();
     284              :     }
     285      3129118 :     if (sink == nullptr) {
     286      3103546 :         sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
     287      3103546 :         if (sink == nullptr) {
     288            5 :             sink = myRoute->getLastEdge();
     289              :         }
     290              :     }
     291      3137484 :     ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
     292              :     ConstMSEdgeVector edges;
     293      3129118 :     if (source != sink || !sink->prohibits(this)) {
     294      3129112 :         edges.push_back(source);
     295              :     }
     296              :     std::vector<StopEdgeInfo> stops;
     297              :     std::set<int> jumps;
     298              : 
     299              : 
     300      3129118 :     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      2947392 :     if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
     307        87059 :         sourcePos = myParameter->departPos;
     308      3042059 :     } else if (getLane() != nullptr && source != &getLane()->getEdge()) {
     309              :         // routing starts on the next edge
     310              :         sourcePos = 0;
     311              :     }
     312      3129118 :     if (myParameter->via.size() == 0) {
     313      3118591 :         double firstPos = INVALID_DOUBLE;
     314      3118591 :         double lastPos = INVALID_DOUBLE;
     315      3118591 :         stops = getStopEdges(firstPos, lastPos, jumps);
     316      3118591 :         if (stops.size() > 0) {
     317        39467 :             if (MSGlobals::gUseMesoSim && isStopped()) {
     318          300 :                 sourcePos = getNextStop().pars.endPos;
     319              :             }
     320        39467 :             if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
     321        36678 :                 sourcePos += getBrakeGap();
     322              :             }
     323              :             // avoid superfluous waypoints for first and last edge
     324        39467 :             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        39467 :             if (stops.size() == 1 && skipFirst) {
     333              :                 stops.clear();
     334        32173 :             } else if (skipFirst) {
     335         8151 :                 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        26810 :         for (const MSStop& stop : myStops) {
     343        16283 :             if (stop.pars.jump >= 0) {
     344              :                 jumpEdges.insert(*stop.edge);
     345              :             }
     346              :             auto itsov = stopsOnVia.find(*stop.edge);
     347        16283 :             if (itsov == stopsOnVia.end()) {
     348        30856 :                 stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
     349              :             } else {
     350          855 :                 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        33637 :         for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
     356        23118 :             MSEdge* viaEdge = MSEdge::dictionary(*it);
     357        23118 :             if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
     358              :                 continue;
     359              :             }
     360              :             assert(viaEdge != 0);
     361        19022 :             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        19014 :             const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
     366        19014 :             const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
     367        19014 :             const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
     368        19014 :             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      3090404 :     if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
     376      3190816 :             || ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
     377      6092950 :         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      3129110 :     const MSEdge* origSource = source;
     393     15645550 :     const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
     394      6263634 :     for (auto& stopEdgeInfo : stops) {
     395      3134529 :         const MSEdge* const stopEdge = stopEdgeInfo.edge;
     396      3134529 :         const double priority = stopEdgeInfo.priority;
     397      3134529 :         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      3135503 :         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      3133344 :         if (into.size() > 0) {
     412      3219086 :             while (stopIt != myStops.end() && stopIt->pars.edge != stopEdge->getID()) {
     413              :                 stopIt++;
     414              :             }
     415              : 
     416      3132535 :             startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
     417      3132535 :             if (stopIt != myStops.end()) {
     418        79692 :                 if (stopIt->pars.priority >= 0 && info != "device.rerouting") {
     419              :                     // consider skipping this stop if it cannot be reached in a timely manner
     420              :                     if (stopIt != myStops.end()) {
     421          189 :                         SUMOTime arrival = stopEdgeInfo.arrival;
     422          189 :                         if (arrival > 0) {
     423           42 :                             SUMOTime delay = startTime - arrival;
     424              :                             //std::cout << " t=" << time2string(t) << " veh=" << getID() << " info=" << info << " stopIndex=" << stopIndex
     425              :                             //   << " into=" << toString(into) << " sourcePos=" << sourcePos << " stopPos=" << stopPos
     426              :                             //   << " startTime=" << time2string(startTime) << " arrival=" << time2string(arrival) << " delay=" << time2string(delay) << "\n";
     427           42 :                             if (delay > 0) {
     428           24 :                                 if (delay > maxDelay) {
     429            9 :                                     stopEdgeInfo.skipped = true;
     430            9 :                                     stopEdgeInfo.delay = delay;
     431              :                                     hasSkipped = true;
     432            9 :                                     continue;
     433              :                                 }
     434              :                             }
     435              :                         }
     436              :                     }
     437              :                 }
     438        79683 :                 sourcePos = stopEdgeInfo.pos;
     439        79683 :                 startTime += stopIt->getMinDuration(startTime);
     440              :             }
     441              :             edges.pop_back();
     442      3132526 :             edges.insert(edges.end(), into.begin(), into.end());
     443      3132526 :             if (edges.back()->isTazConnector()) {
     444              :                 edges.pop_back();
     445              :             }
     446      3132526 :             source = edges.back();
     447      3132526 :             stopEdgeInfo.routeIndex = (int)edges.size() - 1;
     448              :         } else {
     449          809 :             if (priority >= 0) {
     450           53 :                 stopEdgeInfo.skipped = true;
     451              :                 hasSkipped = true;
     452           53 :                 continue;
     453          756 :             } else if (stopEdgeInfo.isSink) {
     454              :                 //error = TLF("Vehicle '%' has no valid route from edge '%' to destination edge '%'.", getID(), source->getID(), stopEdge->getID());
     455              :                 edges.clear();
     456          733 :                 if (onInit && source == stopEdge && stops.size() == 1 && sourcePos > myArrivalPos) {
     457           52 :                     edges.push_back(stopEdge);
     458          208 :                     WRITE_WARNING(TLF("Vehicle '%' ignores arrivalPos % when driving from edge '%' to edge '%'.", getID(), myArrivalPos, source->getID(), stopEdge->getID()));
     459              :                 }
     460           23 :             } else if (source == stopEdge && stopEdgeInfo.stopPar != nullptr && stopEdgeInfo.stopPar->endPos >= sourcePos) {
     461              :                 // special case: no failure on dynamically computed stop position
     462              :                 edges.clear();
     463              :             } else {
     464           14 :                 std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
     465            7 :                 if (MSGlobals::gCheckRoutes || silent) {
     466            5 :                     throw ProcessError(error);
     467              :                 } else {
     468            9 :                     WRITE_WARNING(error);
     469            2 :                     edges.push_back(source);
     470            2 :                     source = stopEdge;
     471              :                 }
     472              :             }
     473              :         }
     474      3134529 :     }
     475      3129105 :     if (hasSkipped) {
     476              :         MSStopOptimizer opti(this, router, t, maxDelay);
     477          180 :         edges = opti.optimizeSkipped(origSource, origSourcePos, stops, edges);
     478          316 :         for (auto stop : stops) {
     479          261 :             if (stop.skipped || stop.origEdge != nullptr) {
     480           62 :                 const MSEdge* origEdge = stop.origEdge == nullptr ? stop.edge : stop.origEdge;
     481           62 :                 if (stop.delay > 0) {
     482           27 :                     WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with delay % at time %.", getID(), origEdge->getID(), time2string(stop.delay), time2string(SIMSTEP)));
     483           53 :                 } else if (stop.backtracked) {
     484            9 :                     WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
     485              :                 } else {
     486          150 :                     WRITE_WARNING(TLF("Vehicle '%' skips unreachable stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
     487              :                 }
     488              :             }
     489              :         }
     490              :     }
     491              : 
     492              :     // router.setHint(myCurrEdge, myRoute->end(), this, t);
     493      3129105 :     if (edges.empty() && silent) {
     494              :         return false;
     495              :     }
     496      3128981 :     if (!edges.empty() && edges.front()->isTazConnector()) {
     497              :         edges.erase(edges.begin());
     498              :     }
     499      3128981 :     if (!edges.empty() && edges.back()->isTazConnector()) {
     500              :         edges.pop_back();
     501              :     }
     502      3128981 :     const double routeCost = router.recomputeCosts(edges, this, t);
     503      3128981 :     const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
     504      3128981 :     const double savings = previousCost - routeCost;
     505      3128981 :     bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
     506              :     if (!savingsOk) {
     507       153241 :         MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
     508              :         assert(routingDevice != 0);
     509       153241 :         savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
     510       153241 :         if (!savingsOk) {
     511              :             std::string dummyMsg;
     512       141420 :             if (!hasValidRoute(dummyMsg, oldEdgesRemaining.begin(), oldEdgesRemaining.end(), true)) {
     513              :                 // the old route is prohibted (i.e. due to temporary permission changes)
     514              :                 savingsOk = true;
     515              :             }
     516              :         }
     517              :     }
     518              :     //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     519              :     //    << " onInit=" << onInit
     520              :     //        << " prevEdges=" << toString(oldEdgesRemaining)
     521              :     //        << " newEdges=" << toString(edges)
     522              :     //        << "\n";
     523       141420 :     if (savingsOk) {
     524      2987568 :         replaceRouteEdges(edges, routeCost, savings, info, onInit);
     525              :     }
     526              :     // this must be called even if the route could not be replaced
     527      3128981 :     if (onInit) {
     528      2947384 :         if (edges.empty()) {
     529          189 :             if (MSGlobals::gCheckRoutes) {
     530          336 :                 throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
     531           77 :             } else if (source->isTazConnector()) {
     532          206 :                 WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
     533           27 :                 MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
     534              :                 return false;
     535              :             }
     536              :         }
     537      2947245 :         setDepartAndArrivalEdge();
     538      2947245 :         calculateArrivalParams(onInit);
     539              :     }
     540      3128842 :     return !edges.empty();
     541      3129368 : }
     542              : 
     543              : 
     544              : bool
     545      3039038 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
     546      3039038 :     if (edges.empty()) {
     547         1737 :         WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
     548          579 :         if (msgReturn != nullptr) {
     549              :             *msgReturn = "No route found";
     550              :         }
     551          579 :         return false;
     552              :     }
     553              :     // build a new id, first
     554              :     std::string id = getID();
     555      3038459 :     if (id[0] != '!') {
     556      6076918 :         id = "!" + id;
     557              :     }
     558      3038459 :     const std::string idSuffix = id + "!var#";
     559      3038459 :     int varIndex = 1;
     560      3038459 :     id = idSuffix + toString(varIndex);
     561      7087251 :     while (MSRoute::hasRoute(id)) {
     562      8097584 :         id = idSuffix + toString(++varIndex);
     563              :     }
     564      3038459 :     int oldSize = (int)edges.size();
     565      3038459 :     if (!onInit) {
     566        89580 :         const MSEdge* const origin = *getRerouteOrigin();
     567        89580 :         if (origin != *myCurrEdge && edges.front() == origin) {
     568         1034 :             edges.insert(edges.begin(), *myCurrEdge);
     569         1034 :             oldSize = (int)edges.size();
     570              :         }
     571       179160 :         edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
     572              :     }
     573      3038459 :     if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
     574              :         // re-assign stop iterators when rerouting to a new parkingArea / insertStop
     575              :         return true;
     576              :     }
     577      1535809 :     const RGBColor& c = myRoute->getColor();
     578      1535809 :     MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), StopParVector());
     579              :     newRoute->setCosts(cost);
     580              :     newRoute->setSavings(savings);
     581      1535809 :     ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
     582      3071618 :     if (!MSRoute::dictionary(id, constRoute)) {
     583            0 :         delete newRoute;
     584            0 :         if (msgReturn != nullptr) {
     585            0 :             *msgReturn = "duplicate routeID '" + id + "'";
     586              :         }
     587            0 :         return false;
     588              :     }
     589              : 
     590              :     std::string msg;
     591      1535842 :     if (check && !hasValidRoute(msg, constRoute)) {
     592            3 :         WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
     593            1 :         if (MSGlobals::gCheckRoutes) {
     594            1 :             if (msgReturn != nullptr) {
     595              :                 *msgReturn = msg;
     596              :             }
     597            1 :             return false;
     598              :         }
     599              :     }
     600      3071616 :     if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
     601              :         return false;
     602              :     }
     603              :     return true;
     604              : }
     605              : 
     606              : 
     607              : bool
     608      2060356 : MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     609              :     const ConstMSEdgeVector& edges = newRoute->getEdges();
     610              :     // rebuild in-vehicle route information
     611      2060356 :     if (onInit) {
     612      1466209 :         myCurrEdge = newRoute->begin();
     613              :     } else {
     614       594147 :         MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
     615       594147 :         if (newCurrEdge == edges.end()) {
     616            2 :             if (msgReturn != nullptr) {
     617            6 :                 *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
     618              :             }
     619              : #ifdef DEBUG_REPLACE_ROUTE
     620              :             if (DEBUG_COND) {
     621              :                 std::cout << "  newCurrEdge not found\n";
     622              :             }
     623              : #endif
     624            2 :             return false;
     625              :         }
     626       594145 :         if (getLane() != nullptr) {
     627       456683 :             if (getLane()->getEdge().isInternal() && (
     628       456692 :                         (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
     629            9 :                 if (msgReturn != nullptr) {
     630            1 :                     *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
     631              :                 }
     632              : #ifdef DEBUG_REPLACE_ROUTE
     633              :                 if (DEBUG_COND) {
     634              :                     std::cout << "  Vehicle is on junction-internal edge leading elsewhere\n";
     635              :                 }
     636              : #endif
     637            9 :                 return false;
     638       456674 :             } else if (getPositionOnLane() > getLane()->getLength()
     639       456679 :                        && (myCurrEdge + 1) != myRoute->end()
     640           12 :                        && (newCurrEdge + 1) != edges.end()
     641       456686 :                        && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
     642            7 :                 if (msgReturn != nullptr) {
     643            0 :                     *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
     644              :                 }
     645              : #ifdef DEBUG_REPLACE_ROUTE
     646              :                 if (DEBUG_COND) {
     647              :                     std::cout << "  Vehicle is moving past junction and committed to move to another successor edge\n";
     648              :                 }
     649              : #endif
     650            7 :                 return false;
     651              :             }
     652              :         }
     653       594129 :         myCurrEdge = newCurrEdge;
     654              :     }
     655      2060338 :     const bool stopsFromScratch = onInit && myRoute->getStops().empty();
     656              :     // assign new route
     657      2060338 :     checkRouteRemoval();
     658              :     myRoute = newRoute;
     659              :     // update arrival definition
     660      2060338 :     calculateArrivalParams(onInit);
     661              :     // save information that the vehicle was rerouted
     662      2060338 :     myNumberReroutes++;
     663      2060338 :     myStopUntilOffset += myRoute->getPeriod();
     664      2060338 :     MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
     665      2060338 :     if (!onInit && isRail() && MSRailSignalControl::hasInstance()) {
     666              :         // we need to update driveways (add/remove reminders) before the next call to MSRailSignalControl::updateSignals
     667              :         //
     668              :         // rerouting may be triggered through
     669              :         // - MoveReminders (executeMove->activateReminders)
     670              :         //   - rerouters
     671              :         //   - devices (MSDevice_Stationfinder)
     672              :         // - TraCI (changeTarget, replaceStop, ...
     673              :         // - events (MSDevice_Routing::myRerouteCommand, MSDevice_Taxi::triggerDispatch)
     674              :         //
     675              :         // Since activateReminders actively modifies reminders, adding/deleting reminders would create a mess
     676              :         // hence, we use an event to be safe for all case
     677              : 
     678         1372 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new WrappingCommand<MSBaseVehicle>(this,
     679          686 :                 &MSBaseVehicle::activateRemindersOnReroute), SIMSTEP);
     680              :     }
     681              : #ifdef DEBUG_REPLACE_ROUTE
     682              :     if (DEBUG_COND) {
     683              :         std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
     684              :                   << " lane=" << Named::getIDSecure(getLane())
     685              :                   << " stopsFromScratch=" << stopsFromScratch
     686              :                   << "  newSize=" << newRoute->getEdges().size()
     687              :                   << " newIndex=" << (myCurrEdge - newRoute->begin())
     688              :                   << " edges=" << toString(newRoute->getEdges())
     689              :                   << "\n";
     690              :     }
     691              : #endif
     692              :     // remove past stops which are not on the route anymore
     693      2147593 :     for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
     694       143703 :         const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
     695        87255 :         if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
     696            4 :             it = myPastStops.erase(it);
     697              :         } else {
     698              :             ++it;
     699              :         }
     700              :     }
     701              :     // if we did not drive yet it may be best to simply reassign the stops from scratch
     702      2060338 :     if (stopsFromScratch) {
     703              :         myStops.clear();
     704      1466145 :         addStops(!MSGlobals::gCheckRoutes);
     705              :     } else {
     706              :         // recheck old stops
     707       594193 :         MSRouteIterator searchStart = myCurrEdge;
     708       594193 :         double lastPos = getPositionOnLane() + getBrakeGap();
     709      1050860 :         if (getLane() != nullptr && getLane()->isInternal()
     710       595110 :                 && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
     711              :             // searchStart is still incoming to the intersection so lastPos
     712              :             // relative to that edge must be adapted
     713          172 :             lastPos += (*myCurrEdge)->getLength();
     714              :         }
     715              :         int stopIndex = 0;
     716       644295 :         for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
     717        50102 :             double endPos = iter->getEndPos(*this);
     718              : #ifdef DEBUG_REPLACE_ROUTE
     719              :             if (DEBUG_COND) {
     720              :                 std::cout << "     stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
     721              :             }
     722              : #endif
     723        50102 :             if (*searchStart != &iter->lane->getEdge()
     724        50102 :                     || endPos + NUMERICAL_EPS < lastPos) {
     725        36167 :                 if (searchStart != edges.end() && !iter->reached) {
     726              :                     searchStart++;
     727              :                 }
     728              :             }
     729              :             lastPos = endPos;
     730              : 
     731        50102 :             iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
     732              : #ifdef DEBUG_REPLACE_ROUTE
     733              :             if (DEBUG_COND) {
     734              :                 std::cout << "        foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
     735              :             }
     736              : #endif
     737        50102 :             if (iter->edge == edges.end() && iter->pars.priority >= 0) {
     738              :                 const std::string oldEdge = iter->pars.edge;
     739          124 :                 const std::string oldName = iter->getStoppingPlaceName().first;
     740           62 :                 if (replaceWithAlternative(iter, searchStart, edges.end())) {
     741          164 :                     WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
     742              :                                    getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
     743              :                 }
     744              :             }
     745        50102 :             if (iter->edge == edges.end()) {
     746          180 :                 if (!removeStops) {
     747           32 :                     WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
     748              :                 }
     749          180 :                 iter = myStops.erase(iter);
     750          180 :                 continue;
     751              :             } else {
     752        49922 :                 setSkips(*iter, stopIndex);
     753        49922 :                 searchStart = iter->edge;
     754              :             }
     755              :             ++iter;
     756        49922 :             stopIndex++;
     757              :         }
     758              :         // add new stops
     759       594193 :         if (addRouteStops) {
     760       524815 :             for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
     761              :                 std::string error;
     762          307 :                 addStop(*i, error, myParameter->depart + myStopUntilOffset);
     763          307 :                 if (error != "") {
     764            0 :                     WRITE_WARNING(error);
     765              :                 }
     766              :             }
     767              :         }
     768              :     }
     769              :     return true;
     770              : }
     771              : 
     772              : 
     773              : bool
     774           62 : MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
     775           62 :     std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
     776           62 :     if (!nameTag.first.empty()) {
     777           41 :         const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
     778          110 :         for (MSStoppingPlace* alt : alternatives) {
     779              :             //std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
     780          110 :             if (&alt->getLane().getEdge() == &iter->lane->getEdge()
     781          110 :                     || !alt->getLane().allowsVehicleClass(getVClass())) {
     782           62 :                 continue;
     783              :             }
     784           48 :             iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
     785           48 :             if (iter->edge != end) {
     786           41 :                 iter->replaceStoppingPlace(alt);
     787              :                 return true;
     788              :             }
     789              :         }
     790              :     }
     791              :     return false;
     792              : }
     793              : 
     794              : 
     795              : double
     796       172989 : MSBaseVehicle::getAcceleration() const {
     797       172989 :     return 0;
     798              : }
     799              : 
     800              : 
     801              : void
     802      4424836 : MSBaseVehicle::onDepart() {
     803      4424836 :     myDeparture = MSNet::getInstance()->getCurrentTimeStep();
     804      4424836 :     myDepartPos = getPositionOnLane();
     805      4424836 :     MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
     806      4424836 : }
     807              : 
     808              : 
     809              : SUMOTime
     810      3478182 : MSBaseVehicle:: getDepartDelay() const {
     811      3478182 :     const SUMOTime dep = getParameter().depart;
     812      3478182 :     if (dep < 0) {
     813              :         return 0;
     814              :     }
     815      3478075 :     return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
     816              : }
     817              : 
     818              : 
     819              : bool
     820            0 : MSBaseVehicle::hasArrived() const {
     821            0 :     return succEdge(1) == nullptr;
     822              : }
     823              : 
     824              : 
     825              : int
     826     33691330 : MSBaseVehicle::getRoutePosition() const {
     827     33691330 :     return (int) std::distance(myRoute->begin(), myCurrEdge);
     828              : }
     829              : 
     830              : 
     831              : int
     832       380320 : MSBaseVehicle::getNumRemainingEdges() const {
     833       380320 :     if (myParameter->arrivalEdge >= 0) {
     834            0 :         return myParameter->arrivalEdge - getRoutePosition() + 1;
     835              :     } else {
     836       380320 :         return myRoute->size() - getRoutePosition();
     837              :     }
     838              : }
     839              : 
     840              : 
     841              : void
     842       104063 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
     843       104063 :     myCurrEdge = myRoute->begin() + index;
     844       104063 :     const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
     845              :     // !!! hack
     846       104063 :     myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
     847       104063 : }
     848              : 
     849              : double
     850        26808 : MSBaseVehicle::getOdometer() const {
     851        26808 :     return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
     852              : }
     853              : 
     854              : bool
     855      4631162 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
     856      4631162 :     if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
     857              :         return false;
     858      4527231 :     } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
     859              :         return false;
     860              :     }
     861      8937551 :     if (isStopped() && myStops.begin()->pars.permitted.size() > 0
     862      4468831 :             && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
     863         6193 :         return false;
     864              :     }
     865      4462638 :     MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     866              :     if (taxiDevice != nullptr) {
     867        27569 :         return taxiDevice->allowsBoarding(t);
     868              :     }
     869              :     return true;
     870              : }
     871              : 
     872              : 
     873              : void
     874      4326607 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
     875      4326607 :     if (transportable->isPerson()) {
     876        13042 :         if (myPersonDevice == nullptr) {
     877         4593 :             myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
     878         4593 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
     879         4593 :             if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
     880         1960 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     881              :             }
     882              :         }
     883        13042 :         myPersonDevice->addTransportable(transportable);
     884              :     } else {
     885      4313565 :         if (myContainerDevice == nullptr) {
     886      4313131 :             myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
     887          424 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
     888          424 :             if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
     889           79 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     890              :             }
     891              :         }
     892          858 :         myContainerDevice->addTransportable(transportable);
     893              :     }
     894        13900 :     if (myEnergyParams != nullptr) {
     895         8984 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
     896              :     }
     897        13900 : }
     898              : 
     899              : 
     900              : bool
     901         2856 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
     902         3308 :     for (const MSStop& stop : myStops) {
     903         1049 :         if (stop.edge == it && stop.pars.jump >= 0) {
     904              :             return true;
     905          929 :         } else if (stop.edge > it) {
     906              :             return false;
     907              :         }
     908              :     }
     909              :     return false;
     910              : }
     911              : 
     912              : 
     913              : bool
     914      4656737 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
     915      4656737 :     MSRouteIterator start = myCurrEdge;
     916      4656737 :     if (route == nullptr) {
     917              :         route = myRoute;
     918              :     } else {
     919      3943088 :         start = route->begin();
     920              :     }
     921              :     const bool checkJumps = route == myRoute;  // the edge iterators in the stops are invalid otherwise
     922      4656737 :     return hasValidRoute(msg, start, route->end(), checkJumps);
     923              : }
     924              : 
     925              : 
     926              : bool
     927      4798157 : MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
     928              :     MSRouteIterator lastValid = last - 1;
     929              :     // check connectivity, first
     930     21966808 :     for (MSRouteIterator e = start; e != lastValid; ++e) {
     931     17217943 :         const MSEdge& next = **(e + 1);
     932     17217943 :         if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
     933        50082 :             if (!checkJumps || !hasJump(e)) {
     934        49962 :                 if (!ignoreTransientPermissions()
     935        49962 :                         || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
     936       147876 :                     msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
     937        49292 :                     return false;
     938              :                 }
     939              :             }
     940              :         }
     941              :     }
     942              :     // check usable lanes, then
     943     26665403 :     for (MSRouteIterator e = start; e != last; ++e) {
     944     21916538 :         if ((*e)->prohibits(this)) {
     945            0 :             msg = TLF("Edge '%' prohibits.", (*e)->getID());
     946              :             return false;
     947              :         }
     948              :     }
     949              :     return true;
     950              : }
     951              : 
     952              : 
     953              : bool
     954    504187062 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
     955    504187062 :     if (!(*myCurrEdge)->isTazConnector()) {
     956    504049592 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
     957           12 :             msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
     958            6 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
     959            6 :             return false;
     960              :         }
     961              :     }
     962    504187056 :     if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
     963    504186996 :         myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
     964    504186996 :         return true;
     965              :     } else {
     966          180 :         msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
     967           60 :         myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
     968           60 :         return false;
     969              :     }
     970              : }
     971              : 
     972              : 
     973              : int
     974  12799959302 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
     975  12799959302 :     if (!update) {
     976   5215241871 :         return myRouteValidity;
     977              :     }
     978              :     // insertion check must be done in any case
     979              :     std::string msg;
     980   7584717431 :     if (!hasValidRouteStart(msg)) {
     981          183 :         if (MSGlobals::gCheckRoutes) {
     982          111 :             throw ProcessError(msg);
     983           72 :         } else if (!silent) {
     984              :             // vehicle will be discarded
     985          138 :             WRITE_WARNING(msg);
     986           26 :         } else if (msgReturn != nullptr) {
     987              :             *msgReturn = msg;
     988              :         }
     989              :     }
     990        30468 :     if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
     991   7584686858 :             && (myRouteValidity & ROUTE_UNCHECKED) != 0
     992              :             // we could check after the first rerouting
     993   7590123938 :             && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
     994      7787301 :         if (!hasValidRoute(msg, myRoute)) {
     995           78 :             myRouteValidity |= ROUTE_INVALID;
     996          234 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
     997              :         }
     998              :     }
     999   7584717242 :     myRouteValidity &= ~ROUTE_UNCHECKED;
    1000              :     return myRouteValidity;
    1001              : }
    1002              : 
    1003              : 
    1004              : bool
    1005          719 : MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
    1006         3186 :     for (auto item : myMoveReminders) {
    1007         2495 :         if (item.first == rem) {
    1008              :             return true;
    1009              :         }
    1010              :     }
    1011          691 :     return false;
    1012              : }
    1013              : 
    1014              : 
    1015              : void
    1016     28788963 : MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
    1017              : #ifdef _DEBUG
    1018              :     if (myTraceMoveReminders) {
    1019              :         traceMoveReminder("add", rem, pos, true);
    1020              :     }
    1021              : #endif
    1022     28788963 :     myMoveReminders.push_back(std::make_pair(rem, pos));
    1023     28788963 : }
    1024              : 
    1025              : 
    1026              : void
    1027            0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
    1028            0 :     for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
    1029            0 :         if (r->first == rem) {
    1030              : #ifdef _DEBUG
    1031              :             if (myTraceMoveReminders) {
    1032              :                 traceMoveReminder("remove", rem, 0, false);
    1033              :             }
    1034              : #endif
    1035              :             myMoveReminders.erase(r);
    1036              :             return;
    1037              :         }
    1038              :     }
    1039              : }
    1040              : 
    1041              : 
    1042              : void
    1043     49378501 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
    1044              :     // notifyEnter may cause new reminders to be added so we cannot use an iterator
    1045    141500641 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1046     92122143 :         MSMoveReminder* rem = myMoveReminders[i].first;
    1047     92122143 :         const double remPos = myMoveReminders[i].second;
    1048              :         // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
    1049     92122143 :         if (rem->getLane() != nullptr && remPos > 0.) {
    1050              : #ifdef _DEBUG
    1051              :             if (myTraceMoveReminders) {
    1052              :                 traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
    1053              :             }
    1054              : #endif
    1055     19978451 :             ++i;
    1056              :         } else {
    1057     72143692 :             if (rem->notifyEnter(*this, reason, enteredLane)) {
    1058              : #ifdef _DEBUG
    1059              :                 if (myTraceMoveReminders) {
    1060              :                     traceMoveReminder("notifyEnter", rem, remPos, true);
    1061              :                 }
    1062              : #endif
    1063     70039032 :                 ++i;
    1064              :             } else {
    1065              : #ifdef _DEBUG
    1066              :                 if (myTraceMoveReminders) {
    1067              :                     traceMoveReminder("notifyEnter", rem, remPos, false);
    1068              :                 }
    1069              : #endif
    1070              :                 myMoveReminders.erase(myMoveReminders.begin() + i);
    1071              :             }
    1072              :         }
    1073              :     }
    1074     49378498 : }
    1075              : 
    1076              : 
    1077              : bool
    1078   2859085172 : MSBaseVehicle::isRail() const {
    1079   2859085172 :     return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
    1080              : }
    1081              : 
    1082              : void
    1083     10547235 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
    1084     10547235 :     if (myRoute->getLastEdge()->isTazConnector()) {
    1085              :         return;
    1086              :     }
    1087      9969543 :     const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
    1088      9969543 :     if (arrivalEdgeIndex != myParameter->arrivalEdge) {
    1089           21 :         if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
    1090           42 :             WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
    1091              :                            getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
    1092              :         }
    1093              :     }
    1094      9969543 :     const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
    1095      9969543 :     if (!onInit) {
    1096       594129 :         arrivalEdge = myRoute->getLastEdge();
    1097              :         // ignore arrivalEdge parameter after rerouting
    1098       594129 :         const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
    1099              :     }
    1100              :     const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
    1101      9969543 :     const double lastLaneLength = lanes[0]->getLength();
    1102      9969543 :     switch (myParameter->arrivalPosProcedure) {
    1103       249550 :         case ArrivalPosDefinition::GIVEN:
    1104       249550 :             if (fabs(myParameter->arrivalPos) > lastLaneLength) {
    1105         4212 :                 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
    1106              :             }
    1107              :             // Maybe we should warn the user about invalid inputs!
    1108       249550 :             myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
    1109       249550 :             if (myArrivalPos < 0) {
    1110        28201 :                 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
    1111              :             }
    1112              :             break;
    1113              :         case ArrivalPosDefinition::RANDOM:
    1114       100274 :             myArrivalPos = RandHelper::rand(lastLaneLength);
    1115       100274 :             break;
    1116            0 :         case ArrivalPosDefinition::CENTER:
    1117            0 :             myArrivalPos = lastLaneLength / 2.;
    1118            0 :             break;
    1119      9619719 :         default:
    1120      9619719 :             myArrivalPos = lastLaneLength;
    1121      9619719 :             break;
    1122              :     }
    1123      9969543 :     if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
    1124       161676 :         if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
    1125       385545 :             WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
    1126              :         }
    1127       161676 :         myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
    1128      9807867 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
    1129            7 :         myArrivalLane = -1;
    1130            7 :         for (MSLane* lane : lanes) {
    1131            7 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1132            7 :                 myArrivalLane = lane->getIndex();
    1133            7 :                 break;
    1134              :             }
    1135              :         }
    1136            7 :         if (myArrivalLane == -1) {
    1137            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1138            0 :             myArrivalLane = 0;
    1139              :         }
    1140      9807860 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
    1141              :         // pick random lane among all usable lanes
    1142              :         std::vector<MSLane*> usable;
    1143       388393 :         for (MSLane* lane : lanes) {
    1144       295575 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1145       270441 :                 usable.push_back(lane);
    1146              :             }
    1147              :         }
    1148        92818 :         if (usable.empty()) {
    1149            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1150            0 :             myArrivalLane = 0;
    1151              :         } else {
    1152        92818 :             myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
    1153              :         }
    1154        92818 :     }
    1155      9969543 :     if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
    1156       292333 :         for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
    1157       224751 :             if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
    1158              :                 return;
    1159              :             }
    1160              :         }
    1161       202746 :         WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
    1162              :     }
    1163              : }
    1164              : 
    1165              : void
    1166      6933544 : MSBaseVehicle::setDepartAndArrivalEdge() {
    1167      6933544 :     SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
    1168      6933544 :     if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
    1169         8142 :         const int routeEdges = (int)myRoute->getEdges().size();
    1170         8142 :         if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1171              :             // write specific edge in vehroute output for reproducibility
    1172         4185 :             pars->departEdge = RandHelper::rand(0, routeEdges);
    1173         4185 :             pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
    1174              :         }
    1175              :         assert(pars->departEdge >= 0);
    1176         8142 :         if (pars->departEdge >= routeEdges) {
    1177            0 :             WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
    1178              :         } else {
    1179         8142 :             myCurrEdge = myRoute->begin() + pars->departEdge;
    1180              :         }
    1181              :     }
    1182      6933544 :     if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1183          147 :         const int routeEdges = (int)myRoute->getEdges().size();
    1184          147 :         const int begin = (int)(myCurrEdge - myRoute->begin());
    1185              :         // write specific edge in vehroute output for reproducibility
    1186          147 :         pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
    1187          147 :         pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
    1188              :         assert(pars->arrivalEdge >= begin);
    1189              :         assert(pars->arrivalEdge < routeEdges);
    1190              :     }
    1191      6933544 : }
    1192              : 
    1193              : int
    1194         3883 : MSBaseVehicle::getDepartEdge() const {
    1195         3883 :     return myParameter->departEdge < myRoute->size() ? myParameter->departEdge : 0;
    1196              : }
    1197              : 
    1198              : int
    1199     32917594 : MSBaseVehicle::getInsertionChecks() const {
    1200     32917594 :     if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
    1201       440282 :         return getParameter().insertionChecks;
    1202              :     } else {
    1203     32477312 :         return MSGlobals::gInsertionChecks;
    1204              :     }
    1205              : }
    1206              : 
    1207              : double
    1208    640338943 : MSBaseVehicle::getImpatience() const {
    1209   1280677886 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
    1210    640338943 :                          + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
    1211    640338943 :                          + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
    1212              : }
    1213              : 
    1214              : 
    1215              : MSDevice*
    1216    985701004 : MSBaseVehicle::getDevice(const std::type_info& type) const {
    1217   1705546191 :     for (MSVehicleDevice* const dev : myDevices) {
    1218    799872006 :         if (typeid(*dev) == type) {
    1219     80026819 :             return dev;
    1220              :         }
    1221              :     }
    1222              :     return nullptr;
    1223              : }
    1224              : 
    1225              : 
    1226              : void
    1227         4265 : MSBaseVehicle::saveState(OutputDevice& out) {
    1228              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
    1229         4265 :     const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
    1230         4265 :     myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
    1231              :     // params and stops must be written in child classes since they may wish to add additional attributes first
    1232         4265 :     out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
    1233         4265 :     std::ostringstream os;
    1234         8530 :     os << myOdometer << " " << myNumberReroutes;
    1235         4265 :     out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
    1236         4265 :     if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
    1237           13 :         out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
    1238              :     }
    1239         4265 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
    1240              :         const int precision = out.getPrecision();
    1241         4265 :         out.setPrecision(MAX2(gPrecisionRandom, precision));
    1242         4265 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
    1243         4265 :         out.setPrecision(precision);
    1244              :     }
    1245         4265 :     if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    1246         2878 :         out.writeAttr(SUMO_ATTR_REROUTE, true);
    1247              :     }
    1248         4265 :     if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
    1249              :         // could be set from stop
    1250            2 :         out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
    1251              :     }
    1252              :     // here starts the vehicle internal part (see loading)
    1253              :     // @note: remember to close the vehicle tag when calling this in a subclass!
    1254         8530 : }
    1255              : 
    1256              : 
    1257              : bool
    1258            0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    1259              :     UNUSED_PARAMETER(stop);
    1260              :     UNUSED_PARAMETER(distToStop);
    1261            0 :     return true;
    1262              : }
    1263              : 
    1264              : 
    1265              : bool
    1266   9556987513 : MSBaseVehicle::isStopped() const {
    1267   9556987513 :     return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
    1268              : }
    1269              : 
    1270              : 
    1271              : bool
    1272   2664980339 : MSBaseVehicle::isParking() const {
    1273   2722473380 :     return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
    1274      5784300 :             && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
    1275   2669706208 :             && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
    1276              : }
    1277              : 
    1278              : 
    1279              : bool
    1280    677641650 : MSBaseVehicle::isJumping() const {
    1281    677641650 :     return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
    1282              : }
    1283              : 
    1284              : 
    1285              : bool
    1286      7364891 : MSBaseVehicle::isStoppedTriggered() const {
    1287      7364891 :     return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
    1288              : }
    1289              : 
    1290              : 
    1291              : bool
    1292        28231 : MSBaseVehicle::isStoppedParking() const {
    1293        28231 :     return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
    1294              : }
    1295              : 
    1296              : 
    1297              : bool
    1298      4331026 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
    1299      4331026 :     if (isStopped() || (checkFuture && hasStops())) {
    1300              :         const MSStop& stop = myStops.front();
    1301      4332161 :         return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
    1302              :     }
    1303              :     return false;
    1304              : }
    1305              : 
    1306              : bool
    1307        28809 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
    1308              :     // Check if there is a parking area to be replaced
    1309        28809 :     if (parkingArea == 0) {
    1310              :         errorMsg = "new parkingArea is NULL";
    1311            0 :         return false;
    1312              :     }
    1313        28809 :     if (myStops.size() == 0) {
    1314              :         errorMsg = "vehicle has no stops";
    1315            0 :         return false;
    1316              :     }
    1317        28809 :     if (myStops.front().parkingarea == 0) {
    1318              :         errorMsg = "first stop is not at parkingArea";
    1319            0 :         return false;
    1320              :     }
    1321              :     MSStop& first = myStops.front();
    1322              :     SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
    1323        28809 :     std::string oldStopEdgeID = first.lane->getEdge().getID();
    1324              :     // merge subsequent duplicate stops equals to parking area
    1325        28827 :     for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
    1326          342 :         if (iter->parkingarea == parkingArea) {
    1327           18 :             stopPar.duration += iter->duration;
    1328           18 :             myStops.erase(iter++);
    1329              :         } else {
    1330              :             break;
    1331              :         }
    1332              :     }
    1333        28809 :     stopPar.lane = parkingArea->getLane().getID();
    1334        28809 :     stopPar.parkingarea = parkingArea->getID();
    1335        28809 :     stopPar.startPos = parkingArea->getBeginLanePosition();
    1336        28809 :     stopPar.endPos = parkingArea->getEndLanePosition();
    1337        28809 :     first.edge = myRoute->end(); // will be patched in replaceRoute
    1338        28809 :     first.lane = &parkingArea->getLane();
    1339        28809 :     first.parkingarea = parkingArea;
    1340              : 
    1341              :     // patch via edges
    1342        28809 :     std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
    1343        28809 :     if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
    1344          222 :         myParameter->via.erase(myParameter->via.begin());
    1345          222 :         myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
    1346              :     }
    1347              :     return true;
    1348              : }
    1349              : 
    1350              : 
    1351              : MSParkingArea*
    1352       207895 : MSBaseVehicle::getNextParkingArea() {
    1353              :     MSParkingArea* nextParkingArea = nullptr;
    1354       207895 :     if (!myStops.empty()) {
    1355       205113 :         SUMOVehicleParameter::Stop stopPar;
    1356       205113 :         MSStop stop = myStops.front();
    1357       205113 :         if (!stop.reached && stop.parkingarea != nullptr) {
    1358              :             nextParkingArea = stop.parkingarea;
    1359              :         }
    1360       205113 :     }
    1361       207895 :     return nextParkingArea;
    1362              : }
    1363              : 
    1364              : 
    1365              : MSParkingArea*
    1366       127016 : MSBaseVehicle::getCurrentParkingArea() {
    1367              :     MSParkingArea* currentParkingArea = nullptr;
    1368       127016 :     if (isParking()) {
    1369       126947 :         currentParkingArea = myStops.begin()->parkingarea;
    1370              :     }
    1371       127016 :     return currentParkingArea;
    1372              : }
    1373              : 
    1374              : 
    1375              : const std::vector<std::string>&
    1376         1656 : MSBaseVehicle::getParkingBadges() const {
    1377         1656 :     if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
    1378            7 :         return myParameter->parkingBadges;
    1379              :     } else {
    1380         1649 :         return getVehicleType().getParkingBadges();
    1381              :     }
    1382              : }
    1383              : 
    1384              : 
    1385              : double
    1386     12226496 : MSBaseVehicle::basePos(const MSEdge* edge) const {
    1387     12226496 :     double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
    1388     12226496 :     if (hasStops()
    1389     12251041 :             && myStops.front().edge == myRoute->begin()
    1390     12251041 :             && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
    1391        24501 :         result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
    1392              :     }
    1393     12226496 :     return result;
    1394              : }
    1395              : 
    1396              : 
    1397              : MSLane*
    1398          298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
    1399          298 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
    1400          298 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
    1401          298 :     if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
    1402            8 :         return nullptr;
    1403              :     }
    1404          580 :     const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
    1405          290 :     if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
    1406          290 :         const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
    1407          290 :         stop.edge = edgeID;
    1408          290 :         return edge->getOppositeEdge()->getLanes()[oppositeIndex];
    1409              :     }
    1410              :     return nullptr;
    1411              : }
    1412              : 
    1413              : 
    1414              : bool
    1415       138422 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
    1416              :                        MSRouteIterator* searchStart) {
    1417       138422 :     MSStop stop(stopPar);
    1418       138422 :     if (stopPar.lane == "") {
    1419         2987 :         MSEdge* e = MSEdge::dictionary(stopPar.edge);
    1420         2987 :         stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
    1421         2987 :         if (stop.lane == nullptr) {
    1422            0 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
    1423            0 :             return false;
    1424              :         }
    1425              :     } else {
    1426       135435 :         stop.lane = MSLane::dictionary(stopPar.lane);
    1427       135435 :         if (stop.lane == nullptr) {
    1428              :             // must be an opposite stop
    1429          145 :             SUMOVehicleParameter::Stop tmp = stopPar;
    1430          145 :             stop.lane = interpretOppositeStop(tmp);
    1431              :             assert(stop.lane != nullptr);
    1432          145 :         }
    1433       135435 :         if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
    1434           24 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
    1435           12 :             return false;
    1436              :         }
    1437              :     }
    1438       138410 :     if (MSGlobals::gUseMesoSim) {
    1439        28652 :         stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
    1440        28652 :         if (stop.lane->isInternal()) {
    1441            2 :             errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
    1442            1 :             return false;
    1443              :         }
    1444              :     }
    1445       138409 :     stop.initPars(stopPar);
    1446       138409 :     if (stopPar.until != -1) {
    1447              :         // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
    1448        53005 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
    1449              :     }
    1450       138409 :     if (stopPar.arrival != -1) {
    1451          620 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
    1452              :     }
    1453       138409 :     std::string stopType = "stop";
    1454       138409 :     std::string stopID = "";
    1455       138409 :     double parkingLength = stop.pars.endPos - stop.pars.startPos;
    1456       138409 :     if (stop.busstop != nullptr) {
    1457              :         stopType = "busStop";
    1458        37637 :         stopID = stop.busstop->getID();
    1459        37637 :         parkingLength = stop.busstop->getParkingLength();
    1460       100772 :     } else if (stop.containerstop != nullptr) {
    1461              :         stopType = "containerStop";
    1462         1050 :         stopID = stop.containerstop->getID();
    1463         1050 :         parkingLength = stop.containerstop->getParkingLength();
    1464        99722 :     } else if (stop.chargingStation != nullptr) {
    1465              :         stopType = "chargingStation";
    1466         8254 :         stopID = stop.chargingStation->getID();
    1467         8254 :         parkingLength = stop.chargingStation->getParkingLength();
    1468        91468 :     } else if (stop.overheadWireSegment != nullptr) {
    1469              :         stopType = "overheadWireSegment";
    1470            0 :         stopID = stop.overheadWireSegment->getID();
    1471            0 :         parkingLength = stop.overheadWireSegment->getParkingLength();
    1472        91468 :     } else if (stop.parkingarea != nullptr) {
    1473              :         stopType = "parkingArea";
    1474        29599 :         stopID = stop.parkingarea->getID();
    1475              :     }
    1476       276818 :     const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
    1477              : 
    1478       138409 :     if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
    1479            0 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
    1480            0 :         return false;
    1481              :     }
    1482        76540 :     if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
    1483              :             // do not warn for stops that fill the whole lane
    1484          307 :             && parkingLength < stop.lane->getLength()
    1485              :             // do not warn twice for the same stop
    1486       215786 :             && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
    1487          837 :         errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
    1488              :     }
    1489       138409 :     if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
    1490              :         // forbid access in case the parking requests other badges
    1491           14 :         errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
    1492            7 :         return false;
    1493              :     }
    1494       138402 :     const MSEdge* stopLaneEdge = &stop.lane->getEdge();
    1495              :     const MSEdge* stopEdge;
    1496       138402 :     if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
    1497              :         // stop lane is on the opposite side
    1498          145 :         stopEdge = stopLaneEdge->getOppositeEdge();
    1499          145 :         stop.isOpposite = true;
    1500              :     } else {
    1501              :         // if stop is on an internal edge the normal edge before the intersection is used
    1502       138257 :         stopEdge = stopLaneEdge->getNormalBefore();
    1503              :     }
    1504       138402 :     MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
    1505       138402 :     if (searchStart == nullptr) {
    1506       131557 :         searchStart = &myCurrEdge;
    1507       131557 :         if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
    1508              :             // already on the intersection but myCurrEdge is before it
    1509              :             searchStart = &succ;
    1510              :         }
    1511              :     }
    1512              : #ifdef DEBUG_ADD_STOP
    1513              :     if (DEBUG_COND) {
    1514              :         std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
    1515              :                   << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
    1516              :                   << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
    1517              :                   << "\n";
    1518              :     }
    1519              : #endif
    1520       138402 :     stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
    1521       138402 :     MSRouteIterator prevStopEdge = myCurrEdge;
    1522       138402 :     const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
    1523       138402 :     double prevStopPos = getPositionOnLane();
    1524              :     // where to insert the stop
    1525              :     std::list<MSStop>::iterator iter = myStops.begin();
    1526       138402 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
    1527              :         iter = myStops.end();
    1528       116205 :         if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
    1529              :             prevStopEdge = myStops.back().edge;
    1530        49353 :             prevEdge = &myStops.back().lane->getEdge();
    1531        49353 :             prevStopPos = myStops.back().pars.endPos;
    1532        49353 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1533              :             if (prevStopEdge == stop.edge                // laneEdge check is insufficient for looped routes
    1534         8026 :                     && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
    1535        57367 :                     && (prevStopPos > stop.pars.endPos ||
    1536         2234 :                         (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
    1537          440 :                 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
    1538              :             }
    1539              : #ifdef DEBUG_ADD_STOP
    1540              :             if (DEBUG_COND) {
    1541              :                 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
    1542              :                           << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
    1543              :             }
    1544              : #endif
    1545              :         }
    1546              :         // skip a number of occurences of stopEdge in looped route
    1547       116205 :         int skipLooped = stopPar.index - static_cast<int>(myStops.size());
    1548       116782 :         for (int j = 0; j < skipLooped; j++) {
    1549          723 :             auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
    1550          723 :             if (nextIt == myRoute->end()) {
    1551          146 :                 if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
    1552              :                     // only warn if the route loops over the stop edge at least once
    1553           28 :                     errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
    1554              :                 }
    1555          146 :                 break;
    1556              :             } else {
    1557          577 :                 stop.edge = nextIt;
    1558              :             }
    1559              :         }
    1560              :     } else {
    1561        22197 :         if (stopPar.index == STOP_INDEX_FIT) {
    1562        33779 :             while (iter != myStops.end() && (iter->edge < stop.edge ||
    1563          958 :                                              (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
    1564          958 :                                              (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
    1565              :                 prevStopEdge = iter->edge;
    1566        11681 :                 prevStopPos = iter->pars.endPos;
    1567              :                 ++iter;
    1568              :             }
    1569              :         } else {
    1570              :             int index = stopPar.index;
    1571           99 :             while (index > 0) {
    1572            0 :                 prevStopEdge = iter->edge;
    1573            0 :                 prevStopPos = iter->pars.endPos;
    1574              :                 ++iter;
    1575            0 :                 --index;
    1576              :             }
    1577              : #ifdef DEBUG_ADD_STOP
    1578              :             if (DEBUG_COND) {
    1579              :                 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
    1580              :             }
    1581              : #endif
    1582           99 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1583              :         }
    1584              :     }
    1585       138722 :     const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
    1586       138402 :     if (stop.edge == myRoute->end()) {
    1587           83 :         if (!wasTooClose) {
    1588          207 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
    1589              :         }
    1590           83 :         return false;
    1591              :     }
    1592              : 
    1593       138319 :     const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
    1594        42849 :                            prevStopPos + (iter == myStops.begin() && !instantStopping() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
    1595              : 
    1596       138319 :     if (prevStopEdge > stop.edge ||
    1597              :             // a collision-stop happens after vehicle movement and may move the
    1598              :             // vehicle backwards on its lane (prevStopPos is the vehicle position)
    1599         1874 :             (tooClose && !stop.pars.collision)
    1600       276604 :             || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
    1601              :         // check if the edge occurs again later in the route
    1602              :         //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges())  << "\n";
    1603           34 :         if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
    1604          102 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
    1605              :         }
    1606           34 :         MSRouteIterator next = stop.edge + 1;
    1607           34 :         return addStop(stopPar, errorMsg, untilOffset, &next);
    1608              :     }
    1609       138285 :     if (wasTooClose) {
    1610              :         errorMsg = "";
    1611              :     }
    1612              :     // David.C:
    1613              :     //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
    1614       138285 :     const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
    1615       138285 :     const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
    1616       138285 :     if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
    1617              :         return false;
    1618              :     }
    1619       138285 :     if (!hasDeparted() && myCurrEdge == stop.edge) {
    1620              :         double pos = -1;
    1621        26287 :         if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
    1622         4744 :             pos = myParameter->departPos;
    1623         4744 :             if (pos < 0.) {
    1624          219 :                 pos += (*myCurrEdge)->getLength();
    1625              :             }
    1626              :         }
    1627        26287 :         if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
    1628        18311 :             pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
    1629              :         }
    1630        26287 :         if (pos > stop.pars.endPos + endPosOffset) {
    1631           20 :             if (stop.edge != myRoute->end()) {
    1632              :                 // check if the edge occurs again later in the route
    1633           20 :                 MSRouteIterator next = stop.edge + 1;
    1634           20 :                 return addStop(stopPar, errorMsg, untilOffset, &next);
    1635              :             }
    1636            0 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
    1637            0 :             return false;
    1638              :         }
    1639              :     }
    1640       138265 :     if (iter != myStops.begin()) {
    1641              :         std::list<MSStop>::iterator iter2 = iter;
    1642              :         iter2--;
    1643        96249 :         if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
    1644        61015 :                 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
    1645            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1646           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1647           24 :                        + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
    1648              :         }
    1649        60998 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1650            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1651           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1652           24 :                        + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
    1653              :         }
    1654        60998 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1655            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1656           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1657           24 :                        + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
    1658              :         }
    1659              :     } else {
    1660        95017 :         if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
    1661        77279 :                 && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
    1662            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1663           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1664           24 :                        + " earlier than departure at " + time2string(getParameter().depart) + ".";
    1665              :         }
    1666              :     }
    1667       138265 :     if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
    1668           18 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1669           54 :                    + "' set to end at " + time2string(stop.getUntil())
    1670           72 :                    + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
    1671              :     }
    1672       138265 :     setSkips(stop, (int)myStops.size());
    1673       138265 :     myStops.insert(iter, stop);
    1674       138265 :     if (stopPar.tripId != "") {
    1675         2664 :         MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
    1676              :     }
    1677              :     //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
    1678              :     //    << " routeIndex=" << (stop.edge - myRoute->begin())
    1679              :     //    << " stopIndex=" << std::distance(myStops.begin(), iter)
    1680              :     //    << " route=" << toString(myRoute->getEdges())  << "\n";
    1681              :     return true;
    1682              : }
    1683              : 
    1684              : 
    1685              : void
    1686       188187 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
    1687       188187 :     if (hasDeparted() && stop.edge > myRoute->begin()) {
    1688              :         // if the route is looped we must patch the index to ensure that state
    1689              :         // loading (and vehroute-output) encode the correct number of skips
    1690              :         int foundSkips = 0;
    1691              :         MSRouteIterator itPrev;
    1692              :         double prevEndPos;
    1693        83465 :         if (prevActiveStops > 0) {
    1694              :             assert((int)myStops.size() >= prevActiveStops);
    1695              :             auto prevStopIt = myStops.begin();
    1696        35749 :             std::advance(prevStopIt, prevActiveStops - 1);
    1697              :             const MSStop& prev = *prevStopIt;
    1698        35749 :             itPrev = prev.edge;
    1699        35749 :             prevEndPos = prev.pars.endPos;
    1700        47716 :         } else if (myPastStops.size() > 0) {
    1701        12249 :             itPrev = myRoute->begin() + myPastStops.back().routeIndex;
    1702        12249 :             prevEndPos = myPastStops.back().endPos;
    1703              :         } else {
    1704        35467 :             itPrev = myRoute->begin() + myParameter->departEdge;
    1705        35467 :             prevEndPos = myDepartPos;
    1706              :         }
    1707              :         //auto itPrevOrig = itPrev;
    1708        83465 :         if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
    1709              :             itPrev++;
    1710              :         }
    1711              :         //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
    1712       756463 :         while (itPrev < stop.edge) {
    1713       672998 :             if (*itPrev == *stop.edge) {
    1714        49717 :                 foundSkips++;
    1715              :             }
    1716              :             itPrev++;
    1717              :         }
    1718              :         int newIndex = STOP_INDEX_END;
    1719        83465 :         if (foundSkips > 0) {
    1720              :             //if (getID() == "77_0_0") {
    1721              :             //    std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
    1722              :             //        << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
    1723              :             //        << " prevEdge=" << (*itPrevOrig)->getID()
    1724              :             //        << " prevIndex=" << (itPrevOrig - myRoute->begin())
    1725              :             //        << " skips=" << foundSkips << "\n";
    1726              :             //}
    1727        21340 :             newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
    1728              :         }
    1729        83465 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
    1730              :     }
    1731       188187 : }
    1732              : 
    1733              : 
    1734              : SUMOTime
    1735          681 : MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
    1736         3640 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1737         2959 :         auto rem = &myMoveReminders[i];
    1738         2959 :         if (rem->first->notifyReroute(*this)) {
    1739              : #ifdef _DEBUG
    1740              :             if (myTraceMoveReminders) {
    1741              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, true);
    1742              :             }
    1743              : #endif
    1744         2258 :             ++i;
    1745              :         } else {
    1746              : #ifdef _DEBUG
    1747              :             if (myTraceMoveReminders) {
    1748              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, false);
    1749              :             }
    1750              : #endif
    1751              :             myMoveReminders.erase(myMoveReminders.begin() + i);
    1752              :         }
    1753              :     }
    1754          681 :     resetApproachOnReroute();
    1755              :     // event only called once
    1756          681 :     return 0;
    1757              : }
    1758              : 
    1759              : 
    1760              : void
    1761      7004041 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
    1762      7004041 :     if (addRouteStops) {
    1763      7008557 :         for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    1764              :             std::string errorMsg;
    1765         9890 :             if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
    1766            6 :                 throw ProcessError(errorMsg);
    1767              :             }
    1768         9884 :             if (errorMsg != "") {
    1769          687 :                 WRITE_WARNING(errorMsg);
    1770              :             }
    1771              :         }
    1772              :     }
    1773      7004035 :     const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
    1774      7102346 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    1775              :         std::string errorMsg;
    1776        98339 :         if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
    1777           28 :             throw ProcessError(errorMsg);
    1778              :         }
    1779        98311 :         if (errorMsg != "") {
    1780          463 :             WRITE_WARNING(errorMsg);
    1781              :         }
    1782              :     }
    1783      7004007 : }
    1784              : 
    1785              : 
    1786              : bool
    1787      1512432 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
    1788      1512432 :     MSRouteIterator start = myCurrEdge;
    1789              :     int i = 0;
    1790              :     bool ok = true;
    1791      1540231 :     for (const MSStop& stop : myStops) {
    1792              :         MSRouteIterator it;
    1793        27799 :         if (stop.lane->isInternal()) {
    1794              :             // find the normal predecessor and ensure that the next route edge
    1795              :             // matches the successor of the internal edge successor
    1796            0 :             it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
    1797            0 :             if (it != myRoute->end() && (
    1798            0 :                         it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
    1799            0 :                 it = myRoute->end(); // signal failure
    1800              :             }
    1801              :         } else {
    1802        27799 :             it = std::find(start, myRoute->end(), &stop.lane->getEdge());
    1803              :         }
    1804        27799 :         if (it == myRoute->end()) {
    1805            0 :             if (!silent) {
    1806            0 :                 WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
    1807              :                              i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1808              :             }
    1809              :             ok = false;
    1810              :         } else {
    1811              :             MSRouteIterator it2;
    1812      1066952 :             for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
    1813      1057170 :                 if (it2 == stop.edge) {
    1814              :                     break;
    1815              :                 }
    1816              :             }
    1817        27799 :             if (it2 == myRoute->end()) {
    1818         9782 :                 if (!silent) {
    1819            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
    1820              :                                  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
    1821              :                 }
    1822              :                 ok = false;
    1823        18017 :             } else if (it2 < start) {
    1824            0 :                 if (!silent) {
    1825            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
    1826              :                                  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1827              :                 }
    1828              :                 ok = false;
    1829              :             } else {
    1830        18017 :                 start = stop.edge;
    1831              :             }
    1832              :         }
    1833        27799 :         i++;
    1834              :     }
    1835      1512432 :     return ok;
    1836              : }
    1837              : 
    1838              : 
    1839              : std::vector<MSBaseVehicle::StopEdgeInfo>
    1840      3118591 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
    1841              :     assert(haveValidStopEdges());
    1842              :     std::vector<StopEdgeInfo> result;
    1843              :     const MSStop* prev = nullptr;
    1844              :     const MSEdge* internalSuccessor = nullptr;
    1845      3214072 :     for (const MSStop& stop : myStops) {
    1846        95481 :         if (stop.reached) {
    1847         9740 :             if (stop.pars.jump >= 0) {
    1848            0 :                 jumps.insert((int)result.size());
    1849              :             }
    1850         9740 :             continue;
    1851              :         }
    1852        85741 :         double stopPos = stop.getEndPos(*this);
    1853              :         if ((prev == nullptr
    1854        46274 :                 || prev->edge != stop.edge
    1855         1260 :                 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
    1856       130755 :                 && *stop.edge != internalSuccessor) {
    1857        84481 :             if (stop.lane->isInternal()) {
    1858            9 :                 stopPos = (*stop.edge)->getLength();
    1859              :             }
    1860        84481 :             result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
    1861        84481 :             result.back().nameTag = stop.getStoppingPlaceName();
    1862        84481 :             result.back().stopPar = &stop.pars;
    1863        84481 :             if (stop.lane->isInternal()) {
    1864            9 :                 internalSuccessor = stop.lane->getNextNormal();
    1865           18 :                 result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
    1866              :             } else {
    1867              :                 internalSuccessor = nullptr;
    1868              :             }
    1869         1260 :         } else if (prev != nullptr && prev->edge == stop.edge) {
    1870         1260 :             result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
    1871              :         }
    1872              :         prev = &stop;
    1873        85741 :         if (firstPos == INVALID_DOUBLE) {
    1874        39467 :             if (stop.parkingarea != nullptr) {
    1875         5103 :                 firstPos = MAX2(0., stopPos);
    1876              :             } else {
    1877        34364 :                 firstPos = stopPos;
    1878              :             }
    1879              :         }
    1880        85741 :         lastPos = stopPos;
    1881        85741 :         if (stop.pars.jump >= 0) {
    1882         1208 :             jumps.insert((int)result.size() - 1);
    1883              :         }
    1884              :     }
    1885              :     //std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
    1886              :     //for (auto item : result) {
    1887              :     //    std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
    1888              :     //}
    1889      3118591 :     return result;
    1890            0 : }
    1891              : 
    1892              : 
    1893              : double
    1894         2115 : MSBaseVehicle::addStopPriority(double p1, double p2) {
    1895         2115 :     if (p1 < 0 || p2 < 0) {
    1896              :         return p1;
    1897              :     }
    1898            0 :     return p1 + p2;
    1899              : }
    1900              : 
    1901              : std::vector<std::pair<int, double> >
    1902        41168 : MSBaseVehicle::getStopIndices() const {
    1903              :     std::vector<std::pair<int, double> > result;
    1904        83433 :     for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
    1905        84530 :         result.push_back(std::make_pair(
    1906        42265 :                              (int)(iter->edge - myRoute->begin()),
    1907        42265 :                              iter->getEndPos(*this)));
    1908              :     }
    1909        41168 :     return result;
    1910            0 : }
    1911              : 
    1912              : 
    1913              : const MSStop&
    1914     15617761 : MSBaseVehicle::getNextStop() const {
    1915              :     assert(myStops.size() > 0);
    1916     15617761 :     return myStops.front();
    1917              : }
    1918              : 
    1919              : MSStop&
    1920        95396 : MSBaseVehicle::getNextStopMutable() {
    1921              :     assert(myStops.size() > 0);
    1922        95396 :     return myStops.front();
    1923              : }
    1924              : 
    1925              : SUMOTime
    1926      3646964 : MSBaseVehicle::getStopDuration() const {
    1927      3646964 :     if (isStopped()) {
    1928      1181984 :         return myStops.front().duration;
    1929              :     } else {
    1930              :         return 0;
    1931              :     }
    1932              : }
    1933              : 
    1934              : 
    1935              : MSStop&
    1936       325119 : MSBaseVehicle::getStop(int nextStopIndex) {
    1937       325119 :     if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
    1938            0 :         throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
    1939              :     }
    1940              :     auto stopIt = myStops.begin();
    1941              :     std::advance(stopIt, nextStopIndex);
    1942       325119 :     return *stopIt;
    1943              : }
    1944              : 
    1945              : 
    1946              : const SUMOVehicleParameter::Stop*
    1947       256429 : MSBaseVehicle::getNextStopParameter() const {
    1948       256429 :     if (hasStops()) {
    1949       114638 :         return &myStops.front().pars;
    1950              :     }
    1951              :     return nullptr;
    1952              : }
    1953              : 
    1954              : 
    1955              : bool
    1956        44019 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    1957              :     //if the stop exists update the duration
    1958        68357 :     for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
    1959        46000 :         if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
    1960              :             // update existing stop
    1961        21662 :             if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
    1962        20192 :                 myStops.erase(iter);
    1963              :             } else {
    1964         1470 :                 iter->duration = stop.duration;
    1965         1470 :                 iter->triggered = stop.triggered;
    1966         1470 :                 iter->containerTriggered = stop.containerTriggered;
    1967         1470 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
    1968         1470 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
    1969              :             }
    1970              :             return true;
    1971              :         }
    1972              :     }
    1973        22357 :     const bool result = addStop(stop, errorMsg);
    1974        22357 :     if (result) {
    1975              :         /// XXX handle stops added out of order
    1976        22338 :         myParameter->stops.push_back(stop);
    1977              :     }
    1978              :     return result;
    1979              : }
    1980              : 
    1981              : 
    1982              : void
    1983          748 : MSBaseVehicle::unregisterWaiting() {
    1984          748 :     if (myAmRegisteredAsWaiting) {
    1985          548 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1986          548 :         myAmRegisteredAsWaiting = false;
    1987              :     }
    1988          748 : }
    1989              : 
    1990              : 
    1991              : bool
    1992         1642 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
    1993         1642 :     if (hasStops() && nextStopIndex < (int)myStops.size()) {
    1994         1642 :         if (nextStopIndex == 0 && isStopped()) {
    1995          700 :             resumeFromStopping();
    1996              :         } else {
    1997              :             auto stopIt = myStops.begin();
    1998              :             std::advance(stopIt, nextStopIndex);
    1999          942 :             if (stopIt->parkingarea != nullptr && stopIt->parkingarea->isReservable()) {
    2000            0 :                 stopIt->parkingarea->removeSpaceReservation(this);
    2001              :             }
    2002          942 :             myStops.erase(stopIt);
    2003              :         }
    2004         1642 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2005              :             // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
    2006              :             auto stopIt2 = myParameter->stops.begin();
    2007              :             std::advance(stopIt2, nextStopIndex);
    2008            8 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
    2009              :         }
    2010         1642 :         return true;
    2011              :     } else {
    2012              :         return false;
    2013              :     }
    2014              : }
    2015              : 
    2016              : 
    2017              : bool
    2018          148 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2019          148 :     const int n = (int)myStops.size();
    2020          148 :     if (nextStopIndex < 0 || nextStopIndex >= n) {
    2021            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2022            5 :         return false;
    2023              :     }
    2024          143 :     if (nextStopIndex == 0 && isStopped()) {
    2025            7 :         errorMsg = TL("cannot replace reached stop");
    2026            7 :         return false;
    2027              :     }
    2028          136 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2029          136 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2030          136 :     MSEdge* stopEdge = &stopLane->getEdge();
    2031              : 
    2032              :     auto itStop = myStops.begin();
    2033              :     std::advance(itStop, nextStopIndex);
    2034              :     MSStop& replacedStop = *itStop;
    2035              : 
    2036              :     // check parking access rights
    2037          136 :     if (stop.parkingarea != "") {
    2038            0 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2039            0 :         if (pa != nullptr && !pa->accepts(this)) {
    2040            0 :             errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
    2041            0 :             return false;
    2042              :         }
    2043              :     }
    2044              : 
    2045          136 :     if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
    2046              :         // only replace stop attributes
    2047           10 :         const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2048           10 :         replacedStop.initPars(stop);
    2049           10 :         return true;
    2050              :     }
    2051              : 
    2052          126 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2053            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2054            0 :         return false;
    2055              :     }
    2056              : 
    2057          126 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2058          126 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2059          126 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2060          126 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2061          126 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2062          126 :     MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
    2063          126 :     auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
    2064          126 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2065              : 
    2066          126 :     bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
    2067              : 
    2068              :     ConstMSEdgeVector toNewStop;
    2069          126 :     if (!teleport) {
    2070           97 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2071           97 :         if (toNewStop.size() == 0) {
    2072           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2073            5 :             return false;
    2074              :         }
    2075              :     }
    2076              : 
    2077              :     ConstMSEdgeVector fromNewStop;
    2078          121 :     if (!newDestination) {
    2079          116 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2080          116 :         if (fromNewStop.size() == 0) {
    2081            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2082            0 :             return false;
    2083              :         }
    2084              :     }
    2085              : 
    2086          121 :     cleanupParkingReservation();
    2087          121 :     const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2088          121 :     replacedStop.initPars(stop);
    2089          121 :     replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
    2090          121 :     replacedStop.lane = stopLane;
    2091          121 :     if (MSGlobals::gUseMesoSim) {
    2092           22 :         replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
    2093           22 :         if (replacedStop.lane->isInternal()) {
    2094            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2095            0 :             return false;
    2096              :         }
    2097              :     }
    2098              : 
    2099          121 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2100              :     ConstMSEdgeVector newEdges; // only remaining
    2101          121 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2102          121 :     if (!teleport) {
    2103           92 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2104              :     } else {
    2105           29 :         newEdges.push_back(*itStart);
    2106              :     }
    2107          121 :     if (!newDestination) {
    2108          116 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2109          116 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2110              :     } else {
    2111            5 :         newEdges.push_back(stopEdge);
    2112              :     }
    2113              :     //std::cout << SIMTIME << " replaceStop veh=" << getID()
    2114              :     //    << " teleport=" << teleport
    2115              :     //    << " busStop=" << stop.busstop
    2116              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2117              :     //    << " newEdges=" << newEdges.size()
    2118              :     //    << " toNewStop=" << toNewStop.size()
    2119              :     //    << " fromNewStop=" << fromNewStop.size()
    2120              :     //    << "\n";
    2121              : 
    2122          121 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2123          121 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2124          121 :     const double savings = previousCost - routeCost;
    2125          121 :     if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2126              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2127            5 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
    2128              :     }
    2129          121 :     if (teleport) {
    2130              :         // let the vehicle jump rather than teleport
    2131              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2132              :         // already configure to jump before the replaced stop)
    2133           29 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2134              :             return false;
    2135              :         };
    2136              :     }
    2137          121 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2138          126 : }
    2139              : 
    2140              : 
    2141              : bool
    2142           52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
    2143           52 :     const int n = (int)myStops.size();
    2144           52 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2145            0 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2146            0 :         return false;
    2147              :     }
    2148           52 :     if (nextStopIndex == 0 && isStopped()) {
    2149            0 :         errorMsg = TL("cannot reroute towards reached stop");
    2150            0 :         return false;
    2151              :     }
    2152           52 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2153              : 
    2154           52 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2155           52 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2156           52 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2157           52 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2158           52 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2159           52 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2160           52 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2161           52 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2162              : 
    2163              :     ConstMSEdgeVector newBetween;
    2164           52 :     if (!teleport) {
    2165           15 :         router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
    2166           15 :         if (newBetween.size() == 0) {
    2167            0 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
    2168            0 :             return false;
    2169              :         }
    2170              :     }
    2171              : 
    2172           52 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2173              :     ConstMSEdgeVector newEdges; // only remaining
    2174           52 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2175           52 :     if (!teleport) {
    2176           15 :         newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
    2177              :     } else {
    2178           37 :         newEdges.push_back(*itStart);
    2179              :     }
    2180           52 :     newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2181              :     //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
    2182              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2183              :     //    << " newEdges=" << newEdges.size()
    2184              :     //    << " toNewStop=" << toNewStop.size()
    2185              :     //    << " fromNewStop=" << fromNewStop.size()
    2186              :     //    << "\n";
    2187              : 
    2188           52 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2189           52 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2190           52 :     const double savings = previousCost - routeCost;
    2191              : 
    2192           52 :     if (teleport) {
    2193              :         // let the vehicle jump rather than teleport
    2194              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2195              :         // already configure to jump before the replaced stop)
    2196           37 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2197              :             return false;
    2198              :         };
    2199              :     }
    2200           52 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2201           52 : }
    2202              : 
    2203              : 
    2204              : bool
    2205           66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
    2206              :     bool needJump = true;
    2207           66 :     if (nextStopIndex > 0) {
    2208              :         auto itPriorStop = myStops.begin();
    2209           48 :         std::advance(itPriorStop, nextStopIndex - 1);
    2210              :         const MSStop& priorStop = *itPriorStop;
    2211           48 :         if (priorStop.pars.jump >= 0) {
    2212              :             needJump = false;
    2213              :         }
    2214              :     }
    2215              :     if (needJump) {
    2216           47 :         SUMOVehicleParameter::Stop jumpStopPars;
    2217           47 :         jumpStopPars.endPos = (*itStart)->getLength();
    2218           47 :         jumpStopPars.speed = 1000;
    2219           47 :         jumpStopPars.jump = 0;
    2220              :         jumpStopPars.edge = (*itStart)->getID();
    2221           47 :         jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
    2222              :         MSLane* jumpStopLane = nullptr;
    2223           47 :         for (MSLane* cand : (*itStart)->getLanes()) {
    2224           47 :             if (cand->allowsVehicleClass(getVClass())) {
    2225              :                 jumpStopLane = cand;
    2226              :                 break;
    2227              :             }
    2228              :         }
    2229           47 :         if (jumpStopLane == nullptr) {
    2230            0 :             errorMsg = TL("unable to replace stop with teleporting");
    2231              :             return false;
    2232              :         }
    2233              :         auto itStop = myStops.begin();
    2234              :         std::advance(itStop, nextStopIndex);
    2235           47 :         MSStop jumpStop(jumpStopPars);
    2236           47 :         jumpStop.initPars(jumpStopPars);
    2237           47 :         jumpStop.lane = jumpStopLane;
    2238           47 :         jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
    2239           47 :         myStops.insert(itStop, jumpStop);
    2240           47 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2241              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2242              :             auto it = myParameter->stops.begin() + nextStopIndex;
    2243            0 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
    2244              :         }
    2245           47 :     }
    2246              :     return true;
    2247              : }
    2248              : 
    2249              : 
    2250              : bool
    2251          811 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2252          811 :     const int n = (int)myStops.size();
    2253          811 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2254            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2255            5 :         return false;
    2256              :     }
    2257          806 :     if (nextStopIndex == 0 && isStopped()) {
    2258            7 :         errorMsg = TL("cannot insert stop before the currently reached stop");
    2259            7 :         return false;
    2260              :     }
    2261          799 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2262          799 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2263          799 :     MSEdge* stopEdge = &stopLane->getEdge();
    2264              : 
    2265          799 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2266            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2267            0 :         return false;
    2268              :     }
    2269              : 
    2270              :     // check parking access rights
    2271          799 :     if (stop.parkingarea != "") {
    2272          576 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2273          576 :         if (pa != nullptr && !pa->accepts(this)) {
    2274            0 :             errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
    2275            0 :             return false;
    2276              :         }
    2277              :     }
    2278              : 
    2279          799 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2280          799 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2281         1437 :     const int junctionOffset = ((getLane() != nullptr && getLane()->isInternal())
    2282         1433 :             || getRerouteOrigin() != getCurrentRouteEdge()) ? 1 : 0;
    2283          799 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2284          799 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2285          799 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2286          799 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2287          799 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2288              : 
    2289          799 :     bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
    2290              : 
    2291              :     ConstMSEdgeVector toNewStop;
    2292          799 :     if (!teleport) {
    2293          771 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2294          771 :         if (toNewStop.size() == 0) {
    2295           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2296            5 :             return false;
    2297              :         }
    2298              :     }
    2299              : 
    2300              :     ConstMSEdgeVector fromNewStop;
    2301          794 :     if (!newDestination) {
    2302          574 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2303          574 :         if (fromNewStop.size() == 0) {
    2304            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2305            0 :             return false;
    2306              :         }
    2307              :     }
    2308              : 
    2309              :     auto itStop = myStops.begin();
    2310              :     std::advance(itStop, nextStopIndex);
    2311          794 :     MSStop newStop(stop);
    2312          794 :     newStop.initPars(stop);
    2313          794 :     newStop.edge = myRoute->end(); // will be patched in replaceRoute
    2314          794 :     newStop.lane = stopLane;
    2315          794 :     if (MSGlobals::gUseMesoSim) {
    2316          148 :         newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
    2317          148 :         if (newStop.lane->isInternal()) {
    2318            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2319            0 :             return false;
    2320              :         }
    2321              :     }
    2322          794 :     myStops.insert(itStop, newStop);
    2323              : 
    2324          794 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2325              :     ConstMSEdgeVector newEdges; // only remaining
    2326          794 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2327          794 :     if (!teleport) {
    2328          766 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2329              :     } else {
    2330           28 :         newEdges.push_back(*itStart);
    2331              :     }
    2332          794 :     if (!newDestination) {
    2333          574 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2334          574 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2335              :     } else {
    2336          220 :         newEdges.push_back(stopEdge);
    2337              :     }
    2338              :     //std::cout << SIMTIME << " insertStop veh=" << getID()
    2339              :     //    << " teleport=" << teleport
    2340              :     //    << " busStop=" << stop.busstop
    2341              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2342              :     //    << " newEdges=" << newEdges.size()
    2343              :     //    << " toNewStop=" << toNewStop.size()
    2344              :     //    << " fromNewStop=" << fromNewStop.size()
    2345              :     //    << "\n";
    2346              : 
    2347          794 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2348          794 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2349          794 :     const double savings = previousCost - routeCost;
    2350              : 
    2351          794 :     if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2352              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2353              :         auto it = myParameter->stops.begin() + nextStopIndex;
    2354           15 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2355              :     }
    2356          794 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2357         1593 : }
    2358              : 
    2359              : 
    2360              : EnergyParams*
    2361    106282178 : MSBaseVehicle::getEmissionParameters() const {
    2362    106282178 :     if (myEnergyParams == nullptr) {
    2363      1065582 :         myEnergyParams = new EnergyParams(getVehicleType().getEmissionParameters());
    2364              :         double tMass = 0;
    2365      1065582 :         if (myPersonDevice != nullptr) {
    2366           16 :             for (MSTransportable* t : myPersonDevice->getTransportables()) {
    2367           16 :                 tMass += t->getVehicleType().getMass();
    2368              :             }
    2369              :         }
    2370      1065582 :         if (myContainerDevice != nullptr) {
    2371            0 :             for (MSTransportable* t : myContainerDevice->getTransportables()) {
    2372            0 :                 tMass += t->getVehicleType().getMass();
    2373              :             }
    2374              :         }
    2375      1065582 :         myEnergyParams->setTransportableMass(tMass);
    2376              :     }
    2377    106282178 :     return myEnergyParams;
    2378              : }
    2379              : 
    2380              : 
    2381              : double
    2382            0 : MSBaseVehicle::getStateOfCharge() const {
    2383            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2384            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2385            0 :         return batteryOfVehicle->getActualBatteryCapacity();
    2386              :     } else {
    2387            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2388            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2389            0 :             return batteryOfVehicle->getActualBatteryCapacity();
    2390              :         }
    2391              :     }
    2392              :     return -1;
    2393              : }
    2394              : 
    2395              : 
    2396              : double
    2397            0 : MSBaseVehicle::getRelativeStateOfCharge() const {
    2398            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2399            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2400            0 :         return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2401              :     } else {
    2402            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2403            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2404            0 :             return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2405              :         }
    2406              :     }
    2407              :     return -1;
    2408              : }
    2409              : 
    2410              : 
    2411              : double
    2412            0 : MSBaseVehicle::getChargedEnergy() const {
    2413            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2414            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2415            0 :         return batteryOfVehicle->getEnergyCharged();
    2416              :     } else {
    2417            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2418            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2419            0 :             return batteryOfVehicle->getEnergyCharged();
    2420              :         }
    2421              :     }
    2422              :     return -1;
    2423              : }
    2424              : 
    2425              : 
    2426              : double
    2427            0 : MSBaseVehicle::getMaxChargeRate() const {
    2428            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2429            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2430            0 :         return batteryOfVehicle->getMaximumChargeRate();
    2431              :     }
    2432              :     return -1;
    2433              : }
    2434              : 
    2435              : 
    2436              : double
    2437            0 : MSBaseVehicle::getElecHybridCurrent() const {
    2438            0 :     if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2439            0 :         MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2440            0 :         return elecHybridDevice->getCurrentFromOverheadWire();
    2441              :     }
    2442              : 
    2443              :     return NAN;
    2444              : }
    2445              : 
    2446              : double
    2447          766 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
    2448          766 :     if (isOnRoad() || isIdling()) {
    2449          766 :         return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
    2450              :     } else {
    2451              :         return 0.;
    2452              :     }
    2453              : }
    2454              : 
    2455              : 
    2456              : const MSEdgeWeightsStorage&
    2457      6548138 : MSBaseVehicle::getWeightsStorage() const {
    2458      6548138 :     return _getWeightsStorage();
    2459              : }
    2460              : 
    2461              : 
    2462              : MSEdgeWeightsStorage&
    2463          666 : MSBaseVehicle::getWeightsStorage() {
    2464          666 :     return _getWeightsStorage();
    2465              : }
    2466              : 
    2467              : 
    2468              : MSEdgeWeightsStorage&
    2469      6548804 : MSBaseVehicle::_getWeightsStorage() const {
    2470      6548804 :     if (myEdgeWeights == nullptr) {
    2471        13931 :         myEdgeWeights = new MSEdgeWeightsStorage();
    2472              :     }
    2473      6548804 :     return *myEdgeWeights;
    2474              : }
    2475              : 
    2476              : 
    2477              : 
    2478              : 
    2479              : int
    2480      8407046 : MSBaseVehicle::getPersonNumber() const {
    2481      8407046 :     int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
    2482      8407046 :     return boarded + myParameter->personNumber;
    2483              : }
    2484              : 
    2485              : int
    2486            0 : MSBaseVehicle::getLeavingPersonNumber() const {
    2487              :     int leavingPersonNumber = 0;
    2488            0 :     const std::vector<MSTransportable*>& persons = getPersons();
    2489            0 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2490            0 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
    2491              :         const MSStop* stop = &myStops.front();
    2492            0 :         const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
    2493            0 :         if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
    2494            0 :             leavingPersonNumber++;
    2495              :         }
    2496              :     }
    2497            0 :     return leavingPersonNumber;
    2498              : }
    2499              : 
    2500              : std::vector<std::string>
    2501          172 : MSBaseVehicle::getPersonIDList() const {
    2502              :     std::vector<std::string> ret;
    2503          172 :     const std::vector<MSTransportable*>& persons = getPersons();
    2504          531 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2505          359 :         ret.push_back((*it_p)->getID());
    2506              :     }
    2507          172 :     return ret;
    2508            0 : }
    2509              : 
    2510              : int
    2511      9236717 : MSBaseVehicle::getContainerNumber() const {
    2512      9236717 :     int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
    2513      9236717 :     return loaded + myParameter->containerNumber;
    2514              : }
    2515              : 
    2516              : 
    2517              : void
    2518          166 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
    2519              :     // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
    2520          166 :     if (myPersonDevice != nullptr) {
    2521          146 :         myPersonDevice->removeTransportable(t);
    2522              :     }
    2523          166 :     if (myContainerDevice != nullptr) {
    2524           20 :         myContainerDevice->removeTransportable(t);
    2525              :     }
    2526          166 :     if (myEnergyParams != nullptr) {
    2527           86 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2528              :     }
    2529          166 : }
    2530              : 
    2531              : 
    2532              : void
    2533         9462 : MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
    2534         9462 :     if (myEnergyParams != nullptr) {
    2535         6150 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2536              :     }
    2537         9462 : }
    2538              : 
    2539              : 
    2540              : const std::vector<MSTransportable*>&
    2541     11369579 : MSBaseVehicle::getPersons() const {
    2542     11369579 :     if (myPersonDevice == nullptr) {
    2543              :         return myEmptyTransportableVector;
    2544              :     } else {
    2545        13718 :         return myPersonDevice->getTransportables();
    2546              :     }
    2547              : }
    2548              : 
    2549              : 
    2550              : const std::vector<MSTransportable*>&
    2551     10115760 : MSBaseVehicle::getContainers() const {
    2552     10115760 :     if (myContainerDevice == nullptr) {
    2553              :         return myEmptyTransportableVector;
    2554              :     } else {
    2555         3290 :         return myContainerDevice->getTransportables();
    2556              :     }
    2557              : }
    2558              : 
    2559              : 
    2560              : bool
    2561          210 : MSBaseVehicle::isLineStop(double position) const {
    2562          210 :     if (myParameter->line == "") {
    2563              :         // not a public transport line
    2564              :         return false;
    2565              :     }
    2566          362 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    2567          215 :         if (stop.startPos <= position && position <= stop.endPos) {
    2568              :             return true;
    2569              :         }
    2570              :     }
    2571          175 :     for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    2572           39 :         if (stop.startPos <= position && position <= stop.endPos) {
    2573              :             return true;
    2574              :         }
    2575              :     }
    2576              :     return false;
    2577              : }
    2578              : 
    2579              : 
    2580              : bool
    2581           45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
    2582          144 :     for (MSDevice* const dev : myDevices) {
    2583          126 :         if (dev->deviceName() == deviceName) {
    2584              :             return true;
    2585              :         }
    2586              :     }
    2587              :     return false;
    2588              : }
    2589              : 
    2590              : 
    2591              : void
    2592            9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
    2593            9 :     if (!hasDevice(deviceName)) {
    2594            9 :         if (deviceName == "rerouting") {
    2595           27 :             ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
    2596            9 :             MSDevice_Routing::buildVehicleDevices(*this, myDevices);
    2597            9 :             if (hasDeparted()) {
    2598              :                 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
    2599            0 :                 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
    2600              :                 assert(routingDevice != 0);
    2601            0 :                 routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
    2602              :             }
    2603              :         } else {
    2604            0 :             throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
    2605              :         }
    2606              :     }
    2607            9 : }
    2608              : 
    2609              : 
    2610              : std::string
    2611        50193 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
    2612        59908 :     for (MSVehicleDevice* const dev : myDevices) {
    2613        59899 :         if (dev->deviceName() == deviceName) {
    2614        50184 :             return dev->getParameter(key);
    2615              :         }
    2616              :     }
    2617           27 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2618              : }
    2619              : 
    2620              : 
    2621              : void
    2622          208 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
    2623          355 :     for (MSVehicleDevice* const dev : myDevices) {
    2624          355 :         if (dev->deviceName() == deviceName) {
    2625          208 :             dev->setParameter(key, value);
    2626          208 :             return;
    2627              :         }
    2628              :     }
    2629            0 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2630              : }
    2631              : 
    2632              : 
    2633              : void
    2634          842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
    2635         1669 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
    2636          837 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
    2637          837 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2638              :         // checked in MSLink::ignoreFoe
    2639              :     } else {
    2640           15 :         throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
    2641              :     }
    2642          837 : }
    2643              : 
    2644              : 
    2645              : void
    2646           38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
    2647              :     // handle some generic params first and then delegate to the carFollowModel itself
    2648           67 :     if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
    2649           17 :         getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
    2650           17 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2651              :         // checked in MSVehicle::planMove
    2652              :     } else {
    2653           21 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
    2654           21 :         if (microVeh) {
    2655              :             // remove 'carFollowModel.' prefix
    2656           21 :             const std::string attrName = key.substr(15);
    2657           21 :             microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
    2658              :         }
    2659              :     }
    2660           33 : }
    2661              : 
    2662              : 
    2663              : void
    2664      5537930 : MSBaseVehicle::initTransientModelParams() {
    2665              :     /* Design idea for additional junction model parameters:
    2666              :        We can distinguish between 3 levels of parameters
    2667              :        1. typically shared by multiple vehicles -> vType parameter
    2668              :        2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
    2669              :        3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
    2670              :        */
    2671      5811748 :     for (auto item : getParameter().getParametersMap()) {
    2672       547636 :         if (StringUtils::startsWith(item.first, "junctionModel.")) {
    2673          832 :             setJunctionModelParameter(item.first, item.second);
    2674       545972 :         } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
    2675           17 :             setCarFollowModelParameter(item.first, item.second);
    2676              :         }
    2677              :     }
    2678     11075860 :     const std::string routingModeStr = getStringParam("device.rerouting.mode");
    2679              :     try {
    2680      5537930 :         int routingMode = StringUtils::toInt(routingModeStr);
    2681      5537930 :         if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
    2682              :             setRoutingMode(routingMode);
    2683              :         }
    2684            0 :     } catch (NumberFormatException&) {
    2685              :         // @todo interpret symbolic constants
    2686            0 :         throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
    2687            0 :     }
    2688      5537930 : }
    2689              : 
    2690              : 
    2691              : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
    2692        22485 : MSBaseVehicle::getRouterTT() const {
    2693        22485 :     if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
    2694          204 :         return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
    2695              :     } else {
    2696        44766 :         return MSNet::getInstance()->getRouterTT(getRNGIndex());
    2697              :     }
    2698              : }
    2699              : 
    2700              : 
    2701              : void
    2702        30688 : MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
    2703              :     assert(type != nullptr);
    2704              :     // save old parameters before possible type deletion
    2705        30688 :     const double oldMu = myType->getSpeedFactor().getParameter(0);
    2706              :     const double oldDev = myType->getSpeedFactor().getParameter(1);
    2707        30688 :     if (myType->isVehicleSpecific() && type != myType) {
    2708          938 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    2709              :     }
    2710              :     // adapt myChosenSpeedFactor to the new type
    2711        30688 :     if (oldDev == 0.) {
    2712              :         // old type had speedDev 0, reroll
    2713        22808 :         myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
    2714              :     } else {
    2715              :         // map old speedFactor onto new distribution
    2716         7880 :         const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
    2717              :         const double newMu = type->getSpeedFactor().getParameter(0);
    2718              :         const double newDev = type->getSpeedFactor().getParameter(1);
    2719         7880 :         myChosenSpeedFactor = newMu + distPoint * newDev;
    2720              :         // respect distribution limits
    2721         7880 :         myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
    2722         7885 :         myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
    2723              :     }
    2724        30688 :     myType = type;
    2725        30688 :     if (myEnergyParams != nullptr) {
    2726              :         myEnergyParams->setSecondary(type->getEmissionParameters());
    2727              :     }
    2728        30688 : }
    2729              : 
    2730              : 
    2731              : MSVehicleType&
    2732       145089 : MSBaseVehicle::getSingularType() {
    2733       145089 :     if (myType->isVehicleSpecific()) {
    2734              :         return *const_cast<MSVehicleType*>(myType);
    2735              :     }
    2736         2536 :     MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
    2737         1267 :     replaceVehicleType(type);
    2738         1267 :     return *type;
    2739              : }
    2740              : 
    2741              : 
    2742              : int
    2743       890847 : MSBaseVehicle::getRNGIndex() const {
    2744       890847 :     const MSLane* const lane = getLane();
    2745       890847 :     if (lane == nullptr) {
    2746        18349 :         return getEdge()->getLanes()[0]->getRNGIndex();
    2747              :     } else {
    2748       872498 :         return lane->getRNGIndex();
    2749              :     }
    2750              : }
    2751              : 
    2752              : 
    2753              : SumoRNG*
    2754    746893392 : MSBaseVehicle::getRNG() const {
    2755    746893392 :     const MSLane* lane = getLane();
    2756    746893392 :     if (lane == nullptr) {
    2757         7085 :         return getEdge()->getLanes()[0]->getRNG();
    2758              :     } else {
    2759    746886307 :         return lane->getRNG();
    2760              :     }
    2761              : }
    2762              : 
    2763              : std::string
    2764        69140 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
    2765        69140 :     const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
    2766       138280 :     if (StringUtils::startsWith(key, "device.")) {
    2767       150579 :         StringTokenizer tok(key, ".");
    2768        50193 :         if (tok.size() < 3) {
    2769            0 :             error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
    2770            0 :             return "";
    2771              :         }
    2772              :         try {
    2773       150579 :             return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
    2774           18 :         } catch (InvalidArgument& e) {
    2775           54 :             error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
    2776           18 :             return "";
    2777           18 :         }
    2778        88087 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2779          324 :         if (microVeh == nullptr) {
    2780           36 :             error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
    2781           18 :             return "";
    2782              :         }
    2783          306 :         const std::string attrName = key.substr(16);
    2784              :         try {
    2785          306 :             return microVeh->getLaneChangeModel().getParameter(attrName);
    2786           44 :         } catch (InvalidArgument& e) {
    2787          132 :             error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
    2788           44 :             return "";
    2789           44 :         }
    2790        37246 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2791           16 :         if (microVeh == nullptr) {
    2792            0 :             error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
    2793            0 :             return "";
    2794              :         }
    2795           16 :         const std::string attrName = key.substr(15);
    2796              :         try {
    2797           16 :             return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
    2798            0 :         } catch (InvalidArgument& e) {
    2799            0 :             error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
    2800            0 :             return "";
    2801            0 :         }
    2802        18643 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2803          108 :         StringTokenizer tok(key, ".");
    2804           36 :         if (tok.size() != 3) {
    2805            0 :             error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
    2806            0 :             return "";
    2807              :         }
    2808           81 :         return hasDevice(tok.get(1)) ? "true" : "false";
    2809              :         // parking related parameters start here
    2810        18607 :     } else if (key == "parking.rerouteCount") {
    2811           15 :         return toString(getNumberParkingReroutes());
    2812        37112 :     } else if (StringUtils::startsWith(key, "parking.memory.")) {
    2813              :         std::vector<std::string> values;
    2814           65 :         if (getParkingMemory()) {
    2815           25 :             if (key == "parking.memory.IDList") {
    2816           30 :                 for (const auto& item : *getParkingMemory()) {
    2817           25 :                     values.push_back(item.first->getID());
    2818              :                 }
    2819           20 :             } else if (key == "parking.memory.score") {
    2820           30 :                 for (const auto& item : *getParkingMemory()) {
    2821           25 :                     values.push_back(item.second.score);
    2822              :                 }
    2823           15 :             } else if (key == "parking.memory.blockedAtTime") {
    2824           30 :                 for (const auto& item : *getParkingMemory()) {
    2825           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
    2826              :                 }
    2827           10 :             } else if (key == "parking.memory.blockedAtTimeLocal") {
    2828           30 :                 for (const auto& item : *getParkingMemory()) {
    2829           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
    2830              :                 }
    2831              :             } else {
    2832           10 :                 error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
    2833              :             }
    2834              :         }
    2835           65 :         return toString(values);
    2836           65 :     } else {
    2837              :         // default: custom user parameter
    2838        36982 :         return getParameter().getParameter(key, "");
    2839              :     }
    2840              : }
    2841              : 
    2842              : 
    2843              : void
    2844        89206 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
    2845        89206 :     if (myParkingMemory == nullptr) {
    2846            0 :         myParkingMemory = new StoppingPlaceMemory();
    2847              :     }
    2848        89206 :     myParkingMemory->rememberBlockedStoppingPlace(pa, local);
    2849        89206 : }
    2850              : 
    2851              : 
    2852              : void
    2853        29564 : MSBaseVehicle::resetParkingAreaScores() {
    2854        29564 :     if (myParkingMemory != nullptr) {
    2855        27728 :         myParkingMemory->resetStoppingPlaceScores();
    2856              :     }
    2857        29564 : }
    2858              : 
    2859              : 
    2860              : void
    2861          360 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
    2862          360 :     if (myChargingMemory == nullptr) {
    2863           80 :         myChargingMemory = new StoppingPlaceMemory();
    2864              :     }
    2865          360 :     myChargingMemory->rememberStoppingPlaceScore(cs, score);
    2866          360 : }
    2867              : 
    2868              : 
    2869              : void
    2870          127 : MSBaseVehicle::resetChargingStationScores() {
    2871          127 :     if (myChargingMemory != nullptr) {
    2872           11 :         myChargingMemory->resetStoppingPlaceScores();
    2873              :     }
    2874          127 : }
    2875              : 
    2876              : 
    2877              : void
    2878       131724 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
    2879       131724 :     if (myParkingMemory == nullptr) {
    2880         2357 :         myParkingMemory = new StoppingPlaceMemory();
    2881              :     }
    2882       131724 :     myParkingMemory->rememberStoppingPlaceScore(pa, score);
    2883       131724 : }
    2884              : 
    2885              : 
    2886              : SUMOTime
    2887        71557 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
    2888        71557 :     if (myParkingMemory == nullptr) {
    2889              :         return -1;
    2890              :     }
    2891        71533 :     return myParkingMemory->sawBlockedStoppingPlace(pa, local);
    2892              : }
    2893              : 
    2894              : 
    2895            0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
    2896            0 :     if (myChargingMemory == nullptr) {
    2897            0 :         myChargingMemory = new StoppingPlaceMemory();
    2898              :     }
    2899            0 :     myChargingMemory->rememberBlockedStoppingPlace(cs, local);
    2900            0 : }
    2901              : 
    2902              : 
    2903              : SUMOTime
    2904          548 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
    2905          548 :     if (myChargingMemory == nullptr) {
    2906              :         return -1;
    2907              :     }
    2908           72 :     return myChargingMemory->sawBlockedStoppingPlace(cs, local);
    2909              : }
    2910              : 
    2911              : 
    2912              : void
    2913      4779560 : MSBaseVehicle::cleanupParkingReservation() {
    2914      4779560 :     if (hasStops() && myStops.front().parkingarea != nullptr && myStops.front().parkingarea->isReservable()) {
    2915            0 :         myStops.front().parkingarea->removeSpaceReservation(this);
    2916              :     }
    2917      4779560 : }
    2918              : 
    2919              : 
    2920              : #ifdef _DEBUG
    2921              : void
    2922              : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
    2923              :     if (oc.isSet("movereminder-output.vehicles")) {
    2924              :         const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
    2925              :         myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
    2926              :     }
    2927              : }
    2928              : 
    2929              : 
    2930              : void
    2931              : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
    2932              :     OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
    2933              :     od.openTag("movereminder");
    2934              :     od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
    2935              :     od.writeAttr("veh", getID());
    2936              :     od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
    2937              :     od.writeAttr("type", type);
    2938              :     od.writeAttr("pos", toString(pos));
    2939              :     od.writeAttr("keep", toString(keep));
    2940              :     od.closeTag();
    2941              : }
    2942              : #endif
    2943              : 
    2944              : 
    2945              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1