LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.5 % 1404 1257
Test Date: 2026-03-27 16:39:44 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         3485 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
      90         3485 : {}
      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      5557086 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
     103      5557086 :                              MSVehicleType* type, const double speedFactor) :
     104              :     SUMOVehicle(pars->id),
     105      5557086 :     myParameter(pars),
     106              :     myRoute(route),
     107      5557086 :     myType(type),
     108      5557086 :     myCurrEdge(route->begin()),
     109      5568317 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     110      5557086 :     myMoveReminders(0),
     111      5557086 :     myPersonDevice(nullptr),
     112      5557086 :     myContainerDevice(nullptr),
     113      5557086 :     myEnergyParams(nullptr),
     114      5557086 :     myDeparture(NOT_YET_DEPARTED),
     115      5557086 :     myDepartPos(-1),
     116      5557086 :     myArrivalPos(-1),
     117      5557086 :     myArrivalLane(-1),
     118      5557086 :     myNumberReroutes(0),
     119      5557086 :     myStopUntilOffset(0),
     120      5557086 :     myOdometer(0.),
     121      5557086 :     myRouteValidity(ROUTE_UNCHECKED),
     122      5557086 :     myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
     123      5557086 :     myNumericalID(myCurrentNumericalIndex++),
     124     11114172 :     myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
     125     11114172 :     myEdgeWeights(nullptr)
     126              : #ifdef _DEBUG
     127              :     , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
     128              : #endif
     129              : {
     130      5557086 :     if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
     131       577706 :         pars->parametersSet |= VEHPARS_FORCE_REROUTE;
     132              :     }
     133      5557086 :     if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
     134      4005898 :         setDepartAndArrivalEdge();
     135              :     }
     136      5557086 :     calculateArrivalParams(true);
     137      5557086 :     initTransientModelParams();
     138      5557086 : }
     139              : 
     140              : 
     141      5556991 : MSBaseVehicle::~MSBaseVehicle() {
     142      5556991 :     delete myEdgeWeights;
     143      5556991 :     if (myParameter->repetitionNumber == -1) {
     144              :         // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
     145       460327 :         MSRoute::checkDist(myParameter->routeid);
     146              :     }
     147      9707573 :     for (MSVehicleDevice* dev : myDevices) {
     148      4150582 :         delete dev;
     149              :     }
     150      5556991 :     delete myEnergyParams;
     151      5556991 :     delete myParkingMemory;
     152      5556991 :     delete myChargingMemory;
     153      5556991 :     checkRouteRemoval();
     154      5556991 :     delete myParameter;
     155      5556991 : }
     156              : 
     157              : 
     158              : void
     159     15234594 : 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     15234592 :     if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
     163       837226 :         myRoute->checkRemoval();
     164              :     }
     165      7617297 : }
     166              : 
     167              : 
     168              : std::string
     169      7617295 : MSBaseVehicle::getFlowID() const {
     170      7617295 :     return getID().substr(0, getID().rfind('.'));
     171              : }
     172              : 
     173              : 
     174              : void
     175      5557086 : MSBaseVehicle::initDevices() {
     176      5557086 :     MSDevice::buildVehicleDevices(*this, myDevices);
     177      9702634 :     for (MSVehicleDevice* dev : myDevices) {
     178      4145565 :         myMoveReminders.push_back(std::make_pair(dev, 0.));
     179              :     }
     180      5557069 :     if (MSGlobals::gHaveEmissions) {
     181              :         // ensure we have the emission parameters even if we don't have the device
     182      1061872 :         getEmissionParameters();
     183              :     }
     184      5557069 : }
     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  39030123137 : MSBaseVehicle::getParameter() const {
     194  39030123137 :     return *myParameter;
     195              : }
     196              : 
     197              : 
     198              : void
     199           54 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
     200           54 :     delete myParameter;
     201           54 :     myParameter = newParameter;
     202           54 : }
     203              : 
     204              : 
     205              : bool
     206   7658751995 : MSBaseVehicle::ignoreTransientPermissions() const {
     207   7658751995 :     return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
     208              : }
     209              : 
     210              : double
     211   6189967803 : MSBaseVehicle::getMaxSpeed() const {
     212   6189967803 :     return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
     213              : }
     214              : 
     215              : 
     216              : const MSEdge*
     217   2163736854 : MSBaseVehicle::succEdge(int nSuccs) const {
     218   2163736854 :     if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
     219   1539055438 :         return *(myCurrEdge + nSuccs);
     220              :     } else {
     221    624681416 :         return nullptr;
     222              :     }
     223              : }
     224              : 
     225              : 
     226              : const MSEdge*
     227   7787015347 : MSBaseVehicle::getEdge() const {
     228   7787015347 :     return *myCurrEdge;
     229              : }
     230              : 
     231              : 
     232              : const std::set<SUMOTrafficObject::NumericalID>
     233        65475 : MSBaseVehicle::getUpcomingEdgeIDs() const {
     234              :     std::set<SUMOTrafficObject::NumericalID> result;
     235       294663 :     for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
     236       229188 :         result.insert((*e)->getNumericalID());
     237              :     }
     238        65475 :     return result;
     239              : }
     240              : 
     241              : 
     242              : bool
     243      1226039 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
     244      1226039 :     if (stop == nullptr) {
     245              :         return false;
     246              :     }
     247      2413094 :     for (const MSStop& s : myStops) {
     248      2411555 :         if (s.busstop == stop
     249      2372702 :                 || s.containerstop == stop
     250      1187071 :                 || s.parkingarea == stop
     251      1187065 :                 || s.chargingStation == stop) {
     252              :             return true;
     253              :         }
     254              :     }
     255              :     return false;
     256              : }
     257              : 
     258              : bool
     259       189016 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
     260       398430 :     for (const MSStop& s : myStops) {
     261       368167 :         if (&s.lane->getEdge() == edge) {
     262              :             return true;
     263              :         }
     264              :     }
     265        30263 :     return myRoute->getLastEdge() == edge;
     266              : }
     267              : 
     268              : 
     269              : bool
     270      3129639 : 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      3129639 :     const MSEdge* source = nullptr;
     273      3129639 :     if (onInit) {
     274      2946867 :         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      2946338 :             source = myRoute->getEdges().front();
     281              :         }
     282              :     } else {
     283       182772 :         source = *getRerouteOrigin();
     284              :     }
     285      3129639 :     if (sink == nullptr) {
     286      3103140 :         sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
     287      3103140 :         if (sink == nullptr) {
     288            5 :             sink = myRoute->getLastEdge();
     289              :         }
     290              :     }
     291      3137982 :     ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
     292              :     ConstMSEdgeVector edges;
     293      3129639 :     if (source != sink || !sink->prohibits(this)) {
     294      3129633 :         edges.push_back(source);
     295              :     }
     296              :     std::vector<StopEdgeInfo> stops;
     297              :     std::set<int> jumps;
     298              : 
     299              : 
     300      3129639 :     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      2946867 :     if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
     307        86779 :         sourcePos = myParameter->departPos;
     308      3042860 :     } else if (getLane() != nullptr && source != &getLane()->getEdge()) {
     309              :         // routing starts on the next edge
     310              :         sourcePos = 0;
     311              :     }
     312      3129639 :     if (myParameter->via.size() == 0) {
     313      3119083 :         double firstPos = INVALID_DOUBLE;
     314      3119083 :         double lastPos = INVALID_DOUBLE;
     315      3119083 :         stops = getStopEdges(firstPos, lastPos, jumps);
     316      3119083 :         if (stops.size() > 0) {
     317        40706 :             if (MSGlobals::gUseMesoSim && isStopped()) {
     318          300 :                 sourcePos = getNextStop().pars.endPos;
     319              :             }
     320        40706 :             if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
     321        37550 :                 sourcePos += getBrakeGap();
     322              :             }
     323              :             // avoid superfluous waypoints for first and last edge
     324        40706 :             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        40706 :             if (stops.size() == 1 && skipFirst) {
     333              :                 stops.clear();
     334        33434 :             } else if (skipFirst) {
     335         8234 :                 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        27364 :         for (const MSStop& stop : myStops) {
     343        16808 :             if (stop.pars.jump >= 0) {
     344              :                 jumpEdges.insert(*stop.edge);
     345              :             }
     346              :             auto itsov = stopsOnVia.find(*stop.edge);
     347        16808 :             if (itsov == stopsOnVia.end()) {
     348        31842 :                 stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
     349              :             } else {
     350          887 :                 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        34169 :         for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
     356        23621 :             MSEdge* viaEdge = MSEdge::dictionary(*it);
     357        23621 :             if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
     358              :                 continue;
     359              :             }
     360              :             assert(viaEdge != 0);
     361        19540 :             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        19532 :             const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
     366        19532 :             const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
     367        19532 :             const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
     368        19532 :             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      3089623 :     if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
     376      3191460 :             || ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
     377      6093926 :         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      3129631 :     const MSEdge* origSource = source;
     393     15648155 :     const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
     394      6265947 :     for (auto& stopEdgeInfo : stops) {
     395      3136321 :         const MSEdge* const stopEdge = stopEdgeInfo.edge;
     396      3136321 :         const double priority = stopEdgeInfo.priority;
     397      3136321 :         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      3137295 :         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      3135136 :         if (into.size() > 0) {
     412      3222292 :             while (stopIt != myStops.end() && stopIt->pars.edge != stopEdge->getID()) {
     413              :                 stopIt++;
     414              :             }
     415              : 
     416      3134329 :             startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
     417      3134329 :             if (stopIt != myStops.end()) {
     418        80961 :                 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        80952 :                 sourcePos = stopEdgeInfo.pos;
     439        80952 :                 startTime += stopIt->getMinDuration(startTime);
     440              :             }
     441              :             edges.pop_back();
     442      3134320 :             edges.insert(edges.end(), into.begin(), into.end());
     443      3134320 :             if (edges.back()->isTazConnector()) {
     444              :                 edges.pop_back();
     445              :             }
     446      3134320 :             source = edges.back();
     447      3134320 :             stopEdgeInfo.routeIndex = (int)edges.size() - 1;
     448              :         } else {
     449          807 :             if (priority >= 0) {
     450           53 :                 stopEdgeInfo.skipped = true;
     451              :                 hasSkipped = true;
     452           53 :                 continue;
     453          754 :             } 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          731 :                 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      3136321 :     }
     475      3129626 :     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      3129626 :     if (edges.empty() && silent) {
     494              :         return false;
     495              :     }
     496      3129502 :     if (!edges.empty() && edges.front()->isTazConnector()) {
     497              :         edges.erase(edges.begin());
     498              :     }
     499      3129502 :     if (!edges.empty() && edges.back()->isTazConnector()) {
     500              :         edges.pop_back();
     501              :     }
     502      3129502 :     const double routeCost = router.recomputeCosts(edges, this, t);
     503      3129502 :     const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
     504      3129502 :     const double savings = previousCost - routeCost;
     505      3129502 :     bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
     506              :     if (!savingsOk) {
     507       153367 :         MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
     508              :         assert(routingDevice != 0);
     509       153367 :         savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
     510       153367 :         if (!savingsOk) {
     511              :             std::string dummyMsg;
     512       141422 :             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       141422 :     if (savingsOk) {
     524      2988087 :         replaceRouteEdges(edges, routeCost, savings, info, onInit);
     525              :     }
     526              :     // this must be called even if the route could not be replaced
     527      3129502 :     if (onInit) {
     528      2946859 :         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      2946720 :         setDepartAndArrivalEdge();
     538      2946720 :         calculateArrivalParams(onInit);
     539              :     }
     540      3129363 :     return !edges.empty();
     541      3129889 : }
     542              : 
     543              : 
     544              : bool
     545      3039363 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
     546      3039363 :     if (edges.empty()) {
     547         1731 :         WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
     548          577 :         if (msgReturn != nullptr) {
     549              :             *msgReturn = "No route found";
     550              :         }
     551          577 :         return false;
     552              :     }
     553              :     // build a new id, first
     554              :     std::string id = getID();
     555      3038786 :     if (id[0] != '!') {
     556      6077572 :         id = "!" + id;
     557              :     }
     558      3038786 :     const std::string idSuffix = id + "!var#";
     559      3038786 :     int varIndex = 1;
     560      3038786 :     id = idSuffix + toString(varIndex);
     561      7184948 :     while (MSRoute::hasRoute(id)) {
     562      8292324 :         id = idSuffix + toString(++varIndex);
     563              :     }
     564      3038786 :     int oldSize = (int)edges.size();
     565      3038786 :     if (!onInit) {
     566        90412 :         const MSEdge* const origin = *getRerouteOrigin();
     567        90412 :         if (origin != *myCurrEdge && edges.front() == origin) {
     568         1016 :             edges.insert(edges.begin(), *myCurrEdge);
     569         1016 :             oldSize = (int)edges.size();
     570              :         }
     571       180824 :         edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
     572              :     }
     573      3038786 :     if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
     574              :         // re-assign stop iterators when rerouting to a new parkingArea / insertStop
     575              :         return true;
     576              :     }
     577      1535671 :     const RGBColor& c = myRoute->getColor();
     578      1535671 :     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      1535671 :     ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
     582      3071342 :     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      1535703 :     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      3071340 :     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      2060324 : 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      2060324 :     if (onInit) {
     612      1466247 :         myCurrEdge = newRoute->begin();
     613              :     } else {
     614       594077 :         MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
     615       594077 :         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       594075 :         if (getLane() != nullptr) {
     627       456599 :             if (getLane()->getEdge().isInternal() && (
     628       456608 :                         (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       456590 :             } else if (getPositionOnLane() > getLane()->getLength()
     639       456595 :                        && (myCurrEdge + 1) != myRoute->end()
     640           12 :                        && (newCurrEdge + 1) != edges.end()
     641       456602 :                        && *(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       594059 :         myCurrEdge = newCurrEdge;
     654              :     }
     655      2060306 :     const bool stopsFromScratch = onInit && myRoute->getStops().empty();
     656              :     // assign new route
     657      2060306 :     checkRouteRemoval();
     658              :     myRoute = newRoute;
     659              :     // update arrival definition
     660      2060306 :     calculateArrivalParams(onInit);
     661              :     // save information that the vehicle was rerouted
     662      2060306 :     myNumberReroutes++;
     663      2060306 :     myStopUntilOffset += myRoute->getPeriod();
     664      2060306 :     MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
     665      2060306 :     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      2146181 :     for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
     694       140971 :         const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
     695        85875 :         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      2060306 :     if (stopsFromScratch) {
     703              :         myStops.clear();
     704      1466184 :         addStops(!MSGlobals::gCheckRoutes);
     705              :     } else {
     706              :         // recheck old stops
     707       594122 :         MSRouteIterator searchStart = myCurrEdge;
     708       594122 :         double lastPos = getPositionOnLane() + getBrakeGap();
     709      1050705 :         if (getLane() != nullptr && getLane()->isInternal()
     710       595039 :                 && 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          169 :             lastPos += (*myCurrEdge)->getLength();
     714              :         }
     715              :         int stopIndex = 0;
     716       644442 :         for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
     717        50320 :             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        50320 :             if (*searchStart != &iter->lane->getEdge()
     724              :                     // loop required to reach upstream position
     725        20389 :                     || endPos + NUMERICAL_EPS < lastPos
     726              :                     // loop requested at duplicate pos
     727        13744 :                     || (endPos == lastPos && iter->pars.index == STOP_INDEX_REPEAT)
     728              :                     // index encodes a skip
     729        64029 :                     || iter->pars.index > (int)myPastStops.size() + stopIndex) {
     730        36617 :                 if (searchStart != edges.end() && !iter->reached) {
     731              :                     searchStart++;
     732              :                 }
     733              :             }
     734              :             lastPos = endPos;
     735              : 
     736        50320 :             iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
     737              : #ifdef DEBUG_REPLACE_ROUTE
     738              :             if (DEBUG_COND) {
     739              :                 std::cout << "        foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
     740              :             }
     741              : #endif
     742        50320 :             if (iter->edge == edges.end() && iter->pars.priority >= 0) {
     743              :                 const std::string oldEdge = iter->pars.edge;
     744          124 :                 const std::string oldName = iter->getStoppingPlaceName().first;
     745           62 :                 if (replaceWithAlternative(iter, searchStart, edges.end())) {
     746          164 :                     WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
     747              :                                    getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
     748              :                 }
     749              :             }
     750        50320 :             if (iter->edge == edges.end()) {
     751          174 :                 if (!removeStops) {
     752            0 :                     WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
     753              :                 }
     754          174 :                 iter = myStops.erase(iter);
     755          174 :                 continue;
     756              :             } else {
     757        50146 :                 setSkips(*iter, stopIndex);
     758        50146 :                 searchStart = iter->edge;
     759              :             }
     760              :             ++iter;
     761        50146 :             stopIndex++;
     762              :         }
     763              :         // add new stops
     764       594122 :         if (addRouteStops) {
     765       524920 :             for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
     766              :                 std::string error;
     767          307 :                 addStop(*i, error, myParameter->depart + myStopUntilOffset);
     768          307 :                 if (error != "") {
     769            0 :                     WRITE_WARNING(error);
     770              :                 }
     771              :             }
     772              :         }
     773              :     }
     774              :     return true;
     775              : }
     776              : 
     777              : 
     778              : bool
     779           62 : MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
     780           62 :     std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
     781           62 :     if (!nameTag.first.empty()) {
     782           41 :         const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
     783          110 :         for (MSStoppingPlace* alt : alternatives) {
     784              :             //std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
     785          110 :             if (&alt->getLane().getEdge() == &iter->lane->getEdge()
     786          110 :                     || !alt->getLane().allowsVehicleClass(getVClass())) {
     787           62 :                 continue;
     788              :             }
     789           48 :             iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
     790           48 :             if (iter->edge != end) {
     791           41 :                 iter->replaceStoppingPlace(alt);
     792              :                 return true;
     793              :             }
     794              :         }
     795              :     }
     796              :     return false;
     797              : }
     798              : 
     799              : 
     800              : double
     801       173005 : MSBaseVehicle::getAcceleration() const {
     802       173005 :     return 0;
     803              : }
     804              : 
     805              : 
     806              : void
     807      4441702 : MSBaseVehicle::onDepart() {
     808      4441702 :     myDeparture = MSNet::getInstance()->getCurrentTimeStep();
     809      4441702 :     myDepartPos = getPositionOnLane();
     810      4441702 :     MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
     811      4441702 : }
     812              : 
     813              : 
     814              : SUMOTime
     815      3481688 : MSBaseVehicle:: getDepartDelay() const {
     816      3481688 :     const SUMOTime dep = getParameter().depart;
     817      3481688 :     if (dep < 0) {
     818              :         return 0;
     819              :     }
     820      3481581 :     return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
     821              : }
     822              : 
     823              : 
     824              : bool
     825            0 : MSBaseVehicle::hasArrived() const {
     826            0 :     return succEdge(1) == nullptr;
     827              : }
     828              : 
     829              : 
     830              : int
     831     33938009 : MSBaseVehicle::getRoutePosition() const {
     832     33938009 :     return (int) std::distance(myRoute->begin(), myCurrEdge);
     833              : }
     834              : 
     835              : 
     836              : int
     837       384153 : MSBaseVehicle::getNumRemainingEdges() const {
     838       384153 :     if (myParameter->arrivalEdge >= 0) {
     839            0 :         return myParameter->arrivalEdge - getRoutePosition() + 1;
     840              :     } else {
     841       384153 :         return myRoute->size() - getRoutePosition();
     842              :     }
     843              : }
     844              : 
     845              : 
     846              : void
     847       104044 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
     848       104044 :     myCurrEdge = myRoute->begin() + index;
     849       104044 :     const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
     850              :     // !!! hack
     851       104044 :     myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
     852       104044 : }
     853              : 
     854              : double
     855        26932 : MSBaseVehicle::getOdometer() const {
     856        26932 :     return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
     857              : }
     858              : 
     859              : bool
     860      1427832 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
     861      1427832 :     if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
     862              :         return false;
     863      1323901 :     } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
     864              :         return false;
     865              :     }
     866      2530891 :     if (isStopped() && myStops.begin()->pars.permitted.size() > 0
     867      1265501 :             && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
     868         6193 :         return false;
     869              :     }
     870      1259308 :     MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     871              :     if (taxiDevice != nullptr) {
     872        27569 :         return taxiDevice->allowsBoarding(t);
     873              :     }
     874              :     return true;
     875              : }
     876              : 
     877              : 
     878              : void
     879      1123254 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
     880      1123254 :     if (transportable->isPerson()) {
     881        13067 :         if (myPersonDevice == nullptr) {
     882         4610 :             myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
     883         4610 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
     884         4610 :             if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
     885         1970 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     886              :             }
     887              :         }
     888        13067 :         myPersonDevice->addTransportable(transportable);
     889              :     } else {
     890      1110187 :         if (myContainerDevice == nullptr) {
     891      1109753 :             myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
     892          424 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
     893          424 :             if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
     894           79 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     895              :             }
     896              :         }
     897          858 :         myContainerDevice->addTransportable(transportable);
     898              :     }
     899        13925 :     if (myEnergyParams != nullptr) {
     900         9020 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
     901              :     }
     902        13925 : }
     903              : 
     904              : 
     905              : bool
     906         2874 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
     907         3326 :     for (const MSStop& stop : myStops) {
     908         1049 :         if (stop.edge == it && stop.pars.jump >= 0) {
     909              :             return true;
     910          929 :         } else if (stop.edge > it) {
     911              :             return false;
     912              :         }
     913              :     }
     914              :     return false;
     915              : }
     916              : 
     917              : 
     918              : bool
     919      4679821 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
     920      4679821 :     MSRouteIterator start = myCurrEdge;
     921      4679821 :     if (route == nullptr) {
     922              :         route = myRoute;
     923              :     } else {
     924      3962809 :         start = route->begin();
     925              :     }
     926              :     const bool checkJumps = route == myRoute;  // the edge iterators in the stops are invalid otherwise
     927      4679821 :     return hasValidRoute(msg, start, route->end(), checkJumps);
     928              : }
     929              : 
     930              : 
     931              : bool
     932      4821243 : MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
     933              :     MSRouteIterator lastValid = last - 1;
     934              :     // check connectivity, first
     935     22150905 :     for (MSRouteIterator e = start; e != lastValid; ++e) {
     936     17378972 :         const MSEdge& next = **(e + 1);
     937     17378972 :         if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
     938        50100 :             if (!checkJumps || !hasJump(e)) {
     939        49980 :                 if (!ignoreTransientPermissions()
     940        49980 :                         || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
     941       147930 :                     msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
     942        49310 :                     return false;
     943              :                 }
     944              :             }
     945              :         }
     946              :     }
     947              :     // check usable lanes, then
     948     26872553 :     for (MSRouteIterator e = start; e != last; ++e) {
     949     22100620 :         if ((*e)->prohibits(this)) {
     950            0 :             msg = TLF("Edge '%' prohibits.", (*e)->getID());
     951              :             return false;
     952              :         }
     953              :     }
     954              :     return true;
     955              : }
     956              : 
     957              : 
     958              : bool
     959    504198945 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
     960    504198945 :     if (!(*myCurrEdge)->isTazConnector()) {
     961    504061470 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
     962           12 :             msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
     963            6 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
     964            6 :             return false;
     965              :         }
     966              :     }
     967    504198939 :     if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
     968    504198878 :         myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
     969    504198878 :         return true;
     970              :     } else {
     971          183 :         msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
     972           61 :         myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
     973           61 :         return false;
     974              :     }
     975              : }
     976              : 
     977              : 
     978              : int
     979  12749057381 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
     980  12749057381 :     if (!update) {
     981   5193749588 :         return myRouteValidity;
     982              :     }
     983              :     // insertion check must be done in any case
     984              :     std::string msg;
     985   7555307793 :     if (!hasValidRouteStart(msg)) {
     986          183 :         if (MSGlobals::gCheckRoutes) {
     987          111 :             throw ProcessError(msg);
     988           72 :         } else if (!silent) {
     989              :             // vehicle will be discarded
     990          138 :             WRITE_WARNING(msg);
     991           26 :         } else if (msgReturn != nullptr) {
     992              :             *msgReturn = msg;
     993              :         }
     994              :     }
     995        29838 :     if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
     996   7555277850 :             && (myRouteValidity & ROUTE_UNCHECKED) != 0
     997              :             // we could check after the first rerouting
     998   7560733763 :             && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
     999      7826789 :         if (!hasValidRoute(msg, myRoute)) {
    1000           78 :             myRouteValidity |= ROUTE_INVALID;
    1001          234 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
    1002              :         }
    1003              :     }
    1004   7555307604 :     myRouteValidity &= ~ROUTE_UNCHECKED;
    1005              :     return myRouteValidity;
    1006              : }
    1007              : 
    1008              : 
    1009              : bool
    1010          715 : MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
    1011         3172 :     for (auto item : myMoveReminders) {
    1012         2485 :         if (item.first == rem) {
    1013              :             return true;
    1014              :         }
    1015              :     }
    1016          687 :     return false;
    1017              : }
    1018              : 
    1019              : 
    1020              : void
    1021     28805997 : MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
    1022              : #ifdef _DEBUG
    1023              :     if (myTraceMoveReminders) {
    1024              :         traceMoveReminder("add", rem, pos, true);
    1025              :     }
    1026              : #endif
    1027     28805997 :     myMoveReminders.push_back(std::make_pair(rem, pos));
    1028     28805997 : }
    1029              : 
    1030              : 
    1031              : void
    1032            0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
    1033            0 :     for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
    1034            0 :         if (r->first == rem) {
    1035              : #ifdef _DEBUG
    1036              :             if (myTraceMoveReminders) {
    1037              :                 traceMoveReminder("remove", rem, 0, false);
    1038              :             }
    1039              : #endif
    1040              :             myMoveReminders.erase(r);
    1041              :             return;
    1042              :         }
    1043              :     }
    1044              : }
    1045              : 
    1046              : 
    1047              : void
    1048     49596402 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
    1049              :     // notifyEnter may cause new reminders to be added so we cannot use an iterator
    1050    141785747 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1051     92189348 :         MSMoveReminder* rem = myMoveReminders[i].first;
    1052     92189348 :         const double remPos = myMoveReminders[i].second;
    1053              :         // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
    1054     92189348 :         if (rem->getLane() != nullptr && remPos > 0.) {
    1055              : #ifdef _DEBUG
    1056              :             if (myTraceMoveReminders) {
    1057              :                 traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
    1058              :             }
    1059              : #endif
    1060     20000145 :             ++i;
    1061              :         } else {
    1062     72189203 :             if (rem->notifyEnter(*this, reason, enteredLane)) {
    1063              : #ifdef _DEBUG
    1064              :                 if (myTraceMoveReminders) {
    1065              :                     traceMoveReminder("notifyEnter", rem, remPos, true);
    1066              :                 }
    1067              : #endif
    1068     70082044 :                 ++i;
    1069              :             } else {
    1070              : #ifdef _DEBUG
    1071              :                 if (myTraceMoveReminders) {
    1072              :                     traceMoveReminder("notifyEnter", rem, remPos, false);
    1073              :                 }
    1074              : #endif
    1075              :                 myMoveReminders.erase(myMoveReminders.begin() + i);
    1076              :             }
    1077              :         }
    1078              :     }
    1079     49596399 : }
    1080              : 
    1081              : 
    1082              : bool
    1083   2877197992 : MSBaseVehicle::isRail() const {
    1084   2877197992 :     return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
    1085              : }
    1086              : 
    1087              : void
    1088     10565666 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
    1089     10565666 :     if (myRoute->getLastEdge()->isTazConnector()) {
    1090              :         return;
    1091              :     }
    1092      9987974 :     const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
    1093      9987974 :     if (arrivalEdgeIndex != myParameter->arrivalEdge) {
    1094           21 :         if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
    1095           42 :             WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
    1096              :                            getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
    1097              :         }
    1098              :     }
    1099      9987974 :     const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
    1100      9987974 :     if (!onInit) {
    1101       594059 :         arrivalEdge = myRoute->getLastEdge();
    1102              :         // ignore arrivalEdge parameter after rerouting
    1103       594059 :         const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
    1104              :     }
    1105              :     const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
    1106      9987974 :     const double lastLaneLength = lanes[0]->getLength();
    1107      9987974 :     switch (myParameter->arrivalPosProcedure) {
    1108       249288 :         case ArrivalPosDefinition::GIVEN:
    1109       249288 :             if (fabs(myParameter->arrivalPos) > lastLaneLength) {
    1110         4212 :                 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
    1111              :             }
    1112              :             // Maybe we should warn the user about invalid inputs!
    1113       249288 :             myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
    1114       249288 :             if (myArrivalPos < 0) {
    1115        28201 :                 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
    1116              :             }
    1117              :             break;
    1118              :         case ArrivalPosDefinition::RANDOM:
    1119       100265 :             myArrivalPos = RandHelper::rand(lastLaneLength);
    1120       100265 :             break;
    1121            0 :         case ArrivalPosDefinition::CENTER:
    1122            0 :             myArrivalPos = lastLaneLength / 2.;
    1123            0 :             break;
    1124      9638421 :         default:
    1125      9638421 :             myArrivalPos = lastLaneLength;
    1126      9638421 :             break;
    1127              :     }
    1128      9987974 :     if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
    1129       161386 :         if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
    1130       384711 :             WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
    1131              :         }
    1132       161386 :         myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
    1133      9826588 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
    1134            7 :         myArrivalLane = -1;
    1135            7 :         for (MSLane* lane : lanes) {
    1136            7 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1137            7 :                 myArrivalLane = lane->getIndex();
    1138            7 :                 break;
    1139              :             }
    1140              :         }
    1141            7 :         if (myArrivalLane == -1) {
    1142            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1143            0 :             myArrivalLane = 0;
    1144              :         }
    1145      9826581 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
    1146              :         // pick random lane among all usable lanes
    1147              :         std::vector<MSLane*> usable;
    1148       388393 :         for (MSLane* lane : lanes) {
    1149       295575 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
    1150       270441 :                 usable.push_back(lane);
    1151              :             }
    1152              :         }
    1153        92818 :         if (usable.empty()) {
    1154            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
    1155            0 :             myArrivalLane = 0;
    1156              :         } else {
    1157        92818 :             myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
    1158              :         }
    1159        92818 :     }
    1160      9987974 :     if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
    1161       292073 :         for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
    1162       224491 :             if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
    1163              :                 return;
    1164              :             }
    1165              :         }
    1166       202746 :         WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
    1167              :     }
    1168              : }
    1169              : 
    1170              : void
    1171      6952618 : MSBaseVehicle::setDepartAndArrivalEdge() {
    1172      6952618 :     SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
    1173      6952618 :     if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
    1174         8142 :         const int routeEdges = (int)myRoute->getEdges().size();
    1175         8142 :         if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1176              :             // write specific edge in vehroute output for reproducibility
    1177         4185 :             pars->departEdge = RandHelper::rand(0, routeEdges);
    1178         4185 :             pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
    1179              :         }
    1180              :         assert(pars->departEdge >= 0);
    1181         8142 :         if (pars->departEdge >= routeEdges) {
    1182            0 :             WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
    1183              :         } else {
    1184         8142 :             myCurrEdge = myRoute->begin() + pars->departEdge;
    1185              :         }
    1186              :     }
    1187      6952618 :     if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
    1188          147 :         const int routeEdges = (int)myRoute->getEdges().size();
    1189          147 :         const int begin = (int)(myCurrEdge - myRoute->begin());
    1190              :         // write specific edge in vehroute output for reproducibility
    1191          147 :         pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
    1192          147 :         pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
    1193              :         assert(pars->arrivalEdge >= begin);
    1194              :         assert(pars->arrivalEdge < routeEdges);
    1195              :     }
    1196      6952618 : }
    1197              : 
    1198              : int
    1199         3905 : MSBaseVehicle::getDepartEdge() const {
    1200         3905 :     return myParameter->departEdge < myRoute->size() ? myParameter->departEdge : 0;
    1201              : }
    1202              : 
    1203              : int
    1204     33044230 : MSBaseVehicle::getInsertionChecks() const {
    1205     33044230 :     if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
    1206       432582 :         return getParameter().insertionChecks;
    1207              :     } else {
    1208     32611648 :         return MSGlobals::gInsertionChecks;
    1209              :     }
    1210              : }
    1211              : 
    1212              : double
    1213    647908618 : MSBaseVehicle::getImpatience() const {
    1214   1295817236 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
    1215    647908618 :                          + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
    1216    647908618 :                          + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
    1217              : }
    1218              : 
    1219              : 
    1220              : MSDevice*
    1221    991398689 : MSBaseVehicle::getDevice(const std::type_info& type) const {
    1222   1700682309 :     for (MSVehicleDevice* const dev : myDevices) {
    1223    790302557 :         if (typeid(*dev) == type) {
    1224     81018937 :             return dev;
    1225              :         }
    1226              :     }
    1227              :     return nullptr;
    1228              : }
    1229              : 
    1230              : 
    1231              : void
    1232         4261 : MSBaseVehicle::saveState(OutputDevice& out) {
    1233              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
    1234         4261 :     const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
    1235         4261 :     myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
    1236              :     // params and stops must be written in child classes since they may wish to add additional attributes first
    1237         4261 :     out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
    1238         4261 :     std::ostringstream os;
    1239         8522 :     os << myOdometer << " " << myNumberReroutes;
    1240         4261 :     out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
    1241         4261 :     if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
    1242           13 :         out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
    1243              :     }
    1244         4261 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
    1245              :         const int precision = out.getPrecision();
    1246         4261 :         out.setPrecision(MAX2(gPrecisionRandom, precision));
    1247         4261 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
    1248         4261 :         out.setPrecision(precision);
    1249              :     }
    1250         4261 :     if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    1251         2876 :         out.writeAttr(SUMO_ATTR_REROUTE, true);
    1252              :     }
    1253         4261 :     if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
    1254              :         // could be set from stop
    1255            2 :         out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
    1256              :     }
    1257              :     // here starts the vehicle internal part (see loading)
    1258              :     // @note: remember to close the vehicle tag when calling this in a subclass!
    1259         8522 : }
    1260              : 
    1261              : 
    1262              : bool
    1263            0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    1264              :     UNUSED_PARAMETER(stop);
    1265              :     UNUSED_PARAMETER(distToStop);
    1266            0 :     return true;
    1267              : }
    1268              : 
    1269              : 
    1270              : bool
    1271   9603565190 : MSBaseVehicle::isStopped() const {
    1272   9603565190 :     return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
    1273              : }
    1274              : 
    1275              : 
    1276              : bool
    1277   2676545922 : MSBaseVehicle::isParking() const {
    1278   2731117897 :     return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
    1279      2583426 :             && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
    1280   2678070644 :             && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
    1281              : }
    1282              : 
    1283              : 
    1284              : bool
    1285    682781830 : MSBaseVehicle::isJumping() const {
    1286    682781830 :     return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
    1287              : }
    1288              : 
    1289              : 
    1290              : bool
    1291      7377424 : MSBaseVehicle::isStoppedTriggered() const {
    1292      7377424 :     return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
    1293              : }
    1294              : 
    1295              : 
    1296              : bool
    1297        28210 : MSBaseVehicle::isStoppedParking() const {
    1298        28210 :     return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
    1299              : }
    1300              : 
    1301              : 
    1302              : bool
    1303      1127696 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
    1304      1127696 :     if (isStopped() || (checkFuture && hasStops())) {
    1305              :         const MSStop& stop = myStops.front();
    1306      1128850 :         return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
    1307              :     }
    1308              :     return false;
    1309              : }
    1310              : 
    1311              : bool
    1312        28912 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
    1313              :     // Check if there is a parking area to be replaced
    1314        28912 :     if (parkingArea == 0) {
    1315              :         errorMsg = "new parkingArea is NULL";
    1316            0 :         return false;
    1317              :     }
    1318        28912 :     if (myStops.size() == 0) {
    1319              :         errorMsg = "vehicle has no stops";
    1320            0 :         return false;
    1321              :     }
    1322        28912 :     if (myStops.front().parkingarea == 0) {
    1323              :         errorMsg = "first stop is not at parkingArea";
    1324            0 :         return false;
    1325              :     }
    1326              :     MSStop& first = myStops.front();
    1327              :     SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
    1328        28912 :     std::string oldStopEdgeID = first.lane->getEdge().getID();
    1329              :     // merge subsequent duplicate stops equals to parking area
    1330        28929 :     for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
    1331          301 :         if (iter->parkingarea == parkingArea) {
    1332           17 :             stopPar.duration += iter->duration;
    1333           17 :             myStops.erase(iter++);
    1334              :         } else {
    1335              :             break;
    1336              :         }
    1337              :     }
    1338        28912 :     stopPar.lane = parkingArea->getLane().getID();
    1339        28912 :     stopPar.parkingarea = parkingArea->getID();
    1340        28912 :     stopPar.startPos = parkingArea->getBeginLanePosition();
    1341        28912 :     stopPar.endPos = parkingArea->getEndLanePosition();
    1342        28912 :     stopPar.index = STOP_INDEX_FIT;
    1343        28912 :     first.edge = myRoute->end(); // will be patched in replaceRoute
    1344        28912 :     first.lane = &parkingArea->getLane();
    1345        28912 :     first.parkingarea = parkingArea;
    1346              : 
    1347              :     // patch via edges
    1348        28912 :     std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
    1349        28912 :     if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
    1350          172 :         myParameter->via.erase(myParameter->via.begin());
    1351          172 :         myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
    1352              :     }
    1353              :     return true;
    1354              : }
    1355              : 
    1356              : 
    1357              : MSParkingArea*
    1358       208500 : MSBaseVehicle::getNextParkingArea() {
    1359              :     MSParkingArea* nextParkingArea = nullptr;
    1360       208500 :     if (!myStops.empty()) {
    1361       205668 :         SUMOVehicleParameter::Stop stopPar;
    1362       205668 :         MSStop stop = myStops.front();
    1363       205668 :         if (!stop.reached && stop.parkingarea != nullptr) {
    1364              :             nextParkingArea = stop.parkingarea;
    1365              :         }
    1366       205668 :     }
    1367       208500 :     return nextParkingArea;
    1368              : }
    1369              : 
    1370              : 
    1371              : MSParkingArea*
    1372       132253 : MSBaseVehicle::getCurrentParkingArea() {
    1373              :     MSParkingArea* currentParkingArea = nullptr;
    1374       132253 :     if (isParking()) {
    1375       132184 :         currentParkingArea = myStops.begin()->parkingarea;
    1376              :     }
    1377       132253 :     return currentParkingArea;
    1378              : }
    1379              : 
    1380              : 
    1381              : const std::vector<std::string>&
    1382         1656 : MSBaseVehicle::getParkingBadges() const {
    1383         1656 :     if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
    1384            7 :         return myParameter->parkingBadges;
    1385              :     } else {
    1386         1649 :         return getVehicleType().getParkingBadges();
    1387              :     }
    1388              : }
    1389              : 
    1390              : 
    1391              : double
    1392     12299832 : MSBaseVehicle::basePos(const MSEdge* edge) const {
    1393     12299832 :     double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
    1394     12299832 :     if (hasStops()
    1395     12324921 :             && myStops.front().edge == myRoute->begin()
    1396     12324921 :             && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
    1397        25045 :         result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
    1398              :     }
    1399     12299832 :     return result;
    1400              : }
    1401              : 
    1402              : 
    1403              : MSLane*
    1404          298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
    1405          298 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
    1406          298 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
    1407          298 :     if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
    1408            8 :         return nullptr;
    1409              :     }
    1410          580 :     const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
    1411          290 :     if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
    1412          290 :         const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
    1413          290 :         stop.edge = edgeID;
    1414          290 :         return edge->getOppositeEdge()->getLanes()[oppositeIndex];
    1415              :     }
    1416              :     return nullptr;
    1417              : }
    1418              : 
    1419              : 
    1420              : bool
    1421       140608 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
    1422              :                        MSRouteIterator* searchStart) {
    1423       140608 :     MSStop stop(stopPar);
    1424       140608 :     if (stopPar.lane == "") {
    1425         2990 :         MSEdge* e = MSEdge::dictionary(stopPar.edge);
    1426         2990 :         stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
    1427         2990 :         if (stop.lane == nullptr) {
    1428            0 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
    1429            0 :             return false;
    1430              :         }
    1431              :     } else {
    1432       137618 :         stop.lane = MSLane::dictionary(stopPar.lane);
    1433       137618 :         if (stop.lane == nullptr) {
    1434              :             // must be an opposite stop
    1435          145 :             SUMOVehicleParameter::Stop tmp = stopPar;
    1436          145 :             stop.lane = interpretOppositeStop(tmp);
    1437              :             assert(stop.lane != nullptr);
    1438          145 :         }
    1439       137618 :         if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
    1440           24 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
    1441           12 :             return false;
    1442              :         }
    1443              :     }
    1444       140596 :     if (MSGlobals::gUseMesoSim) {
    1445        29102 :         stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
    1446        29102 :         if (stop.lane->isInternal()) {
    1447            2 :             errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
    1448            1 :             return false;
    1449              :         }
    1450              :     }
    1451       140595 :     stop.initPars(stopPar);
    1452       140595 :     if (stopPar.until != -1) {
    1453              :         // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
    1454        53146 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
    1455              :     }
    1456       140595 :     if (stopPar.arrival != -1) {
    1457          626 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
    1458              :     }
    1459       140595 :     std::string stopType = "stop";
    1460       140595 :     std::string stopID = "";
    1461       140595 :     double parkingLength = stop.pars.endPos - stop.pars.startPos;
    1462       140595 :     if (stop.busstop != nullptr) {
    1463              :         stopType = "busStop";
    1464        37753 :         stopID = stop.busstop->getID();
    1465        37753 :         parkingLength = stop.busstop->getParkingLength();
    1466       102842 :     } else if (stop.containerstop != nullptr) {
    1467              :         stopType = "containerStop";
    1468         1050 :         stopID = stop.containerstop->getID();
    1469         1050 :         parkingLength = stop.containerstop->getParkingLength();
    1470       101792 :     } else if (stop.chargingStation != nullptr) {
    1471              :         stopType = "chargingStation";
    1472         8310 :         stopID = stop.chargingStation->getID();
    1473         8310 :         parkingLength = stop.chargingStation->getParkingLength();
    1474        93482 :     } else if (stop.overheadWireSegment != nullptr) {
    1475              :         stopType = "overheadWireSegment";
    1476            0 :         stopID = stop.overheadWireSegment->getID();
    1477            0 :         parkingLength = stop.overheadWireSegment->getParkingLength();
    1478        93482 :     } else if (stop.parkingarea != nullptr) {
    1479              :         stopType = "parkingArea";
    1480        29804 :         stopID = stop.parkingarea->getID();
    1481              :     }
    1482       281190 :     const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
    1483              : 
    1484       140595 :     if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
    1485            0 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
    1486            0 :         return false;
    1487              :     }
    1488        76917 :     if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
    1489              :             // do not warn for stops that fill the whole lane
    1490          307 :             && parkingLength < stop.lane->getLength()
    1491              :             // do not warn twice for the same stop
    1492       218349 :             && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
    1493          837 :         errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
    1494              :     }
    1495       140595 :     if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
    1496              :         // forbid access in case the parking requests other badges
    1497           14 :         errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
    1498            7 :         return false;
    1499              :     }
    1500       140588 :     const MSEdge* stopLaneEdge = &stop.lane->getEdge();
    1501              :     const MSEdge* stopEdge;
    1502       140588 :     if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
    1503              :         // stop lane is on the opposite side
    1504          145 :         stopEdge = stopLaneEdge->getOppositeEdge();
    1505          145 :         stop.isOpposite = true;
    1506              :     } else {
    1507              :         // if stop is on an internal edge the normal edge before the intersection is used
    1508       140443 :         stopEdge = stopLaneEdge->getNormalBefore();
    1509              :     }
    1510       140588 :     MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
    1511       140588 :     if (searchStart == nullptr) {
    1512       133407 :         searchStart = &myCurrEdge;
    1513       133407 :         if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
    1514              :             // already on the intersection but myCurrEdge is before it
    1515              :             searchStart = &succ;
    1516              :         }
    1517              :     }
    1518              : #ifdef DEBUG_ADD_STOP
    1519              :     if (DEBUG_COND) {
    1520              :         std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
    1521              :                   << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
    1522              :                   << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
    1523              :                   << " stopParIndex=" << stopPar.index
    1524              :                   << "\n";
    1525              :     }
    1526              : #endif
    1527       140588 :     stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
    1528       140588 :     MSRouteIterator prevStopEdge = myCurrEdge;
    1529       140588 :     const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
    1530       140588 :     double prevStopPos = getPositionOnLane();
    1531              :     // where to insert the stop
    1532              :     std::list<MSStop>::iterator iter = myStops.begin();
    1533       140588 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
    1534              :         iter = myStops.end();
    1535       117389 :         if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
    1536              :             prevStopEdge = myStops.back().edge;
    1537        49402 :             prevEdge = &myStops.back().lane->getEdge();
    1538        49402 :             prevStopPos = myStops.back().pars.endPos;
    1539        49402 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1540              :             if (prevStopEdge == stop.edge                // laneEdge check is insufficient for looped routes
    1541         8038 :                     && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
    1542        57428 :                     && (prevStopPos > stop.pars.endPos ||
    1543         2246 :                         (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
    1544          455 :                 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
    1545              :             }
    1546              : #ifdef DEBUG_ADD_STOP
    1547              :             if (DEBUG_COND) {
    1548              :                 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
    1549              :                           << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
    1550              :             }
    1551              : #endif
    1552              :         }
    1553              :         // skip a number of occurences of stopEdge in looped route
    1554       117389 :         int skipLooped = stopPar.index - static_cast<int>(myStops.size());
    1555       117954 :         for (int j = 0; j < skipLooped; j++) {
    1556          711 :             auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
    1557          711 :             if (nextIt == myRoute->end()) {
    1558          146 :                 if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
    1559              :                     // only warn if the route loops over the stop edge at least once
    1560           28 :                     errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
    1561              :                 }
    1562          146 :                 break;
    1563              :             } else {
    1564          565 :                 stop.edge = nextIt;
    1565              :             }
    1566              :         }
    1567              :     } else {
    1568        23199 :         if (stopPar.index == STOP_INDEX_FIT) {
    1569        34847 :             while (iter != myStops.end() && (iter->edge < stop.edge ||
    1570         2234 :                                              (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
    1571         2234 :                                              (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
    1572              :                 prevStopEdge = iter->edge;
    1573        11751 :                 prevStopPos = iter->pars.endPos;
    1574              :                 ++iter;
    1575              :             }
    1576              :         } else {
    1577              :             int index = stopPar.index;
    1578          103 :             while (index > 0) {
    1579            0 :                 prevStopEdge = iter->edge;
    1580            0 :                 prevStopPos = iter->pars.endPos;
    1581              :                 ++iter;
    1582            0 :                 --index;
    1583              :             }
    1584              : #ifdef DEBUG_ADD_STOP
    1585              :             if (DEBUG_COND) {
    1586              :                 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
    1587              :             }
    1588              : #endif
    1589          103 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1590              :         }
    1591              :     }
    1592       140934 :     const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
    1593       140588 :     if (stop.edge == myRoute->end()) {
    1594           89 :         if (!wasTooClose) {
    1595          207 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
    1596              :         }
    1597           89 :         return false;
    1598              :     }
    1599              : 
    1600       140499 :     const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
    1601        43353 :                            prevStopPos + (iter == myStops.begin() && !instantStopping() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
    1602              : 
    1603       140499 :     if (prevStopEdge > stop.edge ||
    1604              :             // a collision-stop happens after vehicle movement and may move the
    1605              :             // vehicle backwards on its lane (prevStopPos is the vehicle position)
    1606         1880 :             (tooClose && !stop.pars.collision)
    1607       280958 :             || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
    1608              :         // check if the edge occurs again later in the route
    1609              :         //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges())  << "\n";
    1610           40 :         if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
    1611          120 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
    1612              :         }
    1613           40 :         MSRouteIterator next = stop.edge + 1;
    1614           40 :         return addStop(stopPar, errorMsg, untilOffset, &next);
    1615              :     }
    1616       140459 :     if (wasTooClose) {
    1617              :         errorMsg = "";
    1618              :     }
    1619              :     // David.C:
    1620              :     //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
    1621       140459 :     const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
    1622       140459 :     const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
    1623       140459 :     if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
    1624              :         return false;
    1625              :     }
    1626       140459 :     if (!hasDeparted() && myCurrEdge == stop.edge) {
    1627              :         double pos = -1;
    1628        26550 :         if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
    1629         5010 :             pos = myParameter->departPos;
    1630         5010 :             if (pos < 0.) {
    1631          219 :                 pos += (*myCurrEdge)->getLength();
    1632              :             }
    1633              :         }
    1634        26550 :         if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
    1635        18312 :             pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
    1636              :         }
    1637        26550 :         if (pos > stop.pars.endPos + endPosOffset) {
    1638           20 :             if (stop.edge != myRoute->end()) {
    1639              :                 // check if the edge occurs again later in the route
    1640           20 :                 MSRouteIterator next = stop.edge + 1;
    1641           20 :                 return addStop(stopPar, errorMsg, untilOffset, &next);
    1642              :             }
    1643            0 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
    1644            0 :             return false;
    1645              :         }
    1646              :     }
    1647       140439 :     if (iter != myStops.begin()) {
    1648              :         std::list<MSStop>::iterator iter2 = iter;
    1649              :         iter2--;
    1650        96395 :         if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
    1651        61100 :                 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
    1652            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1653           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1654           24 :                        + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
    1655              :         }
    1656        61083 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1657            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1658           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1659           24 :                        + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
    1660              :         }
    1661        61083 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1662            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1663           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1664           24 :                        + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
    1665              :         }
    1666              :     } else {
    1667        97186 :         if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
    1668        79368 :                 && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
    1669            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1670           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1671           24 :                        + " earlier than departure at " + time2string(getParameter().depart) + ".";
    1672              :         }
    1673              :     }
    1674       140439 :     if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
    1675           18 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1676           54 :                    + "' set to end at " + time2string(stop.getUntil())
    1677           72 :                    + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
    1678              :     }
    1679       140439 :     setSkips(stop, (int)myStops.size());
    1680       140439 :     myStops.insert(iter, stop);
    1681       140439 :     if (stopPar.tripId != "") {
    1682         2664 :         MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
    1683              :     }
    1684              :     //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
    1685              :     //    << " routeIndex=" << (stop.edge - myRoute->begin())
    1686              :     //    << " stopIndex=" << std::distance(myStops.begin(), iter)
    1687              :     //    << " route=" << toString(myRoute->getEdges())  << "\n";
    1688              :     return true;
    1689              : }
    1690              : 
    1691              : 
    1692              : void
    1693       190585 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
    1694       190585 :     if (hasDeparted() && stop.edge > myRoute->begin()) {
    1695              :         // if the route is looped we must patch the index to ensure that state
    1696              :         // loading (and vehroute-output) encode the correct number of skips
    1697              :         int foundSkips = 0;
    1698              :         MSRouteIterator itPrev;
    1699              :         double prevEndPos;
    1700        84953 :         if (prevActiveStops > 0) {
    1701              :             assert((int)myStops.size() >= prevActiveStops);
    1702              :             auto prevStopIt = myStops.begin();
    1703        37031 :             std::advance(prevStopIt, prevActiveStops - 1);
    1704              :             const MSStop& prev = *prevStopIt;
    1705        37031 :             itPrev = prev.edge;
    1706        37031 :             prevEndPos = prev.pars.endPos;
    1707        47922 :         } else if (myPastStops.size() > 0) {
    1708        12430 :             itPrev = myRoute->begin() + myPastStops.back().routeIndex;
    1709        12430 :             prevEndPos = myPastStops.back().endPos;
    1710              :         } else {
    1711        35492 :             itPrev = myRoute->begin() + myParameter->departEdge;
    1712        35492 :             prevEndPos = myDepartPos;
    1713              :         }
    1714              :         //auto itPrevOrig = itPrev;
    1715        84953 :         if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
    1716              :             itPrev++;
    1717              :         }
    1718              :         //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
    1719       760584 :         while (itPrev < stop.edge) {
    1720       675631 :             if (*itPrev == *stop.edge) {
    1721        49724 :                 foundSkips++;
    1722              :             }
    1723              :             itPrev++;
    1724              :         }
    1725              :         int newIndex = STOP_INDEX_END;
    1726        84953 :         if (foundSkips > 0) {
    1727              :             //if (getID() == "77_0_0") {
    1728              :             //    std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
    1729              :             //        << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
    1730              :             //        << " prevEdge=" << (*itPrevOrig)->getID()
    1731              :             //        << " prevIndex=" << (itPrevOrig - myRoute->begin())
    1732              :             //        << " skips=" << foundSkips << "\n";
    1733              :             //}
    1734        21504 :             newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
    1735              :         }
    1736        84953 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
    1737              :     }
    1738       190585 : }
    1739              : 
    1740              : 
    1741              : SUMOTime
    1742          681 : MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
    1743         3640 :     for (int i = 0; i < (int)myMoveReminders.size();) {
    1744         2959 :         auto rem = &myMoveReminders[i];
    1745         2959 :         if (rem->first->notifyReroute(*this)) {
    1746              : #ifdef _DEBUG
    1747              :             if (myTraceMoveReminders) {
    1748              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, true);
    1749              :             }
    1750              : #endif
    1751         2258 :             ++i;
    1752              :         } else {
    1753              : #ifdef _DEBUG
    1754              :             if (myTraceMoveReminders) {
    1755              :                 traceMoveReminder("notifyReroute", rem->first, rem->second, false);
    1756              :             }
    1757              : #endif
    1758              :             myMoveReminders.erase(myMoveReminders.begin() + i);
    1759              :         }
    1760              :     }
    1761          681 :     resetApproachOnReroute();
    1762              :     // event only called once
    1763          681 :     return 0;
    1764              : }
    1765              : 
    1766              : 
    1767              : void
    1768      7023231 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
    1769      7023231 :     if (addRouteStops) {
    1770      7028181 :         for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    1771              :             std::string errorMsg;
    1772         9890 :             if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
    1773            6 :                 throw ProcessError(errorMsg);
    1774              :             }
    1775         9884 :             if (errorMsg != "") {
    1776          687 :                 WRITE_WARNING(errorMsg);
    1777              :             }
    1778              :         }
    1779              :     }
    1780      7023225 :     const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
    1781      7122378 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    1782              :         std::string errorMsg;
    1783        99181 :         if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
    1784           28 :             throw ProcessError(errorMsg);
    1785              :         }
    1786        99153 :         if (errorMsg != "") {
    1787          463 :             WRITE_WARNING(errorMsg);
    1788              :         }
    1789              :     }
    1790      7023197 : }
    1791              : 
    1792              : 
    1793              : bool
    1794      1512568 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
    1795      1512568 :     MSRouteIterator start = myCurrEdge;
    1796              :     int i = 0;
    1797              :     bool ok = true;
    1798      1540784 :     for (const MSStop& stop : myStops) {
    1799              :         MSRouteIterator it;
    1800        28216 :         if (stop.lane->isInternal()) {
    1801              :             // find the normal predecessor and ensure that the next route edge
    1802              :             // matches the successor of the internal edge successor
    1803            0 :             it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
    1804            0 :             if (it != myRoute->end() && (
    1805            0 :                         it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
    1806            0 :                 it = myRoute->end(); // signal failure
    1807              :             }
    1808              :         } else {
    1809        28216 :             it = std::find(start, myRoute->end(), &stop.lane->getEdge());
    1810              :         }
    1811        28216 :         if (it == myRoute->end()) {
    1812            0 :             if (!silent) {
    1813            0 :                 WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
    1814              :                              i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1815              :             }
    1816              :             ok = false;
    1817              :         } else {
    1818              :             MSRouteIterator it2;
    1819      1179807 :             for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
    1820      1170354 :                 if (it2 == stop.edge) {
    1821              :                     break;
    1822              :                 }
    1823              :             }
    1824        28216 :             if (it2 == myRoute->end()) {
    1825         9453 :                 if (!silent) {
    1826            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
    1827              :                                  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
    1828              :                 }
    1829              :                 ok = false;
    1830        18763 :             } else if (it2 < start) {
    1831            0 :                 if (!silent) {
    1832            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
    1833              :                                  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1834              :                 }
    1835              :                 ok = false;
    1836              :             } else {
    1837        18763 :                 start = stop.edge;
    1838              :             }
    1839              :         }
    1840        28216 :         i++;
    1841              :     }
    1842      1512568 :     return ok;
    1843              : }
    1844              : 
    1845              : 
    1846              : std::vector<MSBaseVehicle::StopEdgeInfo>
    1847      3119083 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
    1848              :     assert(haveValidStopEdges());
    1849              :     std::vector<StopEdgeInfo> result;
    1850              :     const MSStop* prev = nullptr;
    1851              :     const MSEdge* internalSuccessor = nullptr;
    1852      3215408 :     for (const MSStop& stop : myStops) {
    1853        96325 :         if (stop.reached) {
    1854         9737 :             if (stop.pars.jump >= 0) {
    1855            0 :                 jumps.insert((int)result.size());
    1856              :             }
    1857         9737 :             continue;
    1858              :         }
    1859        86588 :         double stopPos = stop.getEndPos(*this);
    1860              :         if ((prev == nullptr
    1861        45882 :                 || prev->edge != stop.edge
    1862         1260 :                 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
    1863       131210 :                 && *stop.edge != internalSuccessor) {
    1864        85328 :             if (stop.lane->isInternal()) {
    1865            9 :                 stopPos = (*stop.edge)->getLength();
    1866              :             }
    1867        85328 :             result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
    1868        85328 :             result.back().nameTag = stop.getStoppingPlaceName();
    1869        85328 :             result.back().stopPar = &stop.pars;
    1870        85328 :             if (stop.lane->isInternal()) {
    1871            9 :                 internalSuccessor = stop.lane->getNextNormal();
    1872           18 :                 result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
    1873              :             } else {
    1874              :                 internalSuccessor = nullptr;
    1875              :             }
    1876         1260 :         } else if (prev != nullptr && prev->edge == stop.edge) {
    1877         1260 :             result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
    1878              :         }
    1879              :         prev = &stop;
    1880        86588 :         if (firstPos == INVALID_DOUBLE) {
    1881        40706 :             if (stop.parkingarea != nullptr) {
    1882         5091 :                 firstPos = MAX2(0., stopPos);
    1883              :             } else {
    1884        35615 :                 firstPos = stopPos;
    1885              :             }
    1886              :         }
    1887        86588 :         lastPos = stopPos;
    1888        86588 :         if (stop.pars.jump >= 0) {
    1889         1208 :             jumps.insert((int)result.size() - 1);
    1890              :         }
    1891              :     }
    1892              :     //std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
    1893              :     //for (auto item : result) {
    1894              :     //    std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
    1895              :     //}
    1896      3119083 :     return result;
    1897            0 : }
    1898              : 
    1899              : 
    1900              : double
    1901         2147 : MSBaseVehicle::addStopPriority(double p1, double p2) {
    1902         2147 :     if (p1 < 0 || p2 < 0) {
    1903              :         return p1;
    1904              :     }
    1905            0 :     return p1 + p2;
    1906              : }
    1907              : 
    1908              : std::vector<std::pair<int, double> >
    1909        41277 : MSBaseVehicle::getStopIndices() const {
    1910              :     std::vector<std::pair<int, double> > result;
    1911        83567 :     for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
    1912        84580 :         result.push_back(std::make_pair(
    1913        42290 :                              (int)(iter->edge - myRoute->begin()),
    1914        42290 :                              iter->getEndPos(*this)));
    1915              :     }
    1916        41277 :     return result;
    1917            0 : }
    1918              : 
    1919              : 
    1920              : const MSStop&
    1921     15757233 : MSBaseVehicle::getNextStop() const {
    1922              :     assert(myStops.size() > 0);
    1923     15757233 :     return myStops.front();
    1924              : }
    1925              : 
    1926              : MSStop&
    1927        95422 : MSBaseVehicle::getNextStopMutable() {
    1928              :     assert(myStops.size() > 0);
    1929        95422 :     return myStops.front();
    1930              : }
    1931              : 
    1932              : SUMOTime
    1933      3648889 : MSBaseVehicle::getStopDuration() const {
    1934      3648889 :     if (isStopped()) {
    1935      1181964 :         return myStops.front().duration;
    1936              :     } else {
    1937              :         return 0;
    1938              :     }
    1939              : }
    1940              : 
    1941              : 
    1942              : MSStop&
    1943       325198 : MSBaseVehicle::getStop(int nextStopIndex) {
    1944       325198 :     if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
    1945            0 :         throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
    1946              :     }
    1947              :     auto stopIt = myStops.begin();
    1948              :     std::advance(stopIt, nextStopIndex);
    1949       325198 :     return *stopIt;
    1950              : }
    1951              : 
    1952              : 
    1953              : const SUMOVehicleParameter::Stop*
    1954       257664 : MSBaseVehicle::getNextStopParameter() const {
    1955       257664 :     if (hasStops()) {
    1956       115903 :         return &myStops.front().pars;
    1957              :     }
    1958              :     return nullptr;
    1959              : }
    1960              : 
    1961              : 
    1962              : bool
    1963        45938 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    1964              :     //if the stop exists update the duration
    1965        71186 :     for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
    1966        47861 :         if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
    1967              :             // update existing stop
    1968        22613 :             if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
    1969        21144 :                 myStops.erase(iter);
    1970              :             } else {
    1971         1469 :                 iter->duration = stop.duration;
    1972         1469 :                 iter->triggered = stop.triggered;
    1973         1469 :                 iter->containerTriggered = stop.containerTriggered;
    1974         1469 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
    1975         1469 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
    1976              :             }
    1977              :             return true;
    1978              :         }
    1979              :     }
    1980        23325 :     const bool result = addStop(stop, errorMsg);
    1981        23325 :     if (result) {
    1982              :         /// XXX handle stops added out of order
    1983        23302 :         myParameter->stops.push_back(stop);
    1984              :     }
    1985              :     return result;
    1986              : }
    1987              : 
    1988              : 
    1989              : void
    1990          748 : MSBaseVehicle::unregisterWaiting() {
    1991          748 :     if (myAmRegisteredAsWaiting) {
    1992          548 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1993          548 :         myAmRegisteredAsWaiting = false;
    1994              :     }
    1995          748 : }
    1996              : 
    1997              : 
    1998              : bool
    1999         1642 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
    2000         1642 :     if (hasStops() && nextStopIndex < (int)myStops.size()) {
    2001         1642 :         if (nextStopIndex == 0 && isStopped()) {
    2002          700 :             resumeFromStopping();
    2003              :         } else {
    2004              :             auto stopIt = myStops.begin();
    2005              :             std::advance(stopIt, nextStopIndex);
    2006          942 :             if (stopIt->parkingarea != nullptr && stopIt->parkingarea->isReservable()) {
    2007            0 :                 stopIt->parkingarea->removeSpaceReservation(this);
    2008              :             }
    2009          942 :             myStops.erase(stopIt);
    2010              :         }
    2011         1642 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2012              :             // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
    2013              :             auto stopIt2 = myParameter->stops.begin();
    2014              :             std::advance(stopIt2, nextStopIndex);
    2015            8 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
    2016              :         }
    2017         1642 :         return true;
    2018              :     } else {
    2019              :         return false;
    2020              :     }
    2021              : }
    2022              : 
    2023              : 
    2024              : bool
    2025          147 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2026          147 :     const int n = (int)myStops.size();
    2027          147 :     if (nextStopIndex < 0 || nextStopIndex >= n) {
    2028            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2029            5 :         return false;
    2030              :     }
    2031          142 :     if (nextStopIndex == 0 && isStopped()) {
    2032            6 :         errorMsg = TL("cannot replace reached stop");
    2033            6 :         return false;
    2034              :     }
    2035          136 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2036          136 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2037          136 :     MSEdge* stopEdge = &stopLane->getEdge();
    2038              : 
    2039              :     auto itStop = myStops.begin();
    2040              :     std::advance(itStop, nextStopIndex);
    2041              :     MSStop& replacedStop = *itStop;
    2042              : 
    2043              :     // check parking access rights
    2044          136 :     if (stop.parkingarea != "") {
    2045            0 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2046            0 :         if (pa != nullptr && !pa->accepts(this)) {
    2047            0 :             errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
    2048            0 :             return false;
    2049              :         }
    2050              :     }
    2051              : 
    2052          136 :     if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
    2053              :         // only replace stop attributes
    2054           10 :         const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2055           10 :         replacedStop.initPars(stop);
    2056           10 :         return true;
    2057              :     }
    2058              : 
    2059          126 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2060            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2061            0 :         return false;
    2062              :     }
    2063              : 
    2064          126 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2065          126 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2066          126 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2067          126 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2068          126 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2069          126 :     MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
    2070          126 :     auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
    2071          126 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2072              : 
    2073          126 :     bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
    2074              : 
    2075              :     ConstMSEdgeVector toNewStop;
    2076          126 :     if (!teleport) {
    2077           98 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2078           98 :         if (toNewStop.size() == 0) {
    2079           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2080            5 :             return false;
    2081              :         }
    2082              :     }
    2083              : 
    2084              :     ConstMSEdgeVector fromNewStop;
    2085          121 :     if (!newDestination) {
    2086          116 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2087          116 :         if (fromNewStop.size() == 0) {
    2088            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2089            0 :             return false;
    2090              :         }
    2091              :     }
    2092              : 
    2093          121 :     cleanupParkingReservation();
    2094          121 :     const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    2095          121 :     replacedStop.initPars(stop);
    2096          121 :     replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
    2097          121 :     replacedStop.lane = stopLane;
    2098          121 :     if (MSGlobals::gUseMesoSim) {
    2099           21 :         replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
    2100           21 :         if (replacedStop.lane->isInternal()) {
    2101            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2102            0 :             return false;
    2103              :         }
    2104              :     }
    2105              : 
    2106          121 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2107              :     ConstMSEdgeVector newEdges; // only remaining
    2108          121 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2109          121 :     if (!teleport) {
    2110           93 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2111              :     } else {
    2112           28 :         newEdges.push_back(*itStart);
    2113              :     }
    2114          121 :     if (!newDestination) {
    2115          116 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2116          116 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2117              :     } else {
    2118            5 :         newEdges.push_back(stopEdge);
    2119              :     }
    2120              :     //std::cout << SIMTIME << " replaceStop veh=" << getID()
    2121              :     //    << " teleport=" << teleport
    2122              :     //    << " busStop=" << stop.busstop
    2123              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2124              :     //    << " newEdges=" << newEdges.size()
    2125              :     //    << " toNewStop=" << toNewStop.size()
    2126              :     //    << " fromNewStop=" << fromNewStop.size()
    2127              :     //    << "\n";
    2128              : 
    2129          121 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2130          121 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2131          121 :     const double savings = previousCost - routeCost;
    2132          121 :     if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2133              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2134            5 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
    2135              :     }
    2136          121 :     if (teleport) {
    2137              :         // let the vehicle jump rather than teleport
    2138              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2139              :         // already configure to jump before the replaced stop)
    2140           28 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2141              :             return false;
    2142              :         };
    2143              :     }
    2144          121 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2145          126 : }
    2146              : 
    2147              : 
    2148              : bool
    2149           52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
    2150           52 :     const int n = (int)myStops.size();
    2151           52 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2152            0 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2153            0 :         return false;
    2154              :     }
    2155           52 :     if (nextStopIndex == 0 && isStopped()) {
    2156            0 :         errorMsg = TL("cannot reroute towards reached stop");
    2157            0 :         return false;
    2158              :     }
    2159           52 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2160              : 
    2161           52 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2162           52 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2163           52 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    2164           52 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2165           52 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2166           52 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2167           52 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2168           52 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2169              : 
    2170              :     ConstMSEdgeVector newBetween;
    2171           52 :     if (!teleport) {
    2172           15 :         router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
    2173           15 :         if (newBetween.size() == 0) {
    2174            0 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
    2175            0 :             return false;
    2176              :         }
    2177              :     }
    2178              : 
    2179           52 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2180              :     ConstMSEdgeVector newEdges; // only remaining
    2181           52 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2182           52 :     if (!teleport) {
    2183           15 :         newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
    2184              :     } else {
    2185           37 :         newEdges.push_back(*itStart);
    2186              :     }
    2187           52 :     newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2188              :     //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
    2189              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2190              :     //    << " newEdges=" << newEdges.size()
    2191              :     //    << " toNewStop=" << toNewStop.size()
    2192              :     //    << " fromNewStop=" << fromNewStop.size()
    2193              :     //    << "\n";
    2194              : 
    2195           52 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2196           52 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2197           52 :     const double savings = previousCost - routeCost;
    2198              : 
    2199           52 :     if (teleport) {
    2200              :         // let the vehicle jump rather than teleport
    2201              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    2202              :         // already configure to jump before the replaced stop)
    2203           37 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    2204              :             return false;
    2205              :         };
    2206              :     }
    2207           52 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2208           52 : }
    2209              : 
    2210              : 
    2211              : bool
    2212           65 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
    2213              :     bool needJump = true;
    2214           65 :     if (nextStopIndex > 0) {
    2215              :         auto itPriorStop = myStops.begin();
    2216           47 :         std::advance(itPriorStop, nextStopIndex - 1);
    2217              :         const MSStop& priorStop = *itPriorStop;
    2218           47 :         if (priorStop.pars.jump >= 0) {
    2219              :             needJump = false;
    2220              :         }
    2221              :     }
    2222              :     if (needJump) {
    2223           47 :         SUMOVehicleParameter::Stop jumpStopPars;
    2224           47 :         jumpStopPars.endPos = (*itStart)->getLength();
    2225           47 :         jumpStopPars.speed = 1000;
    2226           47 :         jumpStopPars.jump = 0;
    2227              :         jumpStopPars.edge = (*itStart)->getID();
    2228           47 :         jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
    2229              :         MSLane* jumpStopLane = nullptr;
    2230           47 :         for (MSLane* cand : (*itStart)->getLanes()) {
    2231           47 :             if (cand->allowsVehicleClass(getVClass())) {
    2232              :                 jumpStopLane = cand;
    2233              :                 break;
    2234              :             }
    2235              :         }
    2236           47 :         if (jumpStopLane == nullptr) {
    2237            0 :             errorMsg = TL("unable to replace stop with teleporting");
    2238              :             return false;
    2239              :         }
    2240              :         auto itStop = myStops.begin();
    2241              :         std::advance(itStop, nextStopIndex);
    2242           47 :         MSStop jumpStop(jumpStopPars);
    2243           47 :         jumpStop.initPars(jumpStopPars);
    2244           47 :         jumpStop.lane = jumpStopLane;
    2245           47 :         jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
    2246           47 :         myStops.insert(itStop, jumpStop);
    2247           47 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    2248              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2249              :             auto it = myParameter->stops.begin() + nextStopIndex;
    2250            0 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
    2251              :         }
    2252           47 :     }
    2253              :     return true;
    2254              : }
    2255              : 
    2256              : 
    2257              : bool
    2258          894 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    2259          894 :     const int n = (int)myStops.size();
    2260          894 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    2261            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    2262            5 :         return false;
    2263              :     }
    2264          889 :     if (nextStopIndex == 0 && isStopped()) {
    2265            7 :         errorMsg = TL("cannot insert stop before the currently reached stop");
    2266            7 :         return false;
    2267              :     }
    2268          882 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    2269          882 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    2270          882 :     MSEdge* stopEdge = &stopLane->getEdge();
    2271              : 
    2272          882 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    2273            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    2274            0 :         return false;
    2275              :     }
    2276              : 
    2277              :     // check parking access rights
    2278          882 :     if (stop.parkingarea != "") {
    2279          570 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    2280          570 :         if (pa != nullptr && !pa->accepts(this)) {
    2281            0 :             errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
    2282            0 :             return false;
    2283              :         }
    2284              :     }
    2285              : 
    2286          882 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    2287          882 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    2288         1549 :     const int junctionOffset = ((getLane() != nullptr && getLane()->isInternal())
    2289         1545 :             || getRerouteOrigin() != getCurrentRouteEdge()) ? 1 : 0;
    2290          882 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    2291          882 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    2292          882 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2293          882 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2294          882 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2295              : 
    2296          882 :     const bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
    2297          882 :     const bool needLoop = nextStopIndex > 0 && *itStart == stopEdge && startPos >= stop.endPos;
    2298          103 :     if (needLoop && startPos == stop.endPos) {
    2299              :         // assume that two stops at the same position indicate a looped route
    2300           95 :         startPos += POSITION_EPS;
    2301           95 :         stop.index = STOP_INDEX_REPEAT;
    2302          787 :     } else if (!hasDeparted()) {
    2303           50 :         stop.index = STOP_INDEX_END;
    2304              :     }
    2305              : 
    2306              :     MSRouteIterator itSentintel = itEnd + 1;
    2307          882 :     MSRouteIterator onRouteStart = itStart + (needLoop ? 1 : 0);
    2308          882 :     const bool onRoute = std::find(onRouteStart, itSentintel, stopEdge) != itSentintel;
    2309          882 :     if (onRoute) {
    2310          370 :         if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2311              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2312              :             auto it = myParameter->stops.begin() + nextStopIndex;
    2313           20 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2314              :         }
    2315          370 :         const bool ok = addStop(stop, errorMsg, 0, &onRouteStart);
    2316          370 :         if (ok) {
    2317          368 :             updateBestLanes(true, !hasDeparted() ? (*myCurrEdge)->getLanes().front() : 0);
    2318              :         }
    2319          370 :         return ok;
    2320              :     }
    2321              : 
    2322              :     ConstMSEdgeVector toNewStop;
    2323          512 :     if (!teleport) {
    2324          484 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2325          484 :         if (toNewStop.size() == 0) {
    2326           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2327            5 :             return false;
    2328              :         }
    2329              :     }
    2330              : 
    2331              :     ConstMSEdgeVector fromNewStop;
    2332          507 :     if (!newDestination) {
    2333          447 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2334          447 :         if (fromNewStop.size() == 0) {
    2335            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2336            0 :             return false;
    2337              :         }
    2338              :     }
    2339              : 
    2340              :     auto itStop = myStops.begin();
    2341              :     std::advance(itStop, nextStopIndex);
    2342          507 :     MSStop newStop(stop);
    2343          507 :     newStop.initPars(stop);
    2344          507 :     newStop.edge = myRoute->end(); // will be patched in replaceRoute
    2345          507 :     newStop.lane = stopLane;
    2346          507 :     if (MSGlobals::gUseMesoSim) {
    2347          124 :         newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
    2348          124 :         if (newStop.lane->isInternal()) {
    2349            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2350            0 :             return false;
    2351              :         }
    2352              :     }
    2353          507 :     myStops.insert(itStop, newStop);
    2354              : 
    2355          507 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2356              :     ConstMSEdgeVector newEdges; // only remaining
    2357          507 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2358          507 :     if (!teleport) {
    2359          479 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2360              :     } else {
    2361           28 :         newEdges.push_back(*itStart);
    2362              :     }
    2363          507 :     if (!newDestination) {
    2364          447 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2365          447 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2366              :     } else {
    2367           60 :         newEdges.push_back(stopEdge);
    2368              :     }
    2369              :     //std::cout << SIMTIME << " insertStop veh=" << getID()
    2370              :     //    << " teleport=" << teleport
    2371              :     //    << " busStop=" << stop.busstop
    2372              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2373              :     //    << " newEdges=" << newEdges.size()
    2374              :     //    << " toNewStop=" << toNewStop.size()
    2375              :     //    << " fromNewStop=" << fromNewStop.size()
    2376              :     //    << "\n";
    2377              : 
    2378          507 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2379          507 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2380          507 :     const double savings = previousCost - routeCost;
    2381              : 
    2382          507 :     if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2383              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2384              :         auto it = myParameter->stops.begin() + nextStopIndex;
    2385           40 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2386              :     }
    2387          507 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2388         1389 : }
    2389              : 
    2390              : 
    2391              : EnergyParams*
    2392    106235797 : MSBaseVehicle::getEmissionParameters() const {
    2393    106235797 :     if (myEnergyParams == nullptr) {
    2394      1065715 :         myEnergyParams = new EnergyParams(getVehicleType().getEmissionParameters());
    2395              :         double tMass = 0;
    2396      1065715 :         if (myPersonDevice != nullptr) {
    2397           16 :             for (MSTransportable* t : myPersonDevice->getTransportables()) {
    2398           16 :                 tMass += t->getVehicleType().getMass();
    2399              :             }
    2400              :         }
    2401      1065715 :         if (myContainerDevice != nullptr) {
    2402            0 :             for (MSTransportable* t : myContainerDevice->getTransportables()) {
    2403            0 :                 tMass += t->getVehicleType().getMass();
    2404              :             }
    2405              :         }
    2406      1065715 :         myEnergyParams->setTransportableMass(tMass);
    2407              :     }
    2408    106235797 :     return myEnergyParams;
    2409              : }
    2410              : 
    2411              : 
    2412              : double
    2413            0 : MSBaseVehicle::getStateOfCharge() const {
    2414            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2415            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2416            0 :         return batteryOfVehicle->getActualBatteryCapacity();
    2417              :     } else {
    2418            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2419            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2420            0 :             return batteryOfVehicle->getActualBatteryCapacity();
    2421              :         }
    2422              :     }
    2423              :     return -1;
    2424              : }
    2425              : 
    2426              : 
    2427              : double
    2428            0 : MSBaseVehicle::getRelativeStateOfCharge() const {
    2429            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2430            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2431            0 :         return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2432              :     } else {
    2433            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2434            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2435            0 :             return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2436              :         }
    2437              :     }
    2438              :     return -1;
    2439              : }
    2440              : 
    2441              : 
    2442              : double
    2443            0 : MSBaseVehicle::getChargedEnergy() const {
    2444            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2445            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2446            0 :         return batteryOfVehicle->getEnergyCharged();
    2447              :     } else {
    2448            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2449            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2450            0 :             return batteryOfVehicle->getEnergyCharged();
    2451              :         }
    2452              :     }
    2453              :     return -1;
    2454              : }
    2455              : 
    2456              : 
    2457              : double
    2458            0 : MSBaseVehicle::getMaxChargeRate() const {
    2459            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2460            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2461            0 :         return batteryOfVehicle->getMaximumChargeRate();
    2462              :     }
    2463              :     return -1;
    2464              : }
    2465              : 
    2466              : 
    2467              : double
    2468            0 : MSBaseVehicle::getElecHybridCurrent() const {
    2469            0 :     if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2470            0 :         MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2471            0 :         return elecHybridDevice->getCurrentFromOverheadWire();
    2472              :     }
    2473              : 
    2474              :     return NAN;
    2475              : }
    2476              : 
    2477              : double
    2478          768 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
    2479          768 :     if (isOnRoad() || isIdling()) {
    2480          768 :         return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
    2481              :     } else {
    2482              :         return 0.;
    2483              :     }
    2484              : }
    2485              : 
    2486              : 
    2487              : const MSEdgeWeightsStorage&
    2488      6749799 : MSBaseVehicle::getWeightsStorage() const {
    2489      6749799 :     return _getWeightsStorage();
    2490              : }
    2491              : 
    2492              : 
    2493              : MSEdgeWeightsStorage&
    2494          670 : MSBaseVehicle::getWeightsStorage() {
    2495          670 :     return _getWeightsStorage();
    2496              : }
    2497              : 
    2498              : 
    2499              : MSEdgeWeightsStorage&
    2500      6750469 : MSBaseVehicle::_getWeightsStorage() const {
    2501      6750469 :     if (myEdgeWeights == nullptr) {
    2502        13829 :         myEdgeWeights = new MSEdgeWeightsStorage();
    2503              :     }
    2504      6750469 :     return *myEdgeWeights;
    2505              : }
    2506              : 
    2507              : 
    2508              : 
    2509              : 
    2510              : int
    2511     10582279 : MSBaseVehicle::getPersonNumber() const {
    2512     10582279 :     int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
    2513     10582279 :     return boarded + myParameter->personNumber;
    2514              : }
    2515              : 
    2516              : int
    2517            0 : MSBaseVehicle::getLeavingPersonNumber() const {
    2518              :     int leavingPersonNumber = 0;
    2519            0 :     const std::vector<MSTransportable*>& persons = getPersons();
    2520            0 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2521            0 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
    2522              :         const MSStop* stop = &myStops.front();
    2523            0 :         const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
    2524            0 :         if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
    2525            0 :             leavingPersonNumber++;
    2526              :         }
    2527              :     }
    2528            0 :     return leavingPersonNumber;
    2529              : }
    2530              : 
    2531              : std::vector<std::string>
    2532          196 : MSBaseVehicle::getPersonIDList() const {
    2533              :     std::vector<std::string> ret;
    2534          196 :     const std::vector<MSTransportable*>& persons = getPersons();
    2535          671 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2536          475 :         ret.push_back((*it_p)->getID());
    2537              :     }
    2538          196 :     return ret;
    2539            0 : }
    2540              : 
    2541              : int
    2542      8198107 : MSBaseVehicle::getContainerNumber() const {
    2543      8198107 :     int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
    2544      8198107 :     return loaded + myParameter->containerNumber;
    2545              : }
    2546              : 
    2547              : 
    2548              : void
    2549          166 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
    2550              :     // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
    2551          166 :     if (myPersonDevice != nullptr) {
    2552          146 :         myPersonDevice->removeTransportable(t);
    2553              :     }
    2554          166 :     if (myContainerDevice != nullptr) {
    2555           20 :         myContainerDevice->removeTransportable(t);
    2556              :     }
    2557          166 :     if (myEnergyParams != nullptr) {
    2558           86 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2559              :     }
    2560          166 : }
    2561              : 
    2562              : 
    2563              : void
    2564         9478 : MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
    2565         9478 :     if (myEnergyParams != nullptr) {
    2566         6166 :         myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
    2567              :     }
    2568         9478 : }
    2569              : 
    2570              : 
    2571              : const std::vector<MSTransportable*>&
    2572      8172122 : MSBaseVehicle::getPersons() const {
    2573      8172122 :     if (myPersonDevice == nullptr) {
    2574              :         return myEmptyTransportableVector;
    2575              :     } else {
    2576        13875 :         return myPersonDevice->getTransportables();
    2577              :     }
    2578              : }
    2579              : 
    2580              : 
    2581              : const std::vector<MSTransportable*>&
    2582      6918914 : MSBaseVehicle::getContainers() const {
    2583      6918914 :     if (myContainerDevice == nullptr) {
    2584              :         return myEmptyTransportableVector;
    2585              :     } else {
    2586         3368 :         return myContainerDevice->getTransportables();
    2587              :     }
    2588              : }
    2589              : 
    2590              : 
    2591              : bool
    2592          210 : MSBaseVehicle::isLineStop(double position) const {
    2593          210 :     if (myParameter->line == "") {
    2594              :         // not a public transport line
    2595              :         return false;
    2596              :     }
    2597          362 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    2598          215 :         if (stop.startPos <= position && position <= stop.endPos) {
    2599              :             return true;
    2600              :         }
    2601              :     }
    2602          174 :     for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    2603           38 :         if (stop.startPos <= position && position <= stop.endPos) {
    2604              :             return true;
    2605              :         }
    2606              :     }
    2607              :     return false;
    2608              : }
    2609              : 
    2610              : 
    2611              : bool
    2612           45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
    2613          144 :     for (MSDevice* const dev : myDevices) {
    2614          126 :         if (dev->deviceName() == deviceName) {
    2615              :             return true;
    2616              :         }
    2617              :     }
    2618              :     return false;
    2619              : }
    2620              : 
    2621              : 
    2622              : void
    2623            9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
    2624            9 :     if (!hasDevice(deviceName)) {
    2625            9 :         if (deviceName == "rerouting") {
    2626           27 :             ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
    2627            9 :             MSDevice_Routing::buildVehicleDevices(*this, myDevices);
    2628            9 :             if (hasDeparted()) {
    2629              :                 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
    2630            0 :                 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
    2631              :                 assert(routingDevice != 0);
    2632            0 :                 routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
    2633              :             }
    2634              :         } else {
    2635            0 :             throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
    2636              :         }
    2637              :     }
    2638            9 : }
    2639              : 
    2640              : 
    2641              : std::string
    2642        50018 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
    2643        59494 :     for (MSVehicleDevice* const dev : myDevices) {
    2644        59485 :         if (dev->deviceName() == deviceName) {
    2645        50009 :             return dev->getParameter(key);
    2646              :         }
    2647              :     }
    2648           27 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2649              : }
    2650              : 
    2651              : 
    2652              : void
    2653          208 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
    2654          355 :     for (MSVehicleDevice* const dev : myDevices) {
    2655          355 :         if (dev->deviceName() == deviceName) {
    2656          208 :             dev->setParameter(key, value);
    2657          208 :             return;
    2658              :         }
    2659              :     }
    2660            0 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2661              : }
    2662              : 
    2663              : 
    2664              : void
    2665          842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
    2666         1669 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
    2667          837 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
    2668          837 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2669              :         // checked in MSLink::ignoreFoe
    2670              :     } else {
    2671           15 :         throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
    2672              :     }
    2673          837 : }
    2674              : 
    2675              : 
    2676              : void
    2677           33 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
    2678              :     // handle some generic params first and then delegate to the carFollowModel itself
    2679           57 :     if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
    2680           17 :         getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
    2681           17 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2682              :         // checked in MSVehicle::planMove
    2683              :     } else {
    2684           16 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
    2685           16 :         if (microVeh) {
    2686              :             // remove 'carFollowModel.' prefix
    2687           16 :             const std::string attrName = key.substr(15);
    2688           16 :             microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
    2689              :         }
    2690              :     }
    2691           29 : }
    2692              : 
    2693              : 
    2694              : void
    2695      5557086 : MSBaseVehicle::initTransientModelParams() {
    2696              :     /* Design idea for additional junction model parameters:
    2697              :        We can distinguish between 3 levels of parameters
    2698              :        1. typically shared by multiple vehicles -> vType parameter
    2699              :        2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
    2700              :        3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
    2701              :        */
    2702      5830475 :     for (auto item : getParameter().getParametersMap()) {
    2703       546778 :         if (StringUtils::startsWith(item.first, "junctionModel.")) {
    2704          832 :             setJunctionModelParameter(item.first, item.second);
    2705       545114 :         } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
    2706           17 :             setCarFollowModelParameter(item.first, item.second);
    2707              :         }
    2708              :     }
    2709     11114172 :     const std::string routingModeStr = getStringParam("device.rerouting.mode");
    2710              :     try {
    2711      5557086 :         int routingMode = StringUtils::toInt(routingModeStr);
    2712      5557086 :         if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
    2713              :             setRoutingMode(routingMode);
    2714              :         }
    2715            0 :     } catch (NumberFormatException&) {
    2716              :         // @todo interpret symbolic constants
    2717            0 :         throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
    2718            0 :     }
    2719      5557086 : }
    2720              : 
    2721              : 
    2722              : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
    2723        23575 : MSBaseVehicle::getRouterTT() const {
    2724        23575 :     if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
    2725          204 :         return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
    2726              :     } else {
    2727        46946 :         return MSNet::getInstance()->getRouterTT(getRNGIndex());
    2728              :     }
    2729              : }
    2730              : 
    2731              : 
    2732              : void
    2733        30684 : MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
    2734              :     assert(type != nullptr);
    2735              :     // save old parameters before possible type deletion
    2736        30684 :     const double oldMu = myType->getSpeedFactor().getParameter(0);
    2737              :     const double oldDev = myType->getSpeedFactor().getParameter(1);
    2738        30684 :     if (myType->isVehicleSpecific() && type != myType) {
    2739          936 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    2740              :     }
    2741              :     // adapt myChosenSpeedFactor to the new type
    2742        30684 :     if (oldDev == 0.) {
    2743              :         // old type had speedDev 0, reroll
    2744        22805 :         myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
    2745              :     } else {
    2746              :         // map old speedFactor onto new distribution
    2747         7879 :         const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
    2748              :         const double newMu = type->getSpeedFactor().getParameter(0);
    2749              :         const double newDev = type->getSpeedFactor().getParameter(1);
    2750         7879 :         myChosenSpeedFactor = newMu + distPoint * newDev;
    2751              :         // respect distribution limits
    2752         7879 :         myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
    2753         7884 :         myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
    2754              :     }
    2755        30684 :     myType = type;
    2756        30684 :     if (myEnergyParams != nullptr) {
    2757              :         myEnergyParams->setSecondary(type->getEmissionParameters());
    2758              :     }
    2759        30684 : }
    2760              : 
    2761              : 
    2762              : MSVehicleType&
    2763       145089 : MSBaseVehicle::getSingularType() {
    2764       145089 :     if (myType->isVehicleSpecific()) {
    2765              :         return *const_cast<MSVehicleType*>(myType);
    2766              :     }
    2767         2536 :     MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
    2768         1268 :     replaceVehicleType(type);
    2769         1268 :     return *type;
    2770              : }
    2771              : 
    2772              : 
    2773              : int
    2774       892061 : MSBaseVehicle::getRNGIndex() const {
    2775       892061 :     const MSLane* const lane = getLane();
    2776       892061 :     if (lane == nullptr) {
    2777        18454 :         return getEdge()->getLanes()[0]->getRNGIndex();
    2778              :     } else {
    2779       873607 :         return lane->getRNGIndex();
    2780              :     }
    2781              : }
    2782              : 
    2783              : 
    2784              : SumoRNG*
    2785    752182058 : MSBaseVehicle::getRNG() const {
    2786    752182058 :     const MSLane* lane = getLane();
    2787    752182058 :     if (lane == nullptr) {
    2788         7084 :         return getEdge()->getLanes()[0]->getRNG();
    2789              :     } else {
    2790    752174974 :         return lane->getRNG();
    2791              :     }
    2792              : }
    2793              : 
    2794              : std::string
    2795        68863 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
    2796        68863 :     const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
    2797       137726 :     if (StringUtils::startsWith(key, "device.")) {
    2798       150054 :         StringTokenizer tok(key, ".");
    2799        50018 :         if (tok.size() < 3) {
    2800            0 :             error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
    2801            0 :             return "";
    2802              :         }
    2803              :         try {
    2804       150054 :             return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
    2805           18 :         } catch (InvalidArgument& e) {
    2806           54 :             error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
    2807           18 :             return "";
    2808           18 :         }
    2809        87708 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2810          324 :         if (microVeh == nullptr) {
    2811           40 :             error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
    2812           20 :             return "";
    2813              :         }
    2814          304 :         const std::string attrName = key.substr(16);
    2815              :         try {
    2816          304 :             return microVeh->getLaneChangeModel().getParameter(attrName);
    2817           44 :         } catch (InvalidArgument& e) {
    2818          132 :             error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
    2819           44 :             return "";
    2820           44 :         }
    2821        37042 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2822           12 :         if (microVeh == nullptr) {
    2823            0 :             error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
    2824            0 :             return "";
    2825              :         }
    2826           12 :         const std::string attrName = key.substr(15);
    2827              :         try {
    2828           12 :             return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
    2829            0 :         } catch (InvalidArgument& e) {
    2830            0 :             error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
    2831            0 :             return "";
    2832            0 :         }
    2833        18545 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2834          108 :         StringTokenizer tok(key, ".");
    2835           36 :         if (tok.size() != 3) {
    2836            0 :             error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
    2837            0 :             return "";
    2838              :         }
    2839           81 :         return hasDevice(tok.get(1)) ? "true" : "false";
    2840              :         // parking related parameters start here
    2841        18509 :     } else if (key == "parking.rerouteCount") {
    2842           15 :         return toString(getNumberParkingReroutes());
    2843        36916 :     } else if (StringUtils::startsWith(key, "parking.memory.")) {
    2844              :         std::vector<std::string> values;
    2845           65 :         if (getParkingMemory()) {
    2846           20 :             if (key == "parking.memory.IDList") {
    2847           24 :                 for (const auto& item : *getParkingMemory()) {
    2848           20 :                     values.push_back(item.first->getID());
    2849              :                 }
    2850           16 :             } else if (key == "parking.memory.score") {
    2851           24 :                 for (const auto& item : *getParkingMemory()) {
    2852           20 :                     values.push_back(item.second.score);
    2853              :                 }
    2854           12 :             } else if (key == "parking.memory.blockedAtTime") {
    2855           24 :                 for (const auto& item : *getParkingMemory()) {
    2856           40 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
    2857              :                 }
    2858            8 :             } else if (key == "parking.memory.blockedAtTimeLocal") {
    2859           24 :                 for (const auto& item : *getParkingMemory()) {
    2860           40 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
    2861              :                 }
    2862              :             } else {
    2863            8 :                 error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
    2864              :             }
    2865              :         }
    2866           65 :         return toString(values);
    2867           65 :     } else {
    2868              :         // default: custom user parameter
    2869        36786 :         return getParameter().getParameter(key, "");
    2870              :     }
    2871              : }
    2872              : 
    2873              : 
    2874              : void
    2875        88992 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
    2876        88992 :     if (myParkingMemory == nullptr) {
    2877            0 :         myParkingMemory = new StoppingPlaceMemory();
    2878              :     }
    2879        88992 :     myParkingMemory->rememberBlockedStoppingPlace(pa, local);
    2880        88992 : }
    2881              : 
    2882              : 
    2883              : void
    2884        29684 : MSBaseVehicle::resetParkingAreaScores() {
    2885        29684 :     if (myParkingMemory != nullptr) {
    2886        27856 :         myParkingMemory->resetStoppingPlaceScores();
    2887              :     }
    2888        29684 : }
    2889              : 
    2890              : 
    2891              : void
    2892          360 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
    2893          360 :     if (myChargingMemory == nullptr) {
    2894           80 :         myChargingMemory = new StoppingPlaceMemory();
    2895              :     }
    2896          360 :     myChargingMemory->rememberStoppingPlaceScore(cs, score);
    2897          360 : }
    2898              : 
    2899              : 
    2900              : void
    2901          127 : MSBaseVehicle::resetChargingStationScores() {
    2902          127 :     if (myChargingMemory != nullptr) {
    2903           11 :         myChargingMemory->resetStoppingPlaceScores();
    2904              :     }
    2905          127 : }
    2906              : 
    2907              : 
    2908              : void
    2909       131687 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
    2910       131687 :     if (myParkingMemory == nullptr) {
    2911         2330 :         myParkingMemory = new StoppingPlaceMemory();
    2912              :     }
    2913       131687 :     myParkingMemory->rememberStoppingPlaceScore(pa, score);
    2914       131687 : }
    2915              : 
    2916              : 
    2917              : SUMOTime
    2918        71984 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
    2919        71984 :     if (myParkingMemory == nullptr) {
    2920              :         return -1;
    2921              :     }
    2922        71960 :     return myParkingMemory->sawBlockedStoppingPlace(pa, local);
    2923              : }
    2924              : 
    2925              : 
    2926            0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
    2927            0 :     if (myChargingMemory == nullptr) {
    2928            0 :         myChargingMemory = new StoppingPlaceMemory();
    2929              :     }
    2930            0 :     myChargingMemory->rememberBlockedStoppingPlace(cs, local);
    2931            0 : }
    2932              : 
    2933              : 
    2934              : SUMOTime
    2935          548 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
    2936          548 :     if (myChargingMemory == nullptr) {
    2937              :         return -1;
    2938              :     }
    2939           72 :     return myChargingMemory->sawBlockedStoppingPlace(cs, local);
    2940              : }
    2941              : 
    2942              : 
    2943              : void
    2944      4795278 : MSBaseVehicle::cleanupParkingReservation() {
    2945      4795278 :     if (hasStops() && myStops.front().parkingarea != nullptr && myStops.front().parkingarea->isReservable()) {
    2946            0 :         myStops.front().parkingarea->removeSpaceReservation(this);
    2947              :     }
    2948      4795278 : }
    2949              : 
    2950              : 
    2951              : #ifdef _DEBUG
    2952              : void
    2953              : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
    2954              :     if (oc.isSet("movereminder-output.vehicles")) {
    2955              :         const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
    2956              :         myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
    2957              :     }
    2958              : }
    2959              : 
    2960              : 
    2961              : void
    2962              : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
    2963              :     OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
    2964              :     od.openTag("movereminder");
    2965              :     od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
    2966              :     od.writeAttr("veh", getID());
    2967              :     od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
    2968              :     od.writeAttr("type", type);
    2969              :     od.writeAttr("pos", toString(pos));
    2970              :     od.writeAttr("keep", toString(keep));
    2971              :     od.closeTag();
    2972              : }
    2973              : #endif
    2974              : 
    2975              : 
    2976              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1