LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.7 % 1244 1104
Test Date: 2024-10-24 15:46:30 Functions: 88.2 % 110 97

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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 <utils/common/StdDefs.h>
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <utils/options/OptionsCont.h>
      30              : #include <utils/iodevices/OutputDevice.h>
      31              : #include <utils/emissions/PollutantsInterface.h>
      32              : #include <utils/emissions/HelpersHarmonoise.h>
      33              : #include <libsumo/TraCIConstants.h>
      34              : #include <mesosim/MELoop.h>
      35              : #include <mesosim/MEVehicle.h>
      36              : #include <microsim/devices/MSRoutingEngine.h>
      37              : #include <microsim/devices/MSDevice_Transportable.h>
      38              : #include <microsim/devices/MSDevice_Emissions.h>
      39              : #include <microsim/devices/MSDevice_Battery.h>
      40              : #include <microsim/devices/MSDevice_ElecHybrid.h>
      41              : #include <microsim/devices/MSDevice_Taxi.h>
      42              : #include <microsim/devices/MSDevice_Routing.h>
      43              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      44              : #include <microsim/transportables/MSPerson.h>
      45              : #include <microsim/transportables/MSStageDriving.h>
      46              : #include <microsim/trigger/MSChargingStation.h>
      47              : #include <microsim/trigger/MSStoppingPlaceRerouter.h>
      48              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      49              : #include "MSGlobals.h"
      50              : #include "MSVehicleControl.h"
      51              : #include "MSVehicleType.h"
      52              : #include "MSEdge.h"
      53              : #include "MSLane.h"
      54              : #include "MSMoveReminder.h"
      55              : #include "MSEdgeWeightsStorage.h"
      56              : #include "MSNet.h"
      57              : #include "MSStop.h"
      58              : #include "MSParkingArea.h"
      59              : #include "MSInsertionControl.h"
      60              : #include "MSBaseVehicle.h"
      61              : 
      62              : //#define DEBUG_REROUTE
      63              : //#define DEBUG_ADD_STOP
      64              : //#define DEBUG_COND (getID() == "")
      65              : //#define DEBUG_COND (true)
      66              : //#define DEBUG_REPLACE_ROUTE
      67              : #define DEBUG_COND (isSelected())
      68              : 
      69              : // ===========================================================================
      70              : // static members
      71              : // ===========================================================================
      72              : const SUMOTime MSBaseVehicle::NOT_YET_DEPARTED = SUMOTime_MAX;
      73              : std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
      74              : #ifdef _DEBUG
      75              : std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
      76              : #endif
      77              : SUMOTrafficObject::NumericalID MSBaseVehicle::myCurrentNumericalIndex = 0;
      78              : 
      79              : // ===========================================================================
      80              : // Influencer method definitions
      81              : // ===========================================================================
      82              : 
      83         3421 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
      84         3421 : {}
      85              : 
      86              : // ===========================================================================
      87              : // method definitions
      88              : // ===========================================================================
      89              : 
      90              : double
      91            0 : MSBaseVehicle::getPreviousSpeed() const {
      92            0 :     throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
      93              : }
      94              : 
      95              : 
      96      4613644 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      97      4613644 :                              MSVehicleType* type, const double speedFactor) :
      98              :     SUMOVehicle(pars->id),
      99      4613644 :     myParameter(pars),
     100              :     myRoute(route),
     101      4613644 :     myType(type),
     102      4613644 :     myCurrEdge(route->begin()),
     103      4624323 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     104      4613644 :     myMoveReminders(0),
     105      4613644 :     myPersonDevice(nullptr),
     106      4613644 :     myContainerDevice(nullptr),
     107      4613644 :     myEnergyParams(nullptr),
     108      4613644 :     myDeparture(NOT_YET_DEPARTED),
     109      4613644 :     myDepartPos(-1),
     110      4613644 :     myArrivalPos(-1),
     111      4613644 :     myArrivalLane(-1),
     112      4613644 :     myNumberReroutes(0),
     113      4613644 :     myStopUntilOffset(0),
     114      4613644 :     myOdometer(0.),
     115      4613644 :     myRouteValidity(ROUTE_UNCHECKED),
     116      4613644 :     myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
     117      4613644 :     myNumericalID(myCurrentNumericalIndex++),
     118      9227288 :     myEdgeWeights(nullptr)
     119              : #ifdef _DEBUG
     120              :     , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
     121              : #endif
     122              : {
     123      4613644 :     if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
     124       566510 :         pars->parametersSet |= VEHPARS_FORCE_REROUTE;
     125              :     }
     126      4613644 :     if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
     127      3121311 :         setDepartAndArrivalEdge();
     128              :     }
     129      4613644 :     if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
     130      3121311 :         calculateArrivalParams(true);
     131              :     }
     132      4613644 :     initTransientModelParams();
     133      4613644 : }
     134              : 
     135              : 
     136      4613553 : MSBaseVehicle::~MSBaseVehicle() {
     137      4613553 :     delete myEdgeWeights;
     138      4613553 :     if (myParameter->repetitionNumber == -1) {
     139              :         // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
     140       439911 :         MSRoute::checkDist(myParameter->routeid);
     141              :     }
     142      8401837 :     for (MSVehicleDevice* dev : myDevices) {
     143      3788284 :         delete dev;
     144              :     }
     145      4613553 :     delete myEnergyParams;
     146      4613553 :     delete myParkingMemory;
     147      4613553 :     delete myChargingMemory;
     148      4613553 :     checkRouteRemoval();
     149      4613553 :     delete myParameter;
     150      4613553 : }
     151              : 
     152              : 
     153              : void
     154      6557957 : MSBaseVehicle::checkRouteRemoval() {
     155              :     // the check for an instance is needed for the unit tests which do not construct a network
     156              :     // TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
     157     13115912 :     if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
     158      1289833 :         myRoute->checkRemoval();
     159              :     }
     160      6557957 : }
     161              : 
     162              : 
     163              : std::string
     164      6557955 : MSBaseVehicle::getFlowID() const {
     165      6557955 :     return getID().substr(0, getID().rfind('.'));
     166              : }
     167              : 
     168              : 
     169              : void
     170      4613644 : MSBaseVehicle::initDevices() {
     171      4613644 :     MSDevice::buildVehicleDevices(*this, myDevices);
     172      8397368 :     for (MSVehicleDevice* dev : myDevices) {
     173      3783740 :         myMoveReminders.push_back(std::make_pair(dev, 0.));
     174              :     }
     175      4613628 :     if (MSGlobals::gHaveEmissions) {
     176              :         // ensure we have the emission parameters even if we don't have the device
     177       852248 :         getEmissionParameters();
     178              :     }
     179      4613628 : }
     180              : 
     181              : 
     182              : void
     183            0 : MSBaseVehicle::setID(const std::string& /*newID*/) {
     184            0 :     throw ProcessError(TL("Changing a vehicle ID is not permitted"));
     185              : }
     186              : 
     187              : const SUMOVehicleParameter&
     188  12511246547 : MSBaseVehicle::getParameter() const {
     189  12511246547 :     return *myParameter;
     190              : }
     191              : 
     192              : 
     193              : void
     194          496 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
     195          496 :     delete myParameter;
     196          496 :     myParameter = newParameter;
     197          496 : }
     198              : 
     199              : 
     200              : bool
     201    632448494 : MSBaseVehicle::ignoreTransientPermissions() const {
     202    632448494 :     return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
     203              : }
     204              : 
     205              : double
     206   5906272812 : MSBaseVehicle::getMaxSpeed() const {
     207   5906272812 :     return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
     208              : }
     209              : 
     210              : 
     211              : const MSEdge*
     212   1709838122 : MSBaseVehicle::succEdge(int nSuccs) const {
     213   1709838122 :     if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
     214   1346600541 :         return *(myCurrEdge + nSuccs);
     215              :     } else {
     216    363237581 :         return nullptr;
     217              :     }
     218              : }
     219              : 
     220              : 
     221              : const MSEdge*
     222   2947188232 : MSBaseVehicle::getEdge() const {
     223   2947188232 :     return *myCurrEdge;
     224              : }
     225              : 
     226              : 
     227              : const std::set<SUMOTrafficObject::NumericalID>
     228        67589 : MSBaseVehicle::getUpcomingEdgeIDs() const {
     229              :     std::set<SUMOTrafficObject::NumericalID> result;
     230       305517 :     for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
     231       237928 :         result.insert((*e)->getNumericalID());
     232              :     }
     233        67589 :     return result;
     234              : }
     235              : 
     236              : 
     237              : bool
     238       112743 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
     239       112743 :     if (stop == nullptr) {
     240              :         return false;
     241              :     }
     242       261024 :     for (const MSStop& s : myStops) {
     243       186512 :         if (s.busstop == stop
     244       148300 :                 || s.containerstop == stop
     245       148294 :                 || s.parkingarea == stop
     246       148289 :                 || s.chargingStation == stop) {
     247              :             return true;
     248              :         }
     249              :     }
     250              :     return false;
     251              : }
     252              : 
     253              : bool
     254       184830 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
     255       391999 :     for (const MSStop& s : myStops) {
     256       366033 :         if (&s.lane->getEdge() == edge) {
     257              :             return true;
     258              :         }
     259              :     }
     260        25966 :     return myRoute->getLastEdge() == edge;
     261              : }
     262              : 
     263              : 
     264              : bool
     265      2663458 : MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
     266              :     // check whether to reroute
     267      2663458 :     const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
     268      2663458 :     if (source == nullptr) {
     269          289 :         source = *getRerouteOrigin();
     270              :     }
     271      2663458 :     if (sink == nullptr) {
     272      2636187 :         sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
     273      2636187 :         if (sink == nullptr) {
     274          289 :             sink = myRoute->getLastEdge();
     275              :         }
     276              :     }
     277      2674345 :     ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
     278              :     ConstMSEdgeVector edges;
     279              :     ConstMSEdgeVector stops;
     280              :     std::set<int> jumps;
     281              :     bool stopAtSink = false;
     282      2663458 :     if (myParameter->via.size() == 0) {
     283      2654945 :         double firstPos = INVALID_DOUBLE;
     284      2654945 :         double lastPos = INVALID_DOUBLE;
     285      2654945 :         stops = getStopEdges(firstPos, lastPos, jumps);
     286      2654945 :         if (stops.size() > 0) {
     287        39307 :             double sourcePos = onInit ? 0 : getPositionOnLane();
     288        39307 :             if (MSGlobals::gUseMesoSim && isStopped()) {
     289          231 :                 sourcePos = getNextStop().pars.endPos;
     290              :             }
     291              :             // avoid superfluous waypoints for first and last edge
     292        39307 :             const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos + NUMERICAL_EPS);
     293        39307 :             const bool skipLast = (stops.back() == sink
     294        21639 :                                    && myArrivalPos >= lastPos
     295        13230 :                                    && (stops.size() < 2 || stops.back() != stops[stops.size() - 2])
     296        52522 :                                    && (stops.size() > 1 || skipFirst));
     297              : #ifdef DEBUG_REROUTE
     298              :             if (DEBUG_COND) {
     299              :                 std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
     300              :                           << " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
     301              :                           << " route=" << toString(myRoute->getEdges()) << " stopEdges=" << toString(stops) << " skipFirst=" << skipFirst << " skipLast=" << skipLast << "\n";
     302              :             }
     303              : #endif
     304        39307 :             if (stops.size() == 1 && (skipFirst || skipLast)) {
     305              :                 stops.clear();
     306              :             } else {
     307        31210 :                 if (skipFirst) {
     308              :                     stops.erase(stops.begin());
     309              :                 }
     310        31210 :                 if (skipLast) {
     311              :                     stops.erase(stops.end() - 1);
     312              :                 }
     313              :             }
     314        39307 :             stopAtSink = stops.size() > 0 && stops.back() == sink && jumps.size() == 0;
     315              :         }
     316              :     } else {
     317              :         std::set<const MSEdge*> jumpEdges;
     318        20741 :         for (const MSStop& stop : myStops) {
     319        12228 :             if (stop.pars.jump >= 0) {
     320              :                 jumpEdges.insert(*stop.edge);
     321              :             }
     322              :         }
     323              :         // via takes precedence over stop edges
     324              :         // there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
     325        26550 :         for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
     326        18045 :             MSEdge* viaEdge = MSEdge::dictionary(*it);
     327        18045 :             if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
     328         3098 :                 continue;
     329              :             }
     330              :             assert(viaEdge != 0);
     331        14947 :             if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
     332           24 :                 throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
     333              :             }
     334        14939 :             stops.push_back(viaEdge);
     335              :             if (jumpEdges.count(viaEdge) != 0) {
     336           15 :                 jumps.insert((int)stops.size());
     337              :             }
     338              :         }
     339              :     }
     340              : 
     341              :     int stopIndex = -1;
     342      2721184 :     for (const MSEdge* const stopEdge : stops) {
     343        57916 :         stopIndex++;
     344              :         // !!! need to adapt t here
     345              :         ConstMSEdgeVector into;
     346          758 :         if (jumps.count(stopIndex) != 0) {
     347          758 :             edges.push_back(source);
     348          758 :             source = stopEdge;
     349              :             continue;
     350              :         }
     351        57158 :         router.computeLooped(source, stopEdge, this, t, into, silent);
     352              :         //std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " target=" << (*s)->getID() << " edges=" << toString(into) << "\n";
     353        57158 :         if (into.size() > 0) {
     354              :             into.pop_back();
     355        56960 :             edges.insert(edges.end(), into.begin(), into.end());
     356        56960 :             if (stopEdge->isTazConnector()) {
     357           49 :                 source = into.back();
     358              :                 edges.pop_back();
     359              :             } else {
     360        56911 :                 source = stopEdge;
     361              :             }
     362              :         } else {
     363          198 :             if ((source != sink || !stopAtSink)) {
     364          364 :                 std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
     365          182 :                 if (MSGlobals::gCheckRoutes || silent) {
     366          364 :                     throw ProcessError(error);
     367              :                 } else {
     368          182 :                     WRITE_WARNING(error);
     369            0 :                     edges.push_back(source);
     370              :                 }
     371              :             }
     372           16 :             source = stopEdge;
     373              :         }
     374        57916 :     }
     375      2630869 :     if (stops.empty() && source == sink && onInit
     376        18615 :             && myParameter->departPosProcedure == DepartPosDefinition::GIVEN
     377           91 :             && myParameter->arrivalPosProcedure == ArrivalPosDefinition::GIVEN
     378      2663289 :             && myParameter->departPos > myParameter->arrivalPos) {
     379           14 :         router.computeLooped(source, sink, this, t, edges, silent);
     380              :     } else {
     381      2663254 :         if (!router.compute(source, sink, this, t, edges, silent)) {
     382              :             edges.clear();
     383              :         }
     384              :     }
     385              : 
     386              :     // router.setHint(myCurrEdge, myRoute->end(), this, t);
     387      2663268 :     if (edges.empty() && silent) {
     388              :         return false;
     389              :     }
     390      2662515 :     if (!edges.empty() && edges.front()->isTazConnector()) {
     391              :         edges.erase(edges.begin());
     392              :     }
     393      2662515 :     if (!edges.empty() && edges.back()->isTazConnector()) {
     394              :         edges.pop_back();
     395              :     }
     396      2662515 :     const double routeCost = router.recomputeCosts(edges, this, t);
     397      2662515 :     const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
     398      2662515 :     const double savings = previousCost - routeCost;
     399              :     //if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
     400              :     //    << " onInit=" << onInit
     401              :     //        << " prevEdges=" << toString(oldEdgesRemaining)
     402              :     //        << " newEdges=" << toString(edges)
     403              :     //        << "\n";
     404      2662515 :     replaceRouteEdges(edges, routeCost, savings, info, onInit);
     405              :     // this must be called even if the route could not be replaced
     406      2662515 :     if (onInit) {
     407      2087790 :         if (edges.empty()) {
     408          191 :             if (MSGlobals::gCheckRoutes) {
     409          342 :                 throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
     410           77 :             } else if (source->isTazConnector()) {
     411          385 :                 WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
     412           27 :                 MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
     413              :                 return false;
     414              :             }
     415              :         }
     416      2087649 :         setDepartAndArrivalEdge();
     417      2087649 :         calculateArrivalParams(onInit);
     418              :     }
     419      2662374 :     return !edges.empty();
     420      2664066 : }
     421              : 
     422              : 
     423              : bool
     424      2684213 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
     425      2684213 :     if (edges.empty()) {
     426         1686 :         WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
     427          562 :         if (msgReturn != nullptr) {
     428              :             *msgReturn = "No route found";
     429              :         }
     430          562 :         return false;
     431              :     }
     432              :     // build a new id, first
     433              :     std::string id = getID();
     434      2683651 :     if (id[0] != '!') {
     435      5367302 :         id = "!" + id;
     436              :     }
     437      2683651 :     const std::string idSuffix = id + "!var#";
     438      2683651 :     int varIndex = 1;
     439      2683651 :     id = idSuffix + toString(varIndex);
     440      4886799 :     while (MSRoute::hasRoute(id)) {
     441      4406296 :         id = idSuffix + toString(++varIndex);
     442              :     }
     443      2683651 :     int oldSize = (int)edges.size();
     444      2683651 :     if (!onInit) {
     445       594428 :         const MSEdge* const origin = *getRerouteOrigin();
     446       594428 :         if (origin != *myCurrEdge && edges.front() == origin) {
     447        10664 :             edges.insert(edges.begin(), *myCurrEdge);
     448        10664 :             oldSize = (int)edges.size();
     449              :         }
     450      1188856 :         edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
     451              :     }
     452      2683651 :     if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
     453              :         // re-assign stop iterators when rerouting to a new parkingArea / insertStop
     454              :         return true;
     455              :     }
     456      1447638 :     const RGBColor& c = myRoute->getColor();
     457      1447638 :     MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), std::vector<SUMOVehicleParameter::Stop>());
     458              :     newRoute->setCosts(cost);
     459              :     newRoute->setSavings(savings);
     460      1447638 :     ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
     461      2895276 :     if (!MSRoute::dictionary(id, constRoute)) {
     462            0 :         delete newRoute;
     463            0 :         if (msgReturn != nullptr) {
     464            0 :             *msgReturn = "duplicate routeID '" + id + "'";
     465              :         }
     466            0 :         return false;
     467              :     }
     468              : 
     469              :     std::string msg;
     470      1447670 :     if (check && !hasValidRoute(msg, constRoute)) {
     471            3 :         WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
     472            1 :         if (MSGlobals::gCheckRoutes) {
     473            1 :             if (msgReturn != nullptr) {
     474              :                 *msgReturn = msg;
     475              :             }
     476            1 :             return false;
     477              :         }
     478              :     }
     479      2895274 :     if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
     480              :         return false;
     481              :     }
     482              :     return true;
     483              : }
     484              : 
     485              : 
     486              : bool
     487      1944412 : MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     488              :     const ConstMSEdgeVector& edges = newRoute->getEdges();
     489              :     // rebuild in-vehicle route information
     490      1944412 :     if (onInit) {
     491      1398893 :         myCurrEdge = newRoute->begin();
     492              :     } else {
     493       545519 :         MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
     494       545519 :         if (newCurrEdge == edges.end()) {
     495            2 :             if (msgReturn != nullptr) {
     496            6 :                 *msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
     497              :             }
     498              : #ifdef DEBUG_REPLACE_ROUTE
     499              :             if (DEBUG_COND) {
     500              :                 std::cout << "  newCurrEdge not found\n";
     501              :             }
     502              : #endif
     503            2 :             return false;
     504              :         }
     505       545517 :         if (getLane() != nullptr) {
     506       412728 :             if (getLane()->getEdge().isInternal() && (
     507       412729 :                         (newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
     508            1 :                 if (msgReturn != nullptr) {
     509            1 :                     *msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
     510              :                 }
     511              : #ifdef DEBUG_REPLACE_ROUTE
     512              :                 if (DEBUG_COND) {
     513              :                     std::cout << "  Vehicle is on junction-internal edge leading elsewhere\n";
     514              :                 }
     515              : #endif
     516            1 :                 return false;
     517       412727 :             } else if (getPositionOnLane() > getLane()->getLength()
     518       412732 :                        && (myCurrEdge + 1) != myRoute->end()
     519           10 :                        && (newCurrEdge + 1) != edges.end()
     520       412737 :                        && *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
     521            5 :                 if (msgReturn != nullptr) {
     522            0 :                     *msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
     523              :                 }
     524              : #ifdef DEBUG_REPLACE_ROUTE
     525              :                 if (DEBUG_COND) {
     526              :                     std::cout << "  Vehicle is moving past junction and committed to move to another successor edge\n";
     527              :                 }
     528              : #endif
     529            5 :                 return false;
     530              :             }
     531              :         }
     532       545511 :         myCurrEdge = newCurrEdge;
     533              :     }
     534      1944404 :     const bool stopsFromScratch = onInit && myRoute->getStops().empty();
     535              :     // assign new route
     536      1944404 :     checkRouteRemoval();
     537              :     myRoute = newRoute;
     538              :     // update arrival definition
     539      1944404 :     calculateArrivalParams(onInit);
     540              :     // save information that the vehicle was rerouted
     541      1944404 :     myNumberReroutes++;
     542      1944404 :     myStopUntilOffset += myRoute->getPeriod();
     543      1944404 :     MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
     544              : #ifdef DEBUG_REPLACE_ROUTE
     545              :     if (DEBUG_COND) {
     546              :         std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
     547              :                   << " lane=" << Named::getIDSecure(getLane())
     548              :                   << " stopsFromScratch=" << stopsFromScratch
     549              :                   << "  newSize=" << newRoute->getEdges().size()
     550              :                   << " newIndex=" << (myCurrEdge - newRoute->begin())
     551              :                   << " edges=" << toString(newRoute->getEdges())
     552              :                   << "\n";
     553              :     }
     554              : #endif
     555              :     // remove past stops which are not on the route anymore
     556      2003568 :     for (std::vector<SUMOVehicleParameter::Stop>::iterator it = myPastStops.begin(); it != myPastStops.end();) {
     557        85485 :         const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
     558        59164 :         if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
     559            3 :             it = myPastStops.erase(it);
     560              :         } else {
     561              :             ++it;
     562              :         }
     563              :     }
     564              :     // if we did not drive yet it may be best to simply reassign the stops from scratch
     565      1944404 :     if (stopsFromScratch) {
     566              :         myStops.clear();
     567      1398829 :         addStops(!MSGlobals::gCheckRoutes);
     568              :     } else {
     569              :         // recheck old stops
     570       545575 :         MSRouteIterator searchStart = myCurrEdge;
     571       545575 :         double lastPos = getPositionOnLane() + getBrakeGap();
     572       958297 :         if (getLane() != nullptr && getLane()->isInternal()
     573       546426 :                 && myStops.size() > 0 && !myStops.front().lane->isInternal()) {
     574              :             // searchStart is still incoming to the intersection so lastPos
     575              :             // relative to that edge must be adapted
     576          193 :             lastPos += (*myCurrEdge)->getLength();
     577              :         }
     578              :         int stopIndex = 0;
     579       576397 :         for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
     580        30822 :             double endPos = iter->getEndPos(*this);
     581              : #ifdef DEBUG_REPLACE_ROUTE
     582              :             if (DEBUG_COND) {
     583              :                 std::cout << "     stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
     584              :             }
     585              : #endif
     586        30822 :             if (*searchStart != &iter->lane->getEdge()
     587        30822 :                     || endPos + NUMERICAL_EPS < lastPos) {
     588        27895 :                 if (searchStart != edges.end() && !iter->reached) {
     589              :                     searchStart++;
     590              :                 }
     591              :             }
     592              :             lastPos = endPos;
     593              : 
     594        30822 :             iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
     595              : #ifdef DEBUG_REPLACE_ROUTE
     596              :             if (DEBUG_COND) {
     597              :                 std::cout << "        foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
     598              :             }
     599              : #endif
     600        30822 :             if (iter->edge == edges.end()) {
     601          187 :                 if (!removeStops) {
     602            8 :                     WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
     603              :                 }
     604          187 :                 iter = myStops.erase(iter);
     605          187 :                 continue;
     606              :             } else {
     607        30635 :                 setSkips(*iter, stopIndex);
     608        30635 :                 searchStart = iter->edge;
     609              :             }
     610              :             ++iter;
     611        30635 :             stopIndex++;
     612              :         }
     613              :         // add new stops
     614       545575 :         if (addRouteStops) {
     615       497030 :             for (std::vector<SUMOVehicleParameter::Stop>::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
     616              :                 std::string error;
     617          307 :                 addStop(*i, error, myParameter->depart + myStopUntilOffset);
     618          307 :                 if (error != "") {
     619            0 :                     WRITE_WARNING(error);
     620              :                 }
     621              :             }
     622              :         }
     623              :     }
     624              :     return true;
     625              : }
     626              : 
     627              : 
     628              : double
     629       160540 : MSBaseVehicle::getAcceleration() const {
     630       160540 :     return 0;
     631              : }
     632              : 
     633              : 
     634              : void
     635      3312499 : MSBaseVehicle::onDepart() {
     636      3312499 :     myDeparture = MSNet::getInstance()->getCurrentTimeStep();
     637      3312499 :     myDepartPos = getPositionOnLane();
     638      3312499 :     MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
     639      3312499 : }
     640              : 
     641              : 
     642              : SUMOTime
     643      2629428 : MSBaseVehicle:: getDepartDelay() const {
     644      2629428 :     const SUMOTime dep = getParameter().depart;
     645      2629428 :     if (dep < 0) {
     646              :         return 0;
     647              :     }
     648      2629321 :     return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
     649              : }
     650              : 
     651              : 
     652              : bool
     653            0 : MSBaseVehicle::hasArrived() const {
     654            0 :     return succEdge(1) == nullptr;
     655              : }
     656              : 
     657              : 
     658              : int
     659     23489453 : MSBaseVehicle::getRoutePosition() const {
     660     23489453 :     return (int) std::distance(myRoute->begin(), myCurrEdge);
     661              : }
     662              : 
     663              : 
     664              : void
     665       100994 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
     666       100994 :     myCurrEdge = myRoute->begin() + index;
     667       100994 :     const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
     668              :     // !!! hack
     669       100994 :     myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
     670       100994 : }
     671              : 
     672              : double
     673       975632 : MSBaseVehicle::getOdometer() const {
     674       975632 :     return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
     675              : }
     676              : 
     677              : bool
     678       310428 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
     679       310428 :     if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
     680              :         return false;
     681       206699 :     } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
     682              :         return false;
     683              :     }
     684       296487 :     if (isStopped() && myStops.begin()->pars.permitted.size() > 0
     685       148299 :             && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
     686         5844 :         return false;
     687              :     }
     688       142455 :     MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     689              :     if (taxiDevice != nullptr) {
     690        23255 :         return taxiDevice->allowsBoarding(t);
     691              :     }
     692              :     return true;
     693              : }
     694              : 
     695              : 
     696              : void
     697        12879 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
     698        12879 :     if (transportable->isPerson()) {
     699        12149 :         if (myPersonDevice == nullptr) {
     700         4158 :             myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
     701         4158 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
     702         4158 :             if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
     703         1901 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     704              :             }
     705              :         }
     706        12149 :         myPersonDevice->addTransportable(transportable);
     707              :     } else {
     708          730 :         if (myContainerDevice == nullptr) {
     709          404 :             myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
     710          404 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
     711          404 :             if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
     712           79 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     713              :             }
     714              :         }
     715          730 :         myContainerDevice->addTransportable(transportable);
     716              :     }
     717        12879 : }
     718              : 
     719              : 
     720              : bool
     721         2050 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
     722         2827 :     for (const MSStop& stop : myStops) {
     723         1033 :         if (stop.edge == it) {
     724          256 :             return stop.pars.jump >= 0;
     725              :         }
     726              :     }
     727              :     return false;
     728              : }
     729              : 
     730              : 
     731              : bool
     732      3743070 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
     733      3743070 :     MSRouteIterator start = myCurrEdge;
     734      3743070 :     if (route == nullptr) {
     735              :         route = myRoute;
     736              :     } else {
     737      3067749 :         start = route->begin();
     738              :     }
     739              :     const bool checkJumps = route == myRoute;  // the edge iterators in the stops are invalid otherwise
     740      3743070 :     MSRouteIterator last = route->end() - 1;
     741              :     // check connectivity, first
     742     19429211 :     for (MSRouteIterator e = start; e != last; ++e) {
     743     15720231 :         const MSEdge& next = **(e + 1);
     744     15720231 :         if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
     745        34237 :             if (!checkJumps || !hasJump(e)) {
     746        34144 :                 if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
     747        34144 :                         || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
     748       102270 :                     msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
     749        34090 :                     return false;
     750              :                 }
     751              :             }
     752              :         }
     753              :     }
     754      3708980 :     last = route->end();
     755              :     // check usable lanes, then
     756     23103246 :     for (MSRouteIterator e = start; e != last; ++e) {
     757     19394266 :         if ((*e)->prohibits(this)) {
     758            0 :             msg = TLF("Edge '%' prohibits.", (*e)->getID());
     759              :             return false;
     760              :         }
     761              :     }
     762              :     return true;
     763              : }
     764              : 
     765              : 
     766              : bool
     767    506537583 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
     768    506537583 :     if (!(*myCurrEdge)->isTazConnector()) {
     769    506400537 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
     770           12 :             msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
     771            6 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
     772            6 :             return false;
     773              :         }
     774              :     }
     775    506537577 :     if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
     776    506537519 :         myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
     777    506537519 :         return true;
     778              :     } else {
     779          174 :         msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
     780           58 :         myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
     781           58 :         return false;
     782              :     }
     783              : }
     784              : 
     785              : 
     786              : int
     787   4820402668 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
     788   4820402668 :     if (!update) {
     789   2049355747 :         return myRouteValidity;
     790              :     }
     791              :     // insertion check must be done in any case
     792              :     std::string msg;
     793   2771046921 :     if (!hasValidRouteStart(msg)) {
     794          182 :         if (MSGlobals::gCheckRoutes) {
     795          220 :             throw ProcessError(msg);
     796           72 :         } else if (!silent) {
     797              :             // vehicle will be discarded
     798          138 :             WRITE_WARNING(msg);
     799           26 :         } else if (msgReturn != nullptr) {
     800              :             *msgReturn = msg;
     801              :         }
     802              :     }
     803              :     if (MSGlobals::gCheckRoutes
     804   2771032208 :             && (myRouteValidity & ROUTE_UNCHECKED) != 0
     805              :             // we could check after the first rerouting
     806   2775533935 :             && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
     807      6066468 :         if (!hasValidRoute(msg, myRoute)) {
     808           72 :             myRouteValidity |= ROUTE_INVALID;
     809          216 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
     810              :         }
     811              :     }
     812   2771046739 :     myRouteValidity &= ~ROUTE_UNCHECKED;
     813              :     return myRouteValidity;
     814              : }
     815              : 
     816              : void
     817     19433491 : MSBaseVehicle::addReminder(MSMoveReminder* rem) {
     818              : #ifdef _DEBUG
     819              :     if (myTraceMoveReminders) {
     820              :         traceMoveReminder("add", rem, 0, true);
     821              :     }
     822              : #endif
     823     19433491 :     myMoveReminders.push_back(std::make_pair(rem, 0.));
     824     19433491 : }
     825              : 
     826              : 
     827              : void
     828            0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
     829            0 :     for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
     830            0 :         if (r->first == rem) {
     831              : #ifdef _DEBUG
     832              :             if (myTraceMoveReminders) {
     833              :                 traceMoveReminder("remove", rem, 0, false);
     834              :             }
     835              : #endif
     836              :             myMoveReminders.erase(r);
     837              :             return;
     838              :         }
     839              :     }
     840              : }
     841              : 
     842              : 
     843              : void
     844     23773517 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     845     54045788 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
     846     30272271 :         if (rem->first->notifyEnter(*this, reason, enteredLane)) {
     847              : #ifdef _DEBUG
     848              :             if (myTraceMoveReminders) {
     849              :                 traceMoveReminder("notifyEnter", rem->first, rem->second, true);
     850              :             }
     851              : #endif
     852              :             ++rem;
     853              :         } else {
     854              : #ifdef _DEBUG
     855              :             if (myTraceMoveReminders) {
     856              :                 traceMoveReminder("notifyEnter", rem->first, rem->second, false);
     857              :             }
     858              : #endif
     859              :             rem = myMoveReminders.erase(rem);
     860              :         }
     861              :     }
     862     23773517 : }
     863              : 
     864              : 
     865              : void
     866      7154728 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
     867      7154728 :     if (myRoute->getLastEdge()->isTazConnector()) {
     868              :         return;
     869              :     }
     870      7154728 :     const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
     871      7154728 :     if (arrivalEdgeIndex != myParameter->arrivalEdge) {
     872           42 :         WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
     873              :                        getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
     874              :     }
     875      7154728 :     const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
     876      7154728 :     if (!onInit) {
     877       545511 :         arrivalEdge = myRoute->getLastEdge();
     878              :         // ignore arrivalEdge parameter after rerouting
     879       545511 :         const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
     880              :     }
     881              :     const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
     882      7154728 :     const double lastLaneLength = lanes[0]->getLength();
     883      7154728 :     switch (myParameter->arrivalPosProcedure) {
     884       201239 :         case ArrivalPosDefinition::GIVEN:
     885       201239 :             if (fabs(myParameter->arrivalPos) > lastLaneLength) {
     886         3048 :                 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
     887              :             }
     888              :             // Maybe we should warn the user about invalid inputs!
     889       201239 :             myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
     890       201239 :             if (myArrivalPos < 0) {
     891        20597 :                 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
     892              :             }
     893              :             break;
     894              :         case ArrivalPosDefinition::RANDOM:
     895        74093 :             myArrivalPos = RandHelper::rand(lastLaneLength);
     896        74093 :             break;
     897            0 :         case ArrivalPosDefinition::CENTER:
     898            0 :             myArrivalPos = lastLaneLength / 2.;
     899            0 :             break;
     900      6879396 :         default:
     901      6879396 :             myArrivalPos = lastLaneLength;
     902      6879396 :             break;
     903              :     }
     904      7154728 :     if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
     905       115107 :         if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
     906       283707 :             WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
     907              :         }
     908       115107 :         myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
     909      7039621 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
     910            7 :         myArrivalLane = -1;
     911            7 :         for (MSLane* lane : lanes) {
     912            7 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
     913            7 :                 myArrivalLane = lane->getIndex();
     914            7 :                 break;
     915              :             }
     916              :         }
     917            7 :         if (myArrivalLane == -1) {
     918            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
     919            0 :             myArrivalLane = 0;
     920              :         }
     921      7039614 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
     922              :         // pick random lane among all usable lanes
     923              :         std::vector<MSLane*> usable;
     924       364240 :         for (MSLane* lane : lanes) {
     925       279473 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
     926       261555 :                 usable.push_back(lane);
     927              :             }
     928              :         }
     929        84767 :         if (usable.empty()) {
     930            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
     931            0 :             myArrivalLane = 0;
     932              :         } else {
     933        84767 :             myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
     934              :         }
     935        84767 :     }
     936      7154728 :     if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
     937       180561 :         for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
     938       142241 :             if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
     939              :                 return;
     940              :             }
     941              :         }
     942       114960 :         WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
     943              :     }
     944              : }
     945              : 
     946              : void
     947      5208960 : MSBaseVehicle::setDepartAndArrivalEdge() {
     948      5208960 :     SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
     949      5208960 :     if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
     950         7871 :         const int routeEdges = (int)myRoute->getEdges().size();
     951         7871 :         if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
     952              :             // write specific edge in vehroute output for reproducibility
     953         4185 :             pars->departEdge = RandHelper::rand(0, routeEdges);
     954         4185 :             pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
     955              :         }
     956              :         assert(pars->departEdge >= 0);
     957         7871 :         if (pars->departEdge >= routeEdges) {
     958            0 :             WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
     959              :         } else {
     960              :             myCurrEdge += pars->departEdge;
     961              :         }
     962              :     }
     963      5208960 :     if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
     964          147 :         const int routeEdges = (int)myRoute->getEdges().size();
     965          147 :         const int begin = (int)(myCurrEdge - myRoute->begin());
     966              :         // write specific edge in vehroute output for reproducibility
     967          147 :         pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
     968          147 :         pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
     969              :         assert(pars->arrivalEdge >= begin);
     970              :         assert(pars->arrivalEdge < routeEdges);
     971              :     }
     972      5208960 : }
     973              : 
     974              : 
     975              : double
     976    569177424 : MSBaseVehicle::getImpatience() const {
     977   1138354848 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
     978    569177424 :                          + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
     979    569177424 :                          + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
     980              : }
     981              : 
     982              : 
     983              : MSDevice*
     984    780480000 : MSBaseVehicle::getDevice(const std::type_info& type) const {
     985   1409702870 :     for (MSVehicleDevice* const dev : myDevices) {
     986    684317369 :         if (typeid(*dev) == type) {
     987     55094499 :             return dev;
     988              :         }
     989              :     }
     990              :     return nullptr;
     991              : }
     992              : 
     993              : 
     994              : void
     995         2817 : MSBaseVehicle::saveState(OutputDevice& out) {
     996              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
     997         2817 :     const std::string& typeID = MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myParameter->vtypeid) || getVehicleType().isVehicleSpecific() ? getVehicleType().getID() : "";
     998         2817 :     myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
     999              :     // params and stops must be written in child classes since they may wish to add additional attributes first
    1000              :     out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
    1001         2817 :     std::ostringstream os;
    1002         5634 :     os << myOdometer << " " << myNumberReroutes;
    1003         2817 :     out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
    1004         2817 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
    1005         2817 :         const int precision = out.precision();
    1006         2817 :         out.setPrecision(MAX2(gPrecisionRandom, precision));
    1007         2817 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
    1008         2817 :         out.setPrecision(precision);
    1009              :     }
    1010         2817 :     if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    1011         3872 :         out.writeAttr(SUMO_ATTR_REROUTE, true);
    1012              :     }
    1013         2817 :     if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
    1014              :         // could be set from stop
    1015              :         out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
    1016              :     }
    1017              :     // here starts the vehicle internal part (see loading)
    1018              :     // @note: remember to close the vehicle tag when calling this in a subclass!
    1019         5634 : }
    1020              : 
    1021              : 
    1022              : bool
    1023            0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    1024              :     UNUSED_PARAMETER(stop);
    1025              :     UNUSED_PARAMETER(distToStop);
    1026            0 :     return true;
    1027              : }
    1028              : 
    1029              : 
    1030              : bool
    1031   7067913346 : MSBaseVehicle::isStopped() const {
    1032   7067913346 :     return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
    1033              : }
    1034              : 
    1035              : 
    1036              : bool
    1037   2015600985 : MSBaseVehicle::isParking() const {
    1038   2063104700 :     return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
    1039       328977 :             && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
    1040   2015809182 :             && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
    1041              : }
    1042              : 
    1043              : 
    1044              : bool
    1045    523621942 : MSBaseVehicle::isJumping() const {
    1046    523621942 :     return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
    1047              : }
    1048              : 
    1049              : 
    1050              : bool
    1051      6250870 : MSBaseVehicle::isStoppedTriggered() const {
    1052      6250870 :     return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
    1053              : }
    1054              : 
    1055              : 
    1056              : bool
    1057        23795 : MSBaseVehicle::isStoppedParking() const {
    1058        23795 :     return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
    1059              : }
    1060              : 
    1061              : 
    1062              : bool
    1063        17230 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
    1064        17230 :     if (isStopped() || (checkFuture && hasStops())) {
    1065              :         const MSStop& stop = myStops.front();
    1066        18147 :         return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
    1067              :     }
    1068              :     return false;
    1069              : }
    1070              : 
    1071              : bool
    1072        11470 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
    1073              :     // Check if there is a parking area to be replaced
    1074        11470 :     if (parkingArea == 0) {
    1075              :         errorMsg = "new parkingArea is NULL";
    1076            0 :         return false;
    1077              :     }
    1078        11470 :     if (myStops.size() == 0) {
    1079              :         errorMsg = "vehicle has no stops";
    1080            0 :         return false;
    1081              :     }
    1082        11470 :     if (myStops.front().parkingarea == 0) {
    1083              :         errorMsg = "first stop is not at parkingArea";
    1084            0 :         return false;
    1085              :     }
    1086              :     MSStop& first = myStops.front();
    1087              :     SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
    1088        11470 :     std::string oldStopEdgeID = first.lane->getEdge().getID();
    1089              :     // merge subsequent duplicate stops equals to parking area
    1090        11490 :     for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
    1091          331 :         if (iter->parkingarea == parkingArea) {
    1092           20 :             stopPar.duration += iter->duration;
    1093           20 :             myStops.erase(iter++);
    1094              :         } else {
    1095              :             break;
    1096              :         }
    1097              :     }
    1098        11470 :     stopPar.lane = parkingArea->getLane().getID();
    1099        11470 :     stopPar.parkingarea = parkingArea->getID();
    1100        11470 :     stopPar.startPos = parkingArea->getBeginLanePosition();
    1101        11470 :     stopPar.endPos = parkingArea->getEndLanePosition();
    1102        11470 :     first.edge = myRoute->end(); // will be patched in replaceRoute
    1103        11470 :     first.lane = &parkingArea->getLane();
    1104        11470 :     first.parkingarea = parkingArea;
    1105              : 
    1106              :     // patch via edges
    1107        11470 :     std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
    1108        11470 :     if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
    1109          198 :         myParameter->via.erase(myParameter->via.begin());
    1110          198 :         myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
    1111              :     }
    1112              :     return true;
    1113              : }
    1114              : 
    1115              : 
    1116              : MSParkingArea*
    1117        58597 : MSBaseVehicle::getNextParkingArea() {
    1118              :     MSParkingArea* nextParkingArea = nullptr;
    1119        58597 :     if (!myStops.empty()) {
    1120        57646 :         SUMOVehicleParameter::Stop stopPar;
    1121        57646 :         MSStop stop = myStops.front();
    1122        57646 :         if (!stop.reached && stop.parkingarea != nullptr) {
    1123              :             nextParkingArea = stop.parkingarea;
    1124              :         }
    1125        57646 :     }
    1126        58597 :     return nextParkingArea;
    1127              : }
    1128              : 
    1129              : 
    1130              : MSParkingArea*
    1131        84783 : MSBaseVehicle::getCurrentParkingArea() {
    1132              :     MSParkingArea* currentParkingArea = nullptr;
    1133        84783 :     if (isParking()) {
    1134        84766 :         currentParkingArea = myStops.begin()->parkingarea;
    1135              :     }
    1136        84783 :     return currentParkingArea;
    1137              : }
    1138              : 
    1139              : 
    1140              : const std::vector<std::string>&
    1141           21 : MSBaseVehicle::getParkingBadges() const {
    1142           21 :     if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
    1143            7 :         return myParameter->parkingBadges;
    1144              :     } else {
    1145           14 :         return getVehicleType().getParkingBadges();
    1146              :     }
    1147              : }
    1148              : 
    1149              : 
    1150              : double
    1151      7571939 : MSBaseVehicle::basePos(const MSEdge* edge) const {
    1152      7571939 :     double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
    1153      7571939 :     if (hasStops()
    1154      7596515 :             && myStops.front().edge == myRoute->begin()
    1155      7596515 :             && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
    1156        24548 :         result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
    1157              :     }
    1158      7571939 :     return result;
    1159              : }
    1160              : 
    1161              : 
    1162              : MSLane*
    1163          298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
    1164          298 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
    1165          298 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
    1166          298 :     if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
    1167            8 :         return nullptr;
    1168              :     }
    1169          580 :     const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
    1170          290 :     if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
    1171          290 :         const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
    1172          290 :         stop.edge = edgeID;
    1173          290 :         return edge->getOppositeEdge()->getLanes()[oppositeIndex];
    1174              :     }
    1175              :     return nullptr;
    1176              : }
    1177              : 
    1178              : 
    1179              : bool
    1180       127803 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
    1181              :                        MSRouteIterator* searchStart) {
    1182       127803 :     MSStop stop(stopPar);
    1183       127803 :     if (stopPar.lane == "") {
    1184         2465 :         MSEdge* e = MSEdge::dictionary(stopPar.edge);
    1185         2465 :         stop.lane = e->getFirstAllowed(getVClass());
    1186         2465 :         if (stop.lane == nullptr) {
    1187            0 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
    1188            0 :             return false;
    1189              :         }
    1190              :     } else {
    1191       125338 :         stop.lane = MSLane::dictionary(stopPar.lane);
    1192       125338 :         if (stop.lane == nullptr) {
    1193              :             // must be an opposite stop
    1194          145 :             SUMOVehicleParameter::Stop tmp = stopPar;
    1195          145 :             stop.lane = interpretOppositeStop(tmp);
    1196              :             assert(stop.lane != nullptr);
    1197          145 :         }
    1198       125338 :         if (!stop.lane->allowsVehicleClass(myType->getVehicleClass())) {
    1199           32 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
    1200           16 :             return false;
    1201              :         }
    1202              :     }
    1203       127787 :     if (MSGlobals::gUseMesoSim) {
    1204        16278 :         stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
    1205        16278 :         if (stop.lane->isInternal()) {
    1206            2 :             errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
    1207            1 :             return false;
    1208              :         }
    1209              :     }
    1210       127786 :     stop.initPars(stopPar);
    1211       127786 :     if (stopPar.until != -1) {
    1212              :         // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
    1213        41021 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
    1214              :     }
    1215       127786 :     if (stopPar.arrival != -1) {
    1216          589 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
    1217              :     }
    1218       127786 :     std::string stopType = "stop";
    1219       127786 :     std::string stopID = "";
    1220       127786 :     if (stop.busstop != nullptr) {
    1221              :         stopType = "busStop";
    1222        33469 :         stopID = stop.busstop->getID();
    1223        94317 :     } else if (stop.containerstop != nullptr) {
    1224              :         stopType = "containerStop";
    1225          727 :         stopID = stop.containerstop->getID();
    1226        93590 :     } else if (stop.chargingStation != nullptr) {
    1227              :         stopType = "chargingStation";
    1228         8067 :         stopID = stop.chargingStation->getID();
    1229        85523 :     } else if (stop.overheadWireSegment != nullptr) {
    1230              :         stopType = "overheadWireSegment";
    1231            0 :         stopID = stop.overheadWireSegment->getID();
    1232        85523 :     } else if (stop.parkingarea != nullptr) {
    1233              :         stopType = "parkingArea";
    1234        16242 :         stopID = stop.parkingarea->getID();
    1235              :     }
    1236       255572 :     const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
    1237              : 
    1238       127786 :     if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
    1239            0 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
    1240            0 :         return false;
    1241              :     }
    1242        58505 :     if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
    1243       187164 :             && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
    1244          834 :         errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
    1245              :     }
    1246       127786 :     if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
    1247              :         // forbid access in case the parking requests other badges
    1248           14 :         errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
    1249            7 :         return false;
    1250              :     }
    1251       127779 :     const MSEdge* stopLaneEdge = &stop.lane->getEdge();
    1252              :     const MSEdge* stopEdge;
    1253       127779 :     if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
    1254              :         // stop lane is on the opposite side
    1255          145 :         stopEdge = stopLaneEdge->getOppositeEdge();
    1256          145 :         stop.isOpposite = true;
    1257              :     } else {
    1258              :         // if stop is on an internal edge the normal edge before the intersection is used
    1259       127634 :         stopEdge = stopLaneEdge->getNormalBefore();
    1260              :     }
    1261       127779 :     MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
    1262       127779 :     if (searchStart == nullptr) {
    1263       124325 :         searchStart = &myCurrEdge;
    1264       124325 :         if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
    1265              :             // already on the intersection but myCurrEdge is before it
    1266              :             searchStart = &succ;
    1267              :         }
    1268              :     }
    1269              : #ifdef DEBUG_ADD_STOP
    1270              :     if (DEBUG_COND) {
    1271              :         std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
    1272              :                   << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
    1273              :                   << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
    1274              :                   << "\n";
    1275              :     }
    1276              : #endif
    1277       127779 :     stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
    1278       127779 :     MSRouteIterator prevStopEdge = myCurrEdge;
    1279       127779 :     const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
    1280       127779 :     double prevStopPos = getPositionOnLane();
    1281              :     // where to insert the stop
    1282              :     std::list<MSStop>::iterator iter = myStops.begin();
    1283       127779 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
    1284              :         iter = myStops.end();
    1285       103439 :         if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
    1286              :             prevStopEdge = myStops.back().edge;
    1287        38877 :             prevEdge = &myStops.back().lane->getEdge();
    1288        38877 :             prevStopPos = myStops.back().pars.endPos;
    1289        38877 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1290              :             if (prevStopEdge == stop.edge                // laneEdge check is insufficient for looped routes
    1291         5979 :                     && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
    1292        44844 :                     && (prevStopPos > stop.pars.endPos ||
    1293         2481 :                         (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
    1294          424 :                 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
    1295              :             }
    1296              : #ifdef DEBUG_ADD_STOP
    1297              :             if (DEBUG_COND) {
    1298              :                 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
    1299              :                           << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
    1300              :             }
    1301              : #endif
    1302              :         }
    1303              :         // skip a number of occurences of stopEdge in looped route
    1304       103439 :         int skipLooped = stopPar.index - static_cast<int>(myStops.size());
    1305       103524 :         for (int j = 0; j < skipLooped; j++) {
    1306          231 :             auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
    1307          231 :             if (nextIt == myRoute->end()) {
    1308          146 :                 if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
    1309              :                     // only warn if the route loops over the stop edge at least once
    1310           28 :                     errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
    1311              :                 }
    1312          146 :                 break;
    1313              :             } else {
    1314           85 :                 stop.edge = nextIt;
    1315              :             }
    1316              :         }
    1317              :     } else {
    1318        24340 :         if (stopPar.index == STOP_INDEX_FIT) {
    1319        36241 :             while (iter != myStops.end() && (iter->edge < stop.edge ||
    1320         1991 :                                              (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
    1321         1991 :                                              (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
    1322              :                 prevStopEdge = iter->edge;
    1323        12000 :                 prevStopPos = iter->pars.endPos;
    1324              :                 ++iter;
    1325              :             }
    1326              :         } else {
    1327              :             int index = stopPar.index;
    1328           99 :             while (index > 0) {
    1329            0 :                 prevStopEdge = iter->edge;
    1330            0 :                 prevStopPos = iter->pars.endPos;
    1331              :                 ++iter;
    1332            0 :                 --index;
    1333              :             }
    1334              : #ifdef DEBUG_ADD_STOP
    1335              :             if (DEBUG_COND) {
    1336              :                 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
    1337              :             }
    1338              : #endif
    1339           99 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1340              :         }
    1341              :     }
    1342       128080 :     const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
    1343       127779 :     if (stop.edge == myRoute->end()) {
    1344           72 :         if (!wasTooClose) {
    1345          192 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
    1346              :         }
    1347           72 :         return false;
    1348              :     }
    1349              : 
    1350       127707 :     const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
    1351        32676 :                            prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
    1352              : 
    1353       127707 :     if (prevStopEdge > stop.edge ||
    1354              :             // a collision-stop happens after vehicle movement and may move the
    1355              :             // vehicle backwards on its lane (prevStopPos is the vehicle position)
    1356         1575 :             (tooClose && !stop.pars.collision)
    1357       255398 :             || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
    1358              :         // check if the edge occurs again later in the route
    1359              :         //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges())  << "\n";
    1360           16 :         if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
    1361           48 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
    1362              :         }
    1363           16 :         MSRouteIterator next = stop.edge + 1;
    1364           16 :         return addStop(stopPar, errorMsg, untilOffset, &next);
    1365              :     }
    1366       127691 :     if (wasTooClose) {
    1367              :         errorMsg = "";
    1368              :     }
    1369              :     // David.C:
    1370              :     //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
    1371       127691 :     const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
    1372       127691 :     const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
    1373       127691 :     if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
    1374              :         return false;
    1375              :     }
    1376       127691 :     if (!hasDeparted() && myCurrEdge == stop.edge) {
    1377              :         double pos = -1;
    1378        26180 :         if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
    1379         4597 :             pos = myParameter->departPos;
    1380         4597 :             if (pos < 0.) {
    1381          194 :                 pos += (*myCurrEdge)->getLength();
    1382              :             }
    1383              :         }
    1384        26180 :         if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
    1385        19190 :             pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
    1386              :         }
    1387        26180 :         if (pos > stop.pars.endPos + endPosOffset) {
    1388           20 :             if (stop.edge != myRoute->end()) {
    1389              :                 // check if the edge occurs again later in the route
    1390           20 :                 MSRouteIterator next = stop.edge + 1;
    1391           20 :                 return addStop(stopPar, errorMsg, untilOffset, &next);
    1392              :             }
    1393            0 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
    1394            0 :             return false;
    1395              :         }
    1396              :     }
    1397       127671 :     if (iter != myStops.begin()) {
    1398              :         std::list<MSStop>::iterator iter2 = iter;
    1399              :         iter2--;
    1400        75539 :         if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
    1401        50836 :                 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
    1402            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1403           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1404           24 :                        + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
    1405              :         }
    1406        50819 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1407            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1408           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1409           24 :                        + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
    1410              :         }
    1411        50819 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1412            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1413           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1414           24 :                        + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
    1415              :         }
    1416              :     } else {
    1417        93149 :         if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
    1418        76864 :                 && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
    1419            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1420           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1421           24 :                        + " earlier than departure at " + time2string(getParameter().depart) + ".";
    1422              :         }
    1423              :     }
    1424       127671 :     if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
    1425           18 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1426           54 :                    + "' set to end at " + time2string(stop.getUntil())
    1427           72 :                    + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
    1428              :     }
    1429       127671 :     setSkips(stop, (int)myStops.size());
    1430       127671 :     myStops.insert(iter, stop);
    1431       127671 :     if (stopPar.tripId != "") {
    1432         2500 :         MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
    1433              :     }
    1434              :     //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
    1435              :     //    << " routeIndex=" << (stop.edge - myRoute->begin())
    1436              :     //    << " stopIndex=" << std::distance(myStops.begin(), iter)
    1437              :     //    << " route=" << toString(myRoute->getEdges())  << "\n";
    1438              :     return true;
    1439              : }
    1440              : 
    1441              : 
    1442              : void
    1443       158306 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
    1444       158306 :     if (hasDeparted() && stop.edge > myRoute->begin()) {
    1445              :         // if the route is looped we must patch the index to ensure that state
    1446              :         // loading (and vehroute-output) encode the correct number of skips
    1447              :         int foundSkips = 0;
    1448              :         MSRouteIterator itPrev;
    1449              :         double prevEndPos;
    1450        61880 :         if (prevActiveStops > 0) {
    1451              :             assert((int)myStops.size() >= prevActiveStops);
    1452              :             auto prevStopIt = myStops.begin();
    1453        32231 :             std::advance(prevStopIt, prevActiveStops - 1);
    1454              :             const MSStop& prev = *prevStopIt;
    1455        32231 :             itPrev = prev.edge;
    1456        32231 :             prevEndPos = prev.pars.endPos;
    1457        29649 :         } else if (myPastStops.size() > 0) {
    1458        11800 :             itPrev = myRoute->begin() + myPastStops.back().routeIndex;
    1459        11800 :             prevEndPos = myPastStops.back().endPos;
    1460              :         } else {
    1461        17849 :             itPrev = myRoute->begin() + myParameter->departEdge;
    1462        17849 :             prevEndPos = myDepartPos;
    1463              :         }
    1464              :         //auto itPrevOrig = itPrev;
    1465        61880 :         if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
    1466              :             itPrev++;
    1467              :         }
    1468              :         //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
    1469       584204 :         while (itPrev < stop.edge) {
    1470       522324 :             if (*itPrev == *stop.edge) {
    1471        19570 :                 foundSkips++;
    1472              :             }
    1473              :             itPrev++;
    1474              :         }
    1475              :         int newIndex = STOP_INDEX_END;
    1476        61880 :         if (foundSkips > 0) {
    1477              :             //if (getID() == "77_0_0") {
    1478              :             //    std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
    1479              :             //        << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
    1480              :             //        << " prevEdge=" << (*itPrevOrig)->getID()
    1481              :             //        << " prevIndex=" << (itPrevOrig - myRoute->begin())
    1482              :             //        << " skips=" << foundSkips << "\n";
    1483              :             //}
    1484         7021 :             newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
    1485              :         }
    1486        61880 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
    1487              :     }
    1488       158306 : }
    1489              : 
    1490              : 
    1491              : void
    1492      6012440 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
    1493      6012440 :     if (addRouteStops) {
    1494      6016536 :         for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    1495              :             std::string errorMsg;
    1496         8541 :             if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
    1497           20 :                 throw ProcessError(errorMsg);
    1498              :             }
    1499         8531 :             if (errorMsg != "") {
    1500          694 :                 WRITE_WARNING(errorMsg);
    1501              :             }
    1502              :         }
    1503              :     }
    1504      6012430 :     const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
    1505      6101091 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    1506              :         std::string errorMsg;
    1507        88684 :         if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
    1508           46 :             throw ProcessError(errorMsg);
    1509              :         }
    1510        88661 :         if (errorMsg != "") {
    1511          452 :             WRITE_WARNING(errorMsg);
    1512              :         }
    1513              :     }
    1514      6012407 : }
    1515              : 
    1516              : 
    1517              : bool
    1518      1239933 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
    1519      1239933 :     MSRouteIterator start = myCurrEdge;
    1520              :     int i = 0;
    1521              :     bool ok = true;
    1522      1292173 :     for (const MSStop& stop : myStops) {
    1523              :         MSRouteIterator it;
    1524        52240 :         if (stop.lane->isInternal()) {
    1525              :             // find the normal predecessor and ensure that the next route edge
    1526              :             // matches the successor of the internal edge successor
    1527            0 :             it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
    1528            0 :             if (it != myRoute->end() && (
    1529            0 :                         it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
    1530            0 :                 it = myRoute->end(); // signal failure
    1531              :             }
    1532              :         } else {
    1533        52240 :             it = std::find(start, myRoute->end(), &stop.lane->getEdge());
    1534              :         }
    1535        52240 :         if (it == myRoute->end()) {
    1536            0 :             if (!silent) {
    1537            0 :                 WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
    1538              :                              i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1539              :             }
    1540              :             ok = false;
    1541              :         } else {
    1542              :             MSRouteIterator it2;
    1543      2199752 :             for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
    1544      2195832 :                 if (it2 == stop.edge) {
    1545              :                     break;
    1546              :                 }
    1547              :             }
    1548        52240 :             if (it2 == myRoute->end()) {
    1549         3920 :                 if (!silent) {
    1550            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
    1551              :                                  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
    1552              :                 }
    1553              :                 ok = false;
    1554        48320 :             } else if (it2 < start) {
    1555            0 :                 if (!silent) {
    1556            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
    1557              :                                  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1558              :                 }
    1559              :                 ok = false;
    1560              :             } else {
    1561        48320 :                 start = stop.edge;
    1562              :             }
    1563              :         }
    1564        52240 :         i++;
    1565              :     }
    1566      1239933 :     return ok;
    1567              : }
    1568              : 
    1569              : 
    1570              : const ConstMSEdgeVector
    1571      2654945 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
    1572              :     assert(haveValidStopEdges());
    1573              :     ConstMSEdgeVector result;
    1574              :     const MSStop* prev = nullptr;
    1575      2654945 :     const MSEdge* internalSuccessor = nullptr;
    1576      2731237 :     for (const MSStop& stop : myStops) {
    1577        76292 :         if (stop.reached) {
    1578         9404 :             if (stop.pars.jump >= 0) {
    1579            0 :                 jumps.insert((int)result.size());
    1580              :             }
    1581         9404 :             continue;
    1582              :         }
    1583        66888 :         const double stopPos = stop.getEndPos(*this);
    1584              :         if ((prev == nullptr
    1585        27581 :                 || prev->edge != stop.edge
    1586         1325 :                 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
    1587        93144 :                 && *stop.edge != internalSuccessor) {
    1588        65563 :             result.push_back(*stop.edge);
    1589        65563 :             if (stop.lane->isInternal()) {
    1590            5 :                 internalSuccessor = stop.lane->getNextNormal();
    1591            5 :                 result.push_back(internalSuccessor);
    1592              :             } else {
    1593        65558 :                 internalSuccessor = nullptr;
    1594              :             }
    1595              :         }
    1596              :         prev = &stop;
    1597        66888 :         if (firstPos == INVALID_DOUBLE) {
    1598        39307 :             if (stop.parkingarea != nullptr) {
    1599         3281 :                 firstPos = MAX2(0., stopPos);
    1600              :             } else {
    1601        36026 :                 firstPos = stopPos;
    1602              :             }
    1603              :         }
    1604        66888 :         lastPos = stopPos;
    1605        66888 :         if (stop.pars.jump >= 0) {
    1606          780 :             jumps.insert((int)result.size() - 1);
    1607              :         }
    1608              :     }
    1609              :     //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
    1610      2654945 :     return result;
    1611            0 : }
    1612              : 
    1613              : 
    1614              : std::vector<std::pair<int, double> >
    1615        21954 : MSBaseVehicle::getStopIndices() const {
    1616              :     std::vector<std::pair<int, double> > result;
    1617        45316 :     for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
    1618        46724 :         result.push_back(std::make_pair(
    1619        23362 :                              (int)(iter->edge - myRoute->begin()),
    1620        23362 :                              iter->getEndPos(*this)));
    1621              :     }
    1622        21954 :     return result;
    1623            0 : }
    1624              : 
    1625              : 
    1626              : MSStop&
    1627      5916807 : MSBaseVehicle::getNextStop() {
    1628              :     assert(myStops.size() > 0);
    1629      5916807 :     return myStops.front();
    1630              : }
    1631              : 
    1632              : SUMOTime
    1633      3952512 : MSBaseVehicle::getStopDuration() const {
    1634      3952512 :     if (isStopped()) {
    1635      1511098 :         return myStops.front().duration;
    1636              :     } else {
    1637              :         return 0;
    1638              :     }
    1639              : }
    1640              : 
    1641              : 
    1642              : MSStop&
    1643        14584 : MSBaseVehicle::getStop(int nextStopIndex) {
    1644        14584 :     if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
    1645            0 :         throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
    1646              :     }
    1647              :     auto stopIt = myStops.begin();
    1648              :     std::advance(stopIt, nextStopIndex);
    1649        14584 :     return *stopIt;
    1650              : }
    1651              : 
    1652              : 
    1653              : const SUMOVehicleParameter::Stop*
    1654       186133 : MSBaseVehicle::getNextStopParameter() const {
    1655       186133 :     if (hasStops()) {
    1656       105674 :         return &myStops.front().pars;
    1657              :     }
    1658              :     return nullptr;
    1659              : }
    1660              : 
    1661              : 
    1662              : bool
    1663        48273 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    1664              :     //if the stop exists update the duration
    1665        73721 :     for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
    1666        49343 :         if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
    1667              :             // update existing stop
    1668        23895 :             if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
    1669        22318 :                 myStops.erase(iter);
    1670              :             } else {
    1671         1577 :                 iter->duration = stop.duration;
    1672         1577 :                 iter->triggered = stop.triggered;
    1673         1577 :                 iter->containerTriggered = stop.containerTriggered;
    1674         1577 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
    1675         1577 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
    1676              :             }
    1677              :             return true;
    1678              :         }
    1679              :     }
    1680        24378 :     const bool result = addStop(stop, errorMsg);
    1681        24378 :     if (result) {
    1682              :         /// XXX handle stops added out of order
    1683        24365 :         myParameter->stops.push_back(stop);
    1684              :     }
    1685              :     return result;
    1686              : }
    1687              : 
    1688              : 
    1689              : void
    1690          561 : MSBaseVehicle::unregisterWaiting() {
    1691          561 :     if (myAmRegisteredAsWaiting) {
    1692          403 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1693          403 :         myAmRegisteredAsWaiting = false;
    1694              :     }
    1695          561 : }
    1696              : 
    1697              : 
    1698              : bool
    1699          834 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
    1700          834 :     if (hasStops() && nextStopIndex < (int)myStops.size()) {
    1701          834 :         if (nextStopIndex == 0 && isStopped()) {
    1702           34 :             resumeFromStopping();
    1703              :         } else {
    1704              :             auto stopIt = myStops.begin();
    1705              :             std::advance(stopIt, nextStopIndex);
    1706          800 :             myStops.erase(stopIt);
    1707              :         }
    1708          834 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1709              :             // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
    1710              :             auto stopIt2 = myParameter->stops.begin();
    1711              :             std::advance(stopIt2, nextStopIndex);
    1712            8 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
    1713              :         }
    1714          834 :         return true;
    1715              :     } else {
    1716              :         return false;
    1717              :     }
    1718              : }
    1719              : 
    1720              : 
    1721              : bool
    1722          133 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    1723          133 :     const int n = (int)myStops.size();
    1724          133 :     if (nextStopIndex < 0 || nextStopIndex >= n) {
    1725            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1726            5 :         return false;
    1727              :     }
    1728          128 :     if (nextStopIndex == 0 && isStopped()) {
    1729            7 :         errorMsg = TL("cannot replace reached stop");
    1730            7 :         return false;
    1731              :     }
    1732          121 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1733          121 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    1734          121 :     MSEdge* stopEdge = &stopLane->getEdge();
    1735              : 
    1736              :     auto itStop = myStops.begin();
    1737              :     std::advance(itStop, nextStopIndex);
    1738              :     MSStop& replacedStop = *itStop;
    1739              : 
    1740              :     // check parking access rights
    1741          121 :     if (stop.parkingarea != "") {
    1742            0 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    1743            0 :         if (pa != nullptr && !pa->accepts(this)) {
    1744            0 :             errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
    1745            0 :             return false;
    1746              :         }
    1747              :     }
    1748              : 
    1749          121 :     if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
    1750              :         // only replace stop attributes
    1751           10 :         const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    1752           10 :         replacedStop.initPars(stop);
    1753           10 :         return true;
    1754              :     }
    1755              : 
    1756          111 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    1757            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    1758            0 :         return false;
    1759              :     }
    1760              : 
    1761          111 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1762          111 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1763          111 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1764          111 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1765          111 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1766          111 :     MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
    1767          111 :     auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
    1768          111 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    1769              : 
    1770          111 :     bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
    1771              : 
    1772              :     ConstMSEdgeVector toNewStop;
    1773          111 :     if (!teleport) {
    1774           82 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    1775           82 :         if (toNewStop.size() == 0) {
    1776           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    1777            5 :             return false;
    1778              :         }
    1779              :     }
    1780              : 
    1781              :     ConstMSEdgeVector fromNewStop;
    1782          106 :     if (!newDestination) {
    1783          101 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    1784          101 :         if (fromNewStop.size() == 0) {
    1785            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    1786            0 :             return false;
    1787              :         }
    1788              :     }
    1789              : 
    1790          106 :     const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    1791          106 :     replacedStop.initPars(stop);
    1792          106 :     replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
    1793          106 :     replacedStop.lane = stopLane;
    1794          106 :     if (MSGlobals::gUseMesoSim) {
    1795           18 :         replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
    1796           18 :         if (replacedStop.lane->isInternal()) {
    1797            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    1798            0 :             return false;
    1799              :         }
    1800              :     }
    1801              : 
    1802          106 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    1803              :     ConstMSEdgeVector newEdges; // only remaining
    1804          106 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    1805          106 :     if (!teleport) {
    1806           77 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    1807              :     } else {
    1808           29 :         newEdges.push_back(*itStart);
    1809              :     }
    1810          106 :     if (!newDestination) {
    1811          101 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    1812          101 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    1813              :     } else {
    1814            5 :         newEdges.push_back(stopEdge);
    1815              :     }
    1816              :     //std::cout << SIMTIME << " replaceStop veh=" << getID()
    1817              :     //    << " teleport=" << teleport
    1818              :     //    << " busStop=" << stop.busstop
    1819              :     //    << " oldEdges=" << oldRemainingEdges.size()
    1820              :     //    << " newEdges=" << newEdges.size()
    1821              :     //    << " toNewStop=" << toNewStop.size()
    1822              :     //    << " fromNewStop=" << fromNewStop.size()
    1823              :     //    << "\n";
    1824              : 
    1825          106 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    1826          106 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    1827          106 :     const double savings = previousCost - routeCost;
    1828          106 :     if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1829              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    1830            5 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
    1831              :     }
    1832          106 :     if (teleport) {
    1833              :         // let the vehicle jump rather than teleport
    1834              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    1835              :         // already configure to jump before the replaced stop)
    1836           29 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    1837              :             return false;
    1838              :         };
    1839              :     }
    1840          106 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    1841          111 : }
    1842              : 
    1843              : 
    1844              : bool
    1845           52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
    1846           52 :     const int n = (int)myStops.size();
    1847           52 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    1848            0 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1849            0 :         return false;
    1850              :     }
    1851           52 :     if (nextStopIndex == 0 && isStopped()) {
    1852            0 :         errorMsg = TL("cannot reroute towards reached stop");
    1853            0 :         return false;
    1854              :     }
    1855           52 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1856              : 
    1857           52 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1858           52 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1859           52 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1860           52 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1861           52 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1862           52 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    1863           52 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    1864           52 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    1865              : 
    1866              :     ConstMSEdgeVector newBetween;
    1867           52 :     if (!teleport) {
    1868           15 :         router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
    1869           15 :         if (newBetween.size() == 0) {
    1870            0 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
    1871            0 :             return false;
    1872              :         }
    1873              :     }
    1874              : 
    1875           52 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    1876              :     ConstMSEdgeVector newEdges; // only remaining
    1877           52 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    1878           52 :     if (!teleport) {
    1879           15 :         newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
    1880              :     } else {
    1881           37 :         newEdges.push_back(*itStart);
    1882              :     }
    1883           52 :     newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    1884              :     //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
    1885              :     //    << " oldEdges=" << oldRemainingEdges.size()
    1886              :     //    << " newEdges=" << newEdges.size()
    1887              :     //    << " toNewStop=" << toNewStop.size()
    1888              :     //    << " fromNewStop=" << fromNewStop.size()
    1889              :     //    << "\n";
    1890              : 
    1891           52 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    1892           52 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    1893           52 :     const double savings = previousCost - routeCost;
    1894              : 
    1895           52 :     if (teleport) {
    1896              :         // let the vehicle jump rather than teleport
    1897              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    1898              :         // already configure to jump before the replaced stop)
    1899           37 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    1900              :             return false;
    1901              :         };
    1902              :     }
    1903           52 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    1904           52 : }
    1905              : 
    1906              : 
    1907              : bool
    1908           66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
    1909              :     bool needJump = true;
    1910           66 :     if (nextStopIndex > 0) {
    1911              :         auto itPriorStop = myStops.begin();
    1912           48 :         std::advance(itPriorStop, nextStopIndex - 1);
    1913              :         const MSStop& priorStop = *itPriorStop;
    1914           48 :         if (priorStop.pars.jump >= 0) {
    1915              :             needJump = false;
    1916              :         }
    1917              :     }
    1918              :     if (needJump) {
    1919           47 :         SUMOVehicleParameter::Stop jumpStopPars;
    1920           47 :         jumpStopPars.endPos = (*itStart)->getLength();
    1921           47 :         jumpStopPars.speed = 1000;
    1922           47 :         jumpStopPars.jump = 0;
    1923              :         jumpStopPars.edge = (*itStart)->getID();
    1924           47 :         jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
    1925              :         MSLane* jumpStopLane = nullptr;
    1926           47 :         for (MSLane* cand : (*itStart)->getLanes()) {
    1927           47 :             if (cand->allowsVehicleClass(getVClass())) {
    1928              :                 jumpStopLane = cand;
    1929              :                 break;
    1930              :             }
    1931              :         }
    1932           47 :         if (jumpStopLane == nullptr) {
    1933            0 :             errorMsg = TL("unable to replace stop with teleporting");
    1934              :             return false;
    1935              :         }
    1936              :         auto itStop = myStops.begin();
    1937              :         std::advance(itStop, nextStopIndex);
    1938           47 :         MSStop jumpStop(jumpStopPars);
    1939           47 :         jumpStop.initPars(jumpStopPars);
    1940           47 :         jumpStop.lane = jumpStopLane;
    1941           47 :         jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
    1942           47 :         myStops.insert(itStop, jumpStop);
    1943           47 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1944              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    1945              :             auto it = myParameter->stops.begin() + nextStopIndex;
    1946            0 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
    1947              :         }
    1948           47 :     }
    1949              :     return true;
    1950              : }
    1951              : 
    1952              : 
    1953              : bool
    1954          326 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    1955          326 :     const int n = (int)myStops.size();
    1956          326 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    1957            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1958            5 :         return false;
    1959              :     }
    1960          321 :     if (nextStopIndex == 0 && isStopped()) {
    1961            7 :         errorMsg = TL("cannot insert stop before the currently reached stop");
    1962            7 :         return false;
    1963              :     }
    1964          314 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1965          314 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    1966          314 :     MSEdge* stopEdge = &stopLane->getEdge();
    1967              : 
    1968          314 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    1969            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    1970            0 :         return false;
    1971              :     }
    1972              : 
    1973              :     // check parking access rights
    1974          314 :     if (stop.parkingarea != "") {
    1975          137 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    1976          137 :         if (pa != nullptr && !pa->accepts(this)) {
    1977            0 :             errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
    1978            0 :             return false;
    1979              :         }
    1980              :     }
    1981              : 
    1982          314 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1983          314 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1984          314 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1985          314 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1986          314 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1987          314 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    1988          314 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    1989          314 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    1990              : 
    1991          314 :     bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
    1992              : 
    1993              :     ConstMSEdgeVector toNewStop;
    1994          314 :     if (!teleport) {
    1995          286 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    1996          286 :         if (toNewStop.size() == 0) {
    1997           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    1998            5 :             return false;
    1999              :         }
    2000              :     }
    2001              : 
    2002              :     ConstMSEdgeVector fromNewStop;
    2003          309 :     if (!newDestination) {
    2004          280 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2005          280 :         if (fromNewStop.size() == 0) {
    2006            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2007            0 :             return false;
    2008              :         }
    2009              :     }
    2010              : 
    2011              :     auto itStop = myStops.begin();
    2012              :     std::advance(itStop, nextStopIndex);
    2013          309 :     MSStop newStop(stop);
    2014          309 :     newStop.initPars(stop);
    2015          309 :     newStop.edge = myRoute->end(); // will be patched in replaceRoute
    2016          309 :     newStop.lane = stopLane;
    2017          309 :     if (MSGlobals::gUseMesoSim) {
    2018           66 :         newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
    2019           66 :         if (newStop.lane->isInternal()) {
    2020            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2021            0 :             return false;
    2022              :         }
    2023              :     }
    2024          309 :     myStops.insert(itStop, newStop);
    2025              : 
    2026          309 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2027              :     ConstMSEdgeVector newEdges; // only remaining
    2028          309 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2029          309 :     if (!teleport) {
    2030          281 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2031              :     } else {
    2032           28 :         newEdges.push_back(*itStart);
    2033              :     }
    2034          309 :     if (!newDestination) {
    2035          280 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2036          280 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2037              :     } else {
    2038           29 :         newEdges.push_back(stopEdge);
    2039              :     }
    2040              :     //std::cout << SIMTIME << " insertStop veh=" << getID()
    2041              :     //    << " teleport=" << teleport
    2042              :     //    << " busStop=" << stop.busstop
    2043              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2044              :     //    << " newEdges=" << newEdges.size()
    2045              :     //    << " toNewStop=" << toNewStop.size()
    2046              :     //    << " fromNewStop=" << fromNewStop.size()
    2047              :     //    << "\n";
    2048              : 
    2049          309 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2050          309 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2051          309 :     const double savings = previousCost - routeCost;
    2052              : 
    2053          309 :     if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2054              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2055              :         auto it = myParameter->stops.begin() + nextStopIndex;
    2056           15 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2057              :     }
    2058          309 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2059          623 : }
    2060              : 
    2061              : 
    2062              : double
    2063            0 : MSBaseVehicle::getStateOfCharge() const {
    2064            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2065            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2066            0 :         return batteryOfVehicle->getActualBatteryCapacity();
    2067              :     } else {
    2068            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2069            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2070            0 :             return batteryOfVehicle->getActualBatteryCapacity();
    2071              :         }
    2072              :     }
    2073              :     return -1;
    2074              : }
    2075              : 
    2076              : 
    2077              : double
    2078            0 : MSBaseVehicle::getRelativeStateOfCharge() const {
    2079            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2080            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2081            0 :         return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2082              :     } else {
    2083            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2084            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2085            0 :             return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2086              :         }
    2087              :     }
    2088              :     return -1;
    2089              : }
    2090              : 
    2091              : 
    2092              : double
    2093            0 : MSBaseVehicle::getChargedEnergy() const {
    2094            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2095            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2096            0 :         return batteryOfVehicle->getEnergyCharged();
    2097              :     } else {
    2098            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2099            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2100            0 :             return batteryOfVehicle->getEnergyCharged();
    2101              :         }
    2102              :     }
    2103              :     return -1;
    2104              : }
    2105              : 
    2106              : 
    2107              : double
    2108            0 : MSBaseVehicle::getMaxChargeRate() const {
    2109            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2110            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2111            0 :         return batteryOfVehicle->getMaximumChargeRate();
    2112              :     }
    2113              :     return -1;
    2114              : }
    2115              : 
    2116              : 
    2117              : double
    2118            0 : MSBaseVehicle::getElecHybridCurrent() const {
    2119            0 :     if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2120            0 :         MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2121            0 :         return elecHybridDevice->getCurrentFromOverheadWire();
    2122              :     }
    2123              : 
    2124              :     return NAN;
    2125              : }
    2126              : 
    2127              : double
    2128          630 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
    2129          630 :     if (isOnRoad() || isIdling()) {
    2130          630 :         return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
    2131              :     } else {
    2132              :         return 0.;
    2133              :     }
    2134              : }
    2135              : 
    2136              : 
    2137              : const MSEdgeWeightsStorage&
    2138      5123548 : MSBaseVehicle::getWeightsStorage() const {
    2139      5123548 :     return _getWeightsStorage();
    2140              : }
    2141              : 
    2142              : 
    2143              : MSEdgeWeightsStorage&
    2144          650 : MSBaseVehicle::getWeightsStorage() {
    2145          650 :     return _getWeightsStorage();
    2146              : }
    2147              : 
    2148              : 
    2149              : MSEdgeWeightsStorage&
    2150      5124198 : MSBaseVehicle::_getWeightsStorage() const {
    2151      5124198 :     if (myEdgeWeights == nullptr) {
    2152        13307 :         myEdgeWeights = new MSEdgeWeightsStorage();
    2153              :     }
    2154      5124198 :     return *myEdgeWeights;
    2155              : }
    2156              : 
    2157              : 
    2158              : 
    2159              : 
    2160              : int
    2161      7250376 : MSBaseVehicle::getPersonNumber() const {
    2162      7250376 :     int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
    2163      7250376 :     return boarded + myParameter->personNumber;
    2164              : }
    2165              : 
    2166              : int
    2167            0 : MSBaseVehicle::getLeavingPersonNumber() const {
    2168              :     int leavingPersonNumber = 0;
    2169            0 :     const std::vector<MSTransportable*>& persons = getPersons();
    2170            0 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2171            0 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
    2172              :         const MSStop* stop = &myStops.front();
    2173            0 :         const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
    2174            0 :         if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
    2175            0 :             leavingPersonNumber++;
    2176              :         }
    2177              :     }
    2178            0 :     return leavingPersonNumber;
    2179              : }
    2180              : 
    2181              : std::vector<std::string>
    2182          165 : MSBaseVehicle::getPersonIDList() const {
    2183              :     std::vector<std::string> ret;
    2184          165 :     const std::vector<MSTransportable*>& persons = getPersons();
    2185          525 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2186          360 :         ret.push_back((*it_p)->getID());
    2187              :     }
    2188          165 :     return ret;
    2189            0 : }
    2190              : 
    2191              : int
    2192      4394764 : MSBaseVehicle::getContainerNumber() const {
    2193      4394764 :     int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
    2194      4394764 :     return loaded + myParameter->containerNumber;
    2195              : }
    2196              : 
    2197              : 
    2198              : void
    2199          138 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
    2200              :     // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
    2201          138 :     if (myPersonDevice != nullptr) {
    2202          118 :         myPersonDevice->removeTransportable(t);
    2203              :     }
    2204          138 :     if (myContainerDevice != nullptr) {
    2205           20 :         myContainerDevice->removeTransportable(t);
    2206              :     }
    2207          138 : }
    2208              : 
    2209              : 
    2210              : const std::vector<MSTransportable*>&
    2211      6862092 : MSBaseVehicle::getPersons() const {
    2212      6862092 :     if (myPersonDevice == nullptr) {
    2213              :         return myEmptyTransportableVector;
    2214              :     } else {
    2215        13299 :         return myPersonDevice->getTransportables();
    2216              :     }
    2217              : }
    2218              : 
    2219              : 
    2220              : const std::vector<MSTransportable*>&
    2221      5626394 : MSBaseVehicle::getContainers() const {
    2222      5626394 :     if (myContainerDevice == nullptr) {
    2223              :         return myEmptyTransportableVector;
    2224              :     } else {
    2225         2906 :         return myContainerDevice->getTransportables();
    2226              :     }
    2227              : }
    2228              : 
    2229              : 
    2230              : bool
    2231          202 : MSBaseVehicle::isLineStop(double position) const {
    2232          202 :     if (myParameter->line == "") {
    2233              :         // not a public transport line
    2234              :         return false;
    2235              :     }
    2236          348 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    2237          209 :         if (stop.startPos <= position && position <= stop.endPos) {
    2238              :             return true;
    2239              :         }
    2240              :     }
    2241          164 :     for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    2242           34 :         if (stop.startPos <= position && position <= stop.endPos) {
    2243              :             return true;
    2244              :         }
    2245              :     }
    2246              :     return false;
    2247              : }
    2248              : 
    2249              : 
    2250              : bool
    2251           45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
    2252          144 :     for (MSDevice* const dev : myDevices) {
    2253          126 :         if (dev->deviceName() == deviceName) {
    2254              :             return true;
    2255              :         }
    2256              :     }
    2257              :     return false;
    2258              : }
    2259              : 
    2260              : 
    2261              : void
    2262            9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
    2263            9 :     if (!hasDevice(deviceName)) {
    2264            9 :         if (deviceName == "rerouting") {
    2265           27 :             ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
    2266            9 :             MSDevice_Routing::buildVehicleDevices(*this, myDevices);
    2267            9 :             if (hasDeparted()) {
    2268              :                 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
    2269            0 :                 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
    2270              :                 assert(routingDevice != 0);
    2271            0 :                 routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
    2272              :             }
    2273              :         } else {
    2274            0 :             throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
    2275              :         }
    2276              :     }
    2277            9 : }
    2278              : 
    2279              : 
    2280              : std::string
    2281        49494 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
    2282        57650 :     for (MSVehicleDevice* const dev : myDevices) {
    2283        57641 :         if (dev->deviceName() == deviceName) {
    2284        49485 :             return dev->getParameter(key);
    2285              :         }
    2286              :     }
    2287           27 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2288              : }
    2289              : 
    2290              : 
    2291              : void
    2292          207 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
    2293          342 :     for (MSVehicleDevice* const dev : myDevices) {
    2294          342 :         if (dev->deviceName() == deviceName) {
    2295          207 :             dev->setParameter(key, value);
    2296          207 :             return;
    2297              :         }
    2298              :     }
    2299            0 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2300              : }
    2301              : 
    2302              : 
    2303              : void
    2304          842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
    2305         1669 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
    2306          837 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
    2307          837 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2308              :         // checked in MSLink::ignoreFoe
    2309              :     } else {
    2310           15 :         throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
    2311              :     }
    2312          837 : }
    2313              : 
    2314              : 
    2315              : void
    2316           38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
    2317              :     // handle some generic params first and then delegate to the carFollowModel itself
    2318           67 :     if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
    2319           17 :         getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
    2320           17 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2321              :         // checked in MSVehicle::planMove
    2322              :     } else {
    2323           21 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
    2324           21 :         if (microVeh) {
    2325              :             // remove 'carFollowModel.' prefix
    2326           21 :             const std::string attrName = key.substr(15);
    2327           21 :             microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
    2328              :         }
    2329              :     }
    2330           33 : }
    2331              : 
    2332              : 
    2333              : void
    2334      4613644 : MSBaseVehicle::initTransientModelParams() {
    2335              :     /* Design idea for additional junction model parameters:
    2336              :        We can distinguish between 3 levels of parameters
    2337              :        1. typically shared by multiple vehicles -> vType parameter
    2338              :        2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
    2339              :        3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
    2340              :        */
    2341      4881400 :     for (auto item : getParameter().getParametersMap()) {
    2342       535512 :         if (StringUtils::startsWith(item.first, "junctionModel.")) {
    2343          832 :             setJunctionModelParameter(item.first, item.second);
    2344       533848 :         } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
    2345           17 :             setCarFollowModelParameter(item.first, item.second);
    2346              :         }
    2347              :     }
    2348      9227288 :     const std::string routingModeStr = getStringParam("device.rerouting.mode");
    2349              :     try {
    2350      4613644 :         int routingMode = StringUtils::toInt(routingModeStr);
    2351      4613644 :         if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
    2352              :             setRoutingMode(routingMode);
    2353              :         }
    2354            0 :     } catch (NumberFormatException&) {
    2355              :         // @todo interpret symbolic constants
    2356            0 :         throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
    2357            0 :     }
    2358      4613644 : }
    2359              : 
    2360              : 
    2361              : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
    2362        24221 : MSBaseVehicle::getRouterTT() const {
    2363        24221 :     if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
    2364          102 :         return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
    2365              :     } else {
    2366        24119 :         return MSNet::getInstance()->getRouterTT(getRNGIndex());
    2367              :     }
    2368              : }
    2369              : 
    2370              : 
    2371              : void
    2372        30448 : MSBaseVehicle::replaceVehicleType(MSVehicleType* type) {
    2373              :     assert(type != nullptr);
    2374              :     // save old parameters before possible type deletion
    2375        30448 :     const double oldMu = myType->getSpeedFactor().getParameter()[0];
    2376        30448 :     const double oldDev = myType->getSpeedFactor().getParameter()[1];
    2377        30448 :     if (myType->isVehicleSpecific() && type != myType) {
    2378          848 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    2379              :     }
    2380              :     // adapt myChosenSpeedFactor to the new type
    2381        30448 :     if (oldDev == 0.) {
    2382              :         // old type had speedDev 0, reroll
    2383        22584 :         myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
    2384              :     } else {
    2385              :         // map old speedFactor onto new distribution
    2386         7864 :         const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
    2387         7864 :         const double newMu = type->getSpeedFactor().getParameter()[0];
    2388         7864 :         const double newDev = type->getSpeedFactor().getParameter()[1];
    2389         7864 :         myChosenSpeedFactor = newMu + distPoint * newDev;
    2390              :         // respect distribution limits
    2391         7864 :         myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
    2392         7869 :         myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
    2393              :     }
    2394        30448 :     myType = type;
    2395        30448 :     if (myEnergyParams != nullptr) {
    2396              :         myEnergyParams->setSecondary(type->getEmissionParameters());
    2397              :     }
    2398        30448 : }
    2399              : 
    2400              : 
    2401              : MSVehicleType&
    2402        96634 : MSBaseVehicle::getSingularType() {
    2403        96634 :     if (myType->isVehicleSpecific()) {
    2404              :         return *myType;
    2405              :     }
    2406         2296 :     MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
    2407         1148 :     replaceVehicleType(type);
    2408         1148 :     return *type;
    2409              : }
    2410              : 
    2411              : 
    2412              : int
    2413       510178 : MSBaseVehicle::getRNGIndex() const {
    2414       510178 :     const MSLane* const lane = getLane();
    2415       510178 :     if (lane == nullptr) {
    2416        14595 :         return getEdge()->getLanes()[0]->getRNGIndex();
    2417              :     } else {
    2418       495583 :         return lane->getRNGIndex();
    2419              :     }
    2420              : }
    2421              : 
    2422              : 
    2423              : SumoRNG*
    2424    589223843 : MSBaseVehicle::getRNG() const {
    2425    589223843 :     const MSLane* lane = getLane();
    2426    589223843 :     if (lane == nullptr) {
    2427         2745 :         return getEdge()->getLanes()[0]->getRNG();
    2428              :     } else {
    2429    589221098 :         return lane->getRNG();
    2430              :     }
    2431              : }
    2432              : 
    2433              : std::string
    2434        60393 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
    2435        60393 :     const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
    2436       120786 :     if (StringUtils::startsWith(key, "device.")) {
    2437       148482 :         StringTokenizer tok(key, ".");
    2438        49494 :         if (tok.size() < 3) {
    2439            0 :             error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
    2440            0 :             return "";
    2441              :         }
    2442              :         try {
    2443       148482 :             return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
    2444           18 :         } catch (InvalidArgument& e) {
    2445           54 :             error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
    2446           18 :             return "";
    2447           18 :         }
    2448        71292 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2449          316 :         if (microVeh == nullptr) {
    2450           36 :             error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
    2451           18 :             return "";
    2452              :         }
    2453          298 :         const std::string attrName = key.substr(16);
    2454              :         try {
    2455          298 :             return microVeh->getLaneChangeModel().getParameter(attrName);
    2456           36 :         } catch (InvalidArgument& e) {
    2457          108 :             error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
    2458           36 :             return "";
    2459           36 :         }
    2460        21166 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2461           16 :         if (microVeh == nullptr) {
    2462            0 :             error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
    2463            0 :             return "";
    2464              :         }
    2465           16 :         const std::string attrName = key.substr(15);
    2466              :         try {
    2467           16 :             return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
    2468            0 :         } catch (InvalidArgument& e) {
    2469            0 :             error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
    2470            0 :             return "";
    2471            0 :         }
    2472        10603 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2473          108 :         StringTokenizer tok(key, ".");
    2474           36 :         if (tok.size() != 3) {
    2475            0 :             error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
    2476            0 :             return "";
    2477              :         }
    2478           81 :         return hasDevice(tok.get(1)) ? "true" : "false";
    2479              :         // parking related parameters start here
    2480        10567 :     } else if (key == "parking.rerouteCount") {
    2481           15 :         return toString(getNumberParkingReroutes());
    2482        21032 :     } else if (StringUtils::startsWith(key, "parking.memory.")) {
    2483              :         std::vector<std::string> values;
    2484           65 :         if (getParkingMemory()) {
    2485           25 :             if (key == "parking.memory.IDList") {
    2486           30 :                 for (const auto& item : *getParkingMemory()) {
    2487           25 :                     values.push_back(item.first->getID());
    2488              :                 }
    2489           20 :             } else if (key == "parking.memory.score") {
    2490           30 :                 for (const auto& item : *getParkingMemory()) {
    2491           25 :                     values.push_back(item.second.score);
    2492              :                 }
    2493           15 :             } else if (key == "parking.memory.blockedAtTime") {
    2494           30 :                 for (const auto& item : *getParkingMemory()) {
    2495           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
    2496              :                 }
    2497           10 :             } else if (key == "parking.memory.blockedAtTimeLocal") {
    2498           30 :                 for (const auto& item : *getParkingMemory()) {
    2499           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
    2500              :                 }
    2501              :             } else {
    2502           10 :                 error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
    2503              :             }
    2504              :         }
    2505           65 :         return toString(values);
    2506           65 :     } else {
    2507              :         // default: custom user parameter
    2508        20902 :         return getParameter().getParameter(key, "");
    2509              :     }
    2510              : }
    2511              : 
    2512              : 
    2513              : void
    2514        30884 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
    2515        30884 :     if (myParkingMemory == nullptr) {
    2516            0 :         myParkingMemory = new StoppingPlaceMemory();
    2517              :     }
    2518        30884 :     myParkingMemory->rememberBlockedStoppingPlace(pa, local);
    2519        30884 : }
    2520              : 
    2521              : 
    2522              : void
    2523        12163 : MSBaseVehicle::resetParkingAreaScores() {
    2524        12163 :     if (myParkingMemory != nullptr) {
    2525        10639 :         myParkingMemory->resetStoppingPlaceScores();
    2526              :     }
    2527        12163 : }
    2528              : 
    2529              : 
    2530              : void
    2531          212 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
    2532          212 :     if (myChargingMemory == nullptr) {
    2533           44 :         myChargingMemory = new StoppingPlaceMemory();
    2534              :     }
    2535          212 :     myChargingMemory->rememberStoppingPlaceScore(cs, score);
    2536          212 : }
    2537              : 
    2538              : 
    2539              : void
    2540           60 : MSBaseVehicle::resetChargingStationScores() {
    2541           60 :     if (myChargingMemory != nullptr) {
    2542            4 :         myChargingMemory->resetStoppingPlaceScores();
    2543              :     }
    2544           60 : }
    2545              : 
    2546              : 
    2547              : void
    2548        54455 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
    2549        54455 :     if (myParkingMemory == nullptr) {
    2550         2025 :         myParkingMemory = new StoppingPlaceMemory();
    2551              :     }
    2552        54455 :     myParkingMemory->rememberStoppingPlaceScore(pa, score);
    2553        54455 : }
    2554              : 
    2555              : 
    2556              : SUMOTime
    2557        37852 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
    2558        37852 :     if (myParkingMemory == nullptr) {
    2559              :         return -1;
    2560              :     }
    2561        37852 :     return myParkingMemory->sawBlockedStoppingPlace(pa, local);
    2562              : }
    2563              : 
    2564              : 
    2565            0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
    2566            0 :     if (myChargingMemory == nullptr) {
    2567            0 :         myChargingMemory = new StoppingPlaceMemory();
    2568              :     }
    2569            0 :     myChargingMemory->rememberBlockedStoppingPlace(cs, local);
    2570            0 : }
    2571              : 
    2572              : 
    2573              : SUMOTime
    2574          276 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
    2575          276 :     if (myChargingMemory == nullptr) {
    2576              :         return -1;
    2577              :     }
    2578           16 :     return myChargingMemory->sawBlockedStoppingPlace(cs, local);
    2579              : }
    2580              : 
    2581              : 
    2582              : #ifdef _DEBUG
    2583              : void
    2584              : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
    2585              :     if (oc.isSet("movereminder-output.vehicles")) {
    2586              :         const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
    2587              :         myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
    2588              :     }
    2589              : }
    2590              : 
    2591              : 
    2592              : void
    2593              : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
    2594              :     OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
    2595              :     od.openTag("movereminder");
    2596              :     od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
    2597              :     od.writeAttr("veh", getID());
    2598              :     od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
    2599              :     od.writeAttr("type", type);
    2600              :     od.writeAttr("pos", toString(pos));
    2601              :     od.writeAttr("keep", toString(keep));
    2602              :     od.closeTag();
    2603              : }
    2604              : #endif
    2605              : 
    2606              : 
    2607              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1