LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.8 % 1245 1105
Test Date: 2024-11-22 15:46:21 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         3368 : MSBaseVehicle::BaseInfluencer::BaseInfluencer()
      84         3368 : {}
      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      5104379 : MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      97      5104379 :                              MSVehicleType* type, const double speedFactor) :
      98              :     SUMOVehicle(pars->id),
      99      5104379 :     myParameter(pars),
     100              :     myRoute(route),
     101      5104379 :     myType(type),
     102      5104379 :     myCurrEdge(route->begin()),
     103      5115040 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     104      5104379 :     myMoveReminders(0),
     105      5104379 :     myPersonDevice(nullptr),
     106      5104379 :     myContainerDevice(nullptr),
     107      5104379 :     myEnergyParams(nullptr),
     108      5104379 :     myDeparture(NOT_YET_DEPARTED),
     109      5104379 :     myDepartPos(-1),
     110      5104379 :     myArrivalPos(-1),
     111      5104379 :     myArrivalLane(-1),
     112      5104379 :     myNumberReroutes(0),
     113      5104379 :     myStopUntilOffset(0),
     114      5104379 :     myOdometer(0.),
     115      5104379 :     myRouteValidity(ROUTE_UNCHECKED),
     116      5104379 :     myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
     117      5104379 :     myNumericalID(myCurrentNumericalIndex++),
     118     10208758 :     myEdgeWeights(nullptr)
     119              : #ifdef _DEBUG
     120              :     , myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
     121              : #endif
     122              : {
     123      5104379 :     if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
     124       566545 :         pars->parametersSet |= VEHPARS_FORCE_REROUTE;
     125              :     }
     126      5104379 :     if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
     127      3611618 :         setDepartAndArrivalEdge();
     128              :     }
     129      5104379 :     if (!pars->wasSet(VEHPARS_FORCE_REROUTE)) {
     130      3611618 :         calculateArrivalParams(true);
     131              :     }
     132      5104379 :     initTransientModelParams();
     133      5104379 : }
     134              : 
     135              : 
     136      5104287 : MSBaseVehicle::~MSBaseVehicle() {
     137      5104287 :     delete myEdgeWeights;
     138      5104287 :     if (myParameter->repetitionNumber == -1) {
     139              :         // this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
     140       441197 :         MSRoute::checkDist(myParameter->routeid);
     141              :     }
     142      8905856 :     for (MSVehicleDevice* dev : myDevices) {
     143      3801569 :         delete dev;
     144              :     }
     145      5104287 :     delete myEnergyParams;
     146      5104287 :     delete myParkingMemory;
     147      5104287 :     delete myChargingMemory;
     148      5104287 :     checkRouteRemoval();
     149      5104287 :     delete myParameter;
     150      5104287 : }
     151              : 
     152              : 
     153              : void
     154      7045874 : 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     14091746 :     if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
     158      1295894 :         myRoute->checkRemoval();
     159              :     }
     160      7045874 : }
     161              : 
     162              : 
     163              : std::string
     164      7045872 : MSBaseVehicle::getFlowID() const {
     165      7045872 :     return getID().substr(0, getID().rfind('.'));
     166              : }
     167              : 
     168              : 
     169              : void
     170      5104379 : MSBaseVehicle::initDevices() {
     171      5104379 :     MSDevice::buildVehicleDevices(*this, myDevices);
     172      8901375 :     for (MSVehicleDevice* dev : myDevices) {
     173      3797012 :         myMoveReminders.push_back(std::make_pair(dev, 0.));
     174              :     }
     175      5104363 :     if (MSGlobals::gHaveEmissions) {
     176              :         // ensure we have the emission parameters even if we don't have the device
     177       857575 :         getEmissionParameters();
     178              :     }
     179      5104363 : }
     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  12696335435 : MSBaseVehicle::getParameter() const {
     189  12696335435 :     return *myParameter;
     190              : }
     191              : 
     192              : 
     193              : void
     194          477 : MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
     195          477 :     delete myParameter;
     196          477 :     myParameter = newParameter;
     197          477 : }
     198              : 
     199              : 
     200              : bool
     201    632965772 : MSBaseVehicle::ignoreTransientPermissions() const {
     202    632965772 :     return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
     203              : }
     204              : 
     205              : double
     206   6448539095 : MSBaseVehicle::getMaxSpeed() const {
     207   6448539095 :     return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
     208              : }
     209              : 
     210              : 
     211              : const MSEdge*
     212   1901504767 : MSBaseVehicle::succEdge(int nSuccs) const {
     213   1901504767 :     if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
     214   1371098265 :         return *(myCurrEdge + nSuccs);
     215              :     } else {
     216    530406502 :         return nullptr;
     217              :     }
     218              : }
     219              : 
     220              : 
     221              : const MSEdge*
     222   2976991322 : MSBaseVehicle::getEdge() const {
     223   2976991322 :     return *myCurrEdge;
     224              : }
     225              : 
     226              : 
     227              : const std::set<SUMOTrafficObject::NumericalID>
     228        65301 : MSBaseVehicle::getUpcomingEdgeIDs() const {
     229              :     std::set<SUMOTrafficObject::NumericalID> result;
     230       294161 :     for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
     231       228860 :         result.insert((*e)->getNumericalID());
     232              :     }
     233        65301 :     return result;
     234              : }
     235              : 
     236              : 
     237              : bool
     238       112690 : MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
     239       112690 :     if (stop == nullptr) {
     240              :         return false;
     241              :     }
     242       260897 :     for (const MSStop& s : myStops) {
     243       186382 :         if (s.busstop == stop
     244       148229 :                 || s.containerstop == stop
     245       148223 :                 || s.parkingarea == stop
     246       148217 :                 || s.chargingStation == stop) {
     247              :             return true;
     248              :         }
     249              :     }
     250              :     return false;
     251              : }
     252              : 
     253              : bool
     254       184824 : MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
     255       391978 :     for (const MSStop& s : myStops) {
     256       366012 :         if (&s.lane->getEdge() == edge) {
     257              :             return true;
     258              :         }
     259              :     }
     260        25966 :     return myRoute->getLastEdge() == edge;
     261              : }
     262              : 
     263              : 
     264              : bool
     265      2661420 : 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      2661420 :     const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
     268      2661420 :     if (source == nullptr) {
     269          289 :         source = *getRerouteOrigin();
     270              :     }
     271      2661420 :     if (sink == nullptr) {
     272      2635315 :         sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
     273      2635315 :         if (sink == nullptr) {
     274          289 :             sink = myRoute->getLastEdge();
     275              :         }
     276              :     }
     277      2672104 :     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      2661420 :     if (myParameter->via.size() == 0) {
     283      2653024 :         double firstPos = INVALID_DOUBLE;
     284      2653024 :         double lastPos = INVALID_DOUBLE;
     285      2653024 :         stops = getStopEdges(firstPos, lastPos, jumps);
     286      2653024 :         if (stops.size() > 0) {
     287        39292 :             double sourcePos = onInit ? 0 : getPositionOnLane();
     288        39292 :             if (MSGlobals::gUseMesoSim && isStopped()) {
     289          232 :                 sourcePos = getNextStop().pars.endPos;
     290              :             }
     291              :             // avoid superfluous waypoints for first and last edge
     292        39292 :             const bool skipFirst = stops.front() == source && (source != getEdge() || sourcePos + getBrakeGap() <= firstPos + NUMERICAL_EPS);
     293        39292 :             const bool skipLast = (stops.back() == sink
     294        21586 :                                    && myArrivalPos >= lastPos
     295        13175 :                                    && (stops.size() < 2 || stops.back() != stops[stops.size() - 2])
     296        52452 :                                    && (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        39292 :             if (stops.size() == 1 && (skipFirst || skipLast)) {
     305              :                 stops.clear();
     306              :             } else {
     307        31505 :                 if (skipFirst) {
     308              :                     stops.erase(stops.begin());
     309              :                 }
     310        31505 :                 if (skipLast) {
     311              :                     stops.erase(stops.end() - 1);
     312              :                 }
     313              :             }
     314        39292 :             stopAtSink = stops.size() > 0 && stops.back() == sink && jumps.size() == 0;
     315              :         }
     316              :     } else {
     317              :         std::set<const MSEdge*> jumpEdges;
     318        20624 :         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        26300 :         for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
     326        17912 :             MSEdge* viaEdge = MSEdge::dictionary(*it);
     327        17912 :             if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
     328         3098 :                 continue;
     329              :             }
     330              :             assert(viaEdge != 0);
     331        14814 :             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        14806 :             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      2720155 :     for (const MSEdge* const stopEdge : stops) {
     343        58745 :         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        57987 :         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        57987 :         if (into.size() > 0) {
     354              :             into.pop_back();
     355        57969 :             edges.insert(edges.end(), into.begin(), into.end());
     356        57969 :             if (stopEdge->isTazConnector()) {
     357           63 :                 source = into.back();
     358              :                 edges.pop_back();
     359              :             } else {
     360        57906 :                 source = stopEdge;
     361              :             }
     362              :         } else {
     363           18 :             if ((source != sink || !stopAtSink)) {
     364            4 :                 std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
     365            2 :                 if (MSGlobals::gCheckRoutes || silent) {
     366            4 :                     throw ProcessError(error);
     367              :                 } else {
     368            2 :                     WRITE_WARNING(error);
     369            0 :                     edges.push_back(source);
     370              :                 }
     371              :             }
     372           16 :             source = stopEdge;
     373              :         }
     374        58745 :     }
     375      2628643 :     if (stops.empty() && source == sink && onInit
     376        18679 :             && myParameter->departPosProcedure == DepartPosDefinition::GIVEN
     377           90 :             && myParameter->arrivalPosProcedure == ArrivalPosDefinition::GIVEN
     378      2661430 :             && myParameter->departPos > myParameter->arrivalPos) {
     379           13 :         router.computeLooped(source, sink, this, t, edges, silent);
     380              :     } else {
     381      2661397 :         if (!router.compute(source, sink, this, t, edges, silent)) {
     382              :             edges.clear();
     383              :         }
     384              :     }
     385              : 
     386              :     // router.setHint(myCurrEdge, myRoute->end(), this, t);
     387      2661410 :     if (edges.empty() && silent) {
     388              :         return false;
     389              :     }
     390      2661286 :     if (!edges.empty() && edges.front()->isTazConnector()) {
     391              :         edges.erase(edges.begin());
     392              :     }
     393      2661286 :     if (!edges.empty() && edges.back()->isTazConnector()) {
     394              :         edges.pop_back();
     395              :     }
     396      2661286 :     const double routeCost = router.recomputeCosts(edges, this, t);
     397      2661286 :     const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
     398      2661286 :     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      2661286 :     replaceRouteEdges(edges, routeCost, savings, info, onInit);
     405              :     // this must be called even if the route could not be replaced
     406      2661286 :     if (onInit) {
     407      2088236 :         if (edges.empty()) {
     408          190 :             if (MSGlobals::gCheckRoutes) {
     409          339 :                 throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
     410           77 :             } else if (source->isTazConnector()) {
     411          204 :                 WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
     412           27 :                 MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
     413              :                 return false;
     414              :             }
     415              :         }
     416      2088096 :         setDepartAndArrivalEdge();
     417      2088096 :         calculateArrivalParams(onInit);
     418              :     }
     419      2661146 :     return !edges.empty();
     420      2661666 : }
     421              : 
     422              : 
     423              : bool
     424      2682952 : MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
     425      2682952 :     if (edges.empty()) {
     426         1683 :         WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
     427          561 :         if (msgReturn != nullptr) {
     428              :             *msgReturn = "No route found";
     429              :         }
     430          561 :         return false;
     431              :     }
     432              :     // build a new id, first
     433              :     std::string id = getID();
     434      2682391 :     if (id[0] != '!') {
     435      5364782 :         id = "!" + id;
     436              :     }
     437      2682391 :     const std::string idSuffix = id + "!var#";
     438      2682391 :     int varIndex = 1;
     439      2682391 :     id = idSuffix + toString(varIndex);
     440      4743058 :     while (MSRoute::hasRoute(id)) {
     441      4121334 :         id = idSuffix + toString(++varIndex);
     442              :     }
     443      2682391 :     int oldSize = (int)edges.size();
     444      2682391 :     if (!onInit) {
     445       592710 :         const MSEdge* const origin = *getRerouteOrigin();
     446       592710 :         if (origin != *myCurrEdge && edges.front() == origin) {
     447        10615 :             edges.insert(edges.begin(), *myCurrEdge);
     448        10615 :             oldSize = (int)edges.size();
     449              :         }
     450      1185420 :         edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
     451              :     }
     452      2682391 :     if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
     453              :         // re-assign stop iterators when rerouting to a new parkingArea / insertStop
     454              :         return true;
     455              :     }
     456      1447760 :     const RGBColor& c = myRoute->getColor();
     457      1447760 :     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      1447760 :     ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
     461      2895520 :     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      1447793 :     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      2895518 :     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      1941595 : 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      1941595 :     if (onInit) {
     491      1399092 :         myCurrEdge = newRoute->begin();
     492              :     } else {
     493       542503 :         MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
     494       542503 :         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       542501 :         if (getLane() != nullptr) {
     506       409710 :             if (getLane()->getEdge().isInternal() && (
     507       409711 :                         (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       409709 :             } else if (getPositionOnLane() > getLane()->getLength()
     518       409714 :                        && (myCurrEdge + 1) != myRoute->end()
     519           10 :                        && (newCurrEdge + 1) != edges.end()
     520       409719 :                        && *(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       542495 :         myCurrEdge = newCurrEdge;
     533              :     }
     534      1941587 :     const bool stopsFromScratch = onInit && myRoute->getStops().empty();
     535              :     // assign new route
     536      1941587 :     checkRouteRemoval();
     537              :     myRoute = newRoute;
     538              :     // update arrival definition
     539      1941587 :     calculateArrivalParams(onInit);
     540              :     // save information that the vehicle was rerouted
     541      1941587 :     myNumberReroutes++;
     542      1941587 :     myStopUntilOffset += myRoute->getPeriod();
     543      1941587 :     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      2001103 :     for (std::vector<SUMOVehicleParameter::Stop>::iterator it = myPastStops.begin(); it != myPastStops.end();) {
     557        85837 :         const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
     558        59516 :         if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
     559            4 :             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      1941587 :     if (stopsFromScratch) {
     566              :         myStops.clear();
     567      1399028 :         addStops(!MSGlobals::gCheckRoutes);
     568              :     } else {
     569              :         // recheck old stops
     570       542559 :         MSRouteIterator searchStart = myCurrEdge;
     571       542559 :         double lastPos = getPositionOnLane() + getBrakeGap();
     572       952263 :         if (getLane() != nullptr && getLane()->isInternal()
     573       543392 :                 && 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       573323 :         for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
     580        30764 :             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        30764 :             if (*searchStart != &iter->lane->getEdge()
     587        30764 :                     || endPos + NUMERICAL_EPS < lastPos) {
     588        27860 :                 if (searchStart != edges.end() && !iter->reached) {
     589              :                     searchStart++;
     590              :                 }
     591              :             }
     592              :             lastPos = endPos;
     593              : 
     594        30764 :             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        30764 :             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        30577 :                 setSkips(*iter, stopIndex);
     608        30577 :                 searchStart = iter->edge;
     609              :             }
     610              :             ++iter;
     611        30577 :             stopIndex++;
     612              :         }
     613              :         // add new stops
     614       542559 :         if (addRouteStops) {
     615       494091 :             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       160990 : MSBaseVehicle::getAcceleration() const {
     630       160990 :     return 0;
     631              : }
     632              : 
     633              : 
     634              : void
     635      3552417 : MSBaseVehicle::onDepart() {
     636      3552417 :     myDeparture = MSNet::getInstance()->getCurrentTimeStep();
     637      3552417 :     myDepartPos = getPositionOnLane();
     638      3552417 :     MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
     639      3552417 : }
     640              : 
     641              : 
     642              : SUMOTime
     643      2820758 : MSBaseVehicle:: getDepartDelay() const {
     644      2820758 :     const SUMOTime dep = getParameter().depart;
     645      2820758 :     if (dep < 0) {
     646              :         return 0;
     647              :     }
     648      2820651 :     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     26934738 : MSBaseVehicle::getRoutePosition() const {
     660     26934738 :     return (int) std::distance(myRoute->begin(), myCurrEdge);
     661              : }
     662              : 
     663              : 
     664              : void
     665       102052 : MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
     666       102052 :     myCurrEdge = myRoute->begin() + index;
     667       102052 :     const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
     668              :     // !!! hack
     669       102052 :     myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
     670       102052 : }
     671              : 
     672              : double
     673       979686 : MSBaseVehicle::getOdometer() const {
     674       979686 :     return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
     675              : }
     676              : 
     677              : bool
     678       310365 : MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
     679       310365 :     if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
     680              :         return false;
     681       206637 :     } else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
     682              :         return false;
     683              :     }
     684       296363 :     if (isStopped() && myStops.begin()->pars.permitted.size() > 0
     685       148237 :             && myStops.begin()->pars.permitted.count(t->getID()) == 0) {
     686         5842 :         return false;
     687              :     }
     688       142395 :     MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     689              :     if (taxiDevice != nullptr) {
     690        23252 :         return taxiDevice->allowsBoarding(t);
     691              :     }
     692              :     return true;
     693              : }
     694              : 
     695              : 
     696              : void
     697        12892 : MSBaseVehicle::addTransportable(MSTransportable* transportable) {
     698        12892 :     if (transportable->isPerson()) {
     699        12162 :         if (myPersonDevice == nullptr) {
     700         4171 :             myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
     701         4171 :             myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
     702         4171 :             if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
     703         1911 :                 const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
     704              :             }
     705              :         }
     706        12162 :         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        12892 : }
     718              : 
     719              : 
     720              : bool
     721         2064 : MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
     722         2346 :     for (const MSStop& stop : myStops) {
     723          741 :         if (stop.edge == it && stop.pars.jump >= 0) {
     724              :             return true;
     725          639 :         } else if (stop.edge > it) {
     726              :             return false;
     727              :         }
     728              :     }
     729              :     return false;
     730              : }
     731              : 
     732              : 
     733              : bool
     734      4236965 : MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
     735      4236965 :     MSRouteIterator start = myCurrEdge;
     736      4236965 :     if (route == nullptr) {
     737              :         route = myRoute;
     738              :     } else {
     739      3558055 :         start = route->begin();
     740              :     }
     741              :     const bool checkJumps = route == myRoute;  // the edge iterators in the stops are invalid otherwise
     742      4236965 :     MSRouteIterator last = route->end() - 1;
     743              :     // check connectivity, first
     744     19942357 :     for (MSRouteIterator e = start; e != last; ++e) {
     745     15739531 :         const MSEdge& next = **(e + 1);
     746     15739531 :         if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
     747        34295 :             if (!checkJumps || !hasJump(e)) {
     748        34193 :                 if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
     749        34193 :                         || (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
     750       102417 :                     msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
     751        34139 :                     return false;
     752              :                 }
     753              :             }
     754              :         }
     755              :     }
     756      4202826 :     last = route->end();
     757              :     // check usable lanes, then
     758     24110186 :     for (MSRouteIterator e = start; e != last; ++e) {
     759     19907360 :         if ((*e)->prohibits(this)) {
     760            0 :             msg = TLF("Edge '%' prohibits.", (*e)->getID());
     761              :             return false;
     762              :         }
     763              :     }
     764              :     return true;
     765              : }
     766              : 
     767              : 
     768              : bool
     769    506541263 : MSBaseVehicle::hasValidRouteStart(std::string& msg) {
     770    506541263 :     if (!(*myCurrEdge)->isTazConnector()) {
     771    506404207 :         if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
     772           12 :             msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
     773            6 :             myRouteValidity |= ROUTE_START_INVALID_LANE;
     774            6 :             return false;
     775              :         }
     776              :     }
     777    506541257 :     if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
     778    506541199 :         myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
     779    506541199 :         return true;
     780              :     } else {
     781          174 :         msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
     782           58 :         myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
     783           58 :         return false;
     784              :     }
     785              : }
     786              : 
     787              : 
     788              : int
     789   4837296888 : MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
     790   4837296888 :     if (!update) {
     791   2057576699 :         return myRouteValidity;
     792              :     }
     793              :     // insertion check must be done in any case
     794              :     std::string msg;
     795   2779720189 :     if (!hasValidRouteStart(msg)) {
     796          182 :         if (MSGlobals::gCheckRoutes) {
     797          220 :             throw ProcessError(msg);
     798           72 :         } else if (!silent) {
     799              :             // vehicle will be discarded
     800          138 :             WRITE_WARNING(msg);
     801           26 :         } else if (msgReturn != nullptr) {
     802              :             *msgReturn = msg;
     803              :         }
     804              :     }
     805              :     if (MSGlobals::gCheckRoutes
     806   2779701620 :             && (myRouteValidity & ROUTE_UNCHECKED) != 0
     807              :             // we could check after the first rerouting
     808   2784697911 :             && (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
     809      7046992 :         if (!hasValidRoute(msg, myRoute)) {
     810           74 :             myRouteValidity |= ROUTE_INVALID;
     811          222 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
     812              :         }
     813              :     }
     814   2779720005 :     myRouteValidity &= ~ROUTE_UNCHECKED;
     815              :     return myRouteValidity;
     816              : }
     817              : 
     818              : void
     819     19436547 : MSBaseVehicle::addReminder(MSMoveReminder* rem) {
     820              : #ifdef _DEBUG
     821              :     if (myTraceMoveReminders) {
     822              :         traceMoveReminder("add", rem, 0, true);
     823              :     }
     824              : #endif
     825     19436547 :     myMoveReminders.push_back(std::make_pair(rem, 0.));
     826     19436547 : }
     827              : 
     828              : 
     829              : void
     830            0 : MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
     831            0 :     for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
     832            0 :         if (r->first == rem) {
     833              : #ifdef _DEBUG
     834              :             if (myTraceMoveReminders) {
     835              :                 traceMoveReminder("remove", rem, 0, false);
     836              :             }
     837              : #endif
     838              :             myMoveReminders.erase(r);
     839              :             return;
     840              :         }
     841              :     }
     842              : }
     843              : 
     844              : 
     845              : void
     846     44553161 : MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     847    115980989 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
     848              :         // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
     849     71427828 :         if (rem->first->getLane() != nullptr && rem->second > 0.) {
     850              : #ifdef _DEBUG
     851              :             if (myTraceMoveReminders) {
     852              :                 traceMoveReminder("notifyEnter_skipped", rem->first, rem->second, true);
     853              :             }
     854              : #endif
     855              :             ++rem;
     856              :         } else {
     857     59260124 :             if (rem->first->notifyEnter(*this, reason, enteredLane)) {
     858              : #ifdef _DEBUG
     859              :                 if (myTraceMoveReminders) {
     860              :                     traceMoveReminder("notifyEnter", rem->first, rem->second, true);
     861              :                 }
     862              : #endif
     863              :                 ++rem;
     864              :             } else {
     865              : #ifdef _DEBUG
     866              :                 if (myTraceMoveReminders) {
     867              :                     traceMoveReminder("notifyEnter", rem->first, rem->second, false);
     868              :                 }
     869              : #endif
     870              :                 rem = myMoveReminders.erase(rem);
     871              :             }
     872              :         }
     873              :     }
     874     44553161 : }
     875              : 
     876              : 
     877              : void
     878      7642656 : MSBaseVehicle::calculateArrivalParams(bool onInit) {
     879      7642656 :     if (myRoute->getLastEdge()->isTazConnector()) {
     880              :         return;
     881              :     }
     882      7642656 :     const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
     883      7642656 :     if (arrivalEdgeIndex != myParameter->arrivalEdge) {
     884           42 :         WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
     885              :                        getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
     886              :     }
     887      7642656 :     const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
     888      7642656 :     if (!onInit) {
     889       542495 :         arrivalEdge = myRoute->getLastEdge();
     890              :         // ignore arrivalEdge parameter after rerouting
     891       542495 :         const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
     892              :     }
     893              :     const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
     894      7642656 :     const double lastLaneLength = lanes[0]->getLength();
     895      7642656 :     switch (myParameter->arrivalPosProcedure) {
     896       201243 :         case ArrivalPosDefinition::GIVEN:
     897       201243 :             if (fabs(myParameter->arrivalPos) > lastLaneLength) {
     898         3048 :                 WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
     899              :             }
     900              :             // Maybe we should warn the user about invalid inputs!
     901       201243 :             myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
     902       201243 :             if (myArrivalPos < 0) {
     903        20597 :                 myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
     904              :             }
     905              :             break;
     906              :         case ArrivalPosDefinition::RANDOM:
     907        74093 :             myArrivalPos = RandHelper::rand(lastLaneLength);
     908        74093 :             break;
     909            0 :         case ArrivalPosDefinition::CENTER:
     910            0 :             myArrivalPos = lastLaneLength / 2.;
     911            0 :             break;
     912      7367320 :         default:
     913      7367320 :             myArrivalPos = lastLaneLength;
     914      7367320 :             break;
     915              :     }
     916      7642656 :     if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
     917       115107 :         if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
     918       283707 :             WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
     919              :         }
     920       115107 :         myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
     921      7527549 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
     922            7 :         myArrivalLane = -1;
     923            7 :         for (MSLane* lane : lanes) {
     924            7 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
     925            7 :                 myArrivalLane = lane->getIndex();
     926            7 :                 break;
     927              :             }
     928              :         }
     929            7 :         if (myArrivalLane == -1) {
     930            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
     931            0 :             myArrivalLane = 0;
     932              :         }
     933      7527542 :     } else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
     934              :         // pick random lane among all usable lanes
     935              :         std::vector<MSLane*> usable;
     936       364240 :         for (MSLane* lane : lanes) {
     937       279473 :             if (lane->allowsVehicleClass(myType->getVehicleClass())) {
     938       261555 :                 usable.push_back(lane);
     939              :             }
     940              :         }
     941        84767 :         if (usable.empty()) {
     942            0 :             WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
     943            0 :             myArrivalLane = 0;
     944              :         } else {
     945        84767 :             myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
     946              :         }
     947        84767 :     }
     948      7642656 :     if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
     949       180580 :         for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
     950       142260 :             if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
     951              :                 return;
     952              :             }
     953              :         }
     954       114960 :         WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
     955              :     }
     956              : }
     957              : 
     958              : void
     959      5699714 : MSBaseVehicle::setDepartAndArrivalEdge() {
     960      5699714 :     SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
     961      5699714 :     if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
     962         7871 :         const int routeEdges = (int)myRoute->getEdges().size();
     963         7871 :         if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
     964              :             // write specific edge in vehroute output for reproducibility
     965         4185 :             pars->departEdge = RandHelper::rand(0, routeEdges);
     966         4185 :             pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
     967              :         }
     968              :         assert(pars->departEdge >= 0);
     969         7871 :         if (pars->departEdge >= routeEdges) {
     970            0 :             WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
     971              :         } else {
     972              :             myCurrEdge += pars->departEdge;
     973              :         }
     974              :     }
     975      5699714 :     if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
     976          147 :         const int routeEdges = (int)myRoute->getEdges().size();
     977          147 :         const int begin = (int)(myCurrEdge - myRoute->begin());
     978              :         // write specific edge in vehroute output for reproducibility
     979          147 :         pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
     980          147 :         pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
     981              :         assert(pars->arrivalEdge >= begin);
     982              :         assert(pars->arrivalEdge < routeEdges);
     983              :     }
     984      5699714 : }
     985              : 
     986              : 
     987              : double
     988    577667723 : MSBaseVehicle::getImpatience() const {
     989   1155335446 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
     990    577667723 :                          + (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
     991    577667723 :                          + (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
     992              : }
     993              : 
     994              : 
     995              : MSDevice*
     996    865170519 : MSBaseVehicle::getDevice(const std::type_info& type) const {
     997   1495088110 :     for (MSVehicleDevice* const dev : myDevices) {
     998    685075816 :         if (typeid(*dev) == type) {
     999     55158225 :             return dev;
    1000              :         }
    1001              :     }
    1002              :     return nullptr;
    1003              : }
    1004              : 
    1005              : 
    1006              : void
    1007         2817 : MSBaseVehicle::saveState(OutputDevice& out) {
    1008              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
    1009         2817 :     const std::string& typeID = MSNet::getInstance()->getVehicleControl().hasVTypeDistribution(myParameter->vtypeid) || getVehicleType().isVehicleSpecific() ? getVehicleType().getID() : "";
    1010         2817 :     myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
    1011              :     // params and stops must be written in child classes since they may wish to add additional attributes first
    1012              :     out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
    1013         2817 :     std::ostringstream os;
    1014         5634 :     os << myOdometer << " " << myNumberReroutes;
    1015         2817 :     out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
    1016         2817 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
    1017         2817 :         const int precision = out.precision();
    1018         2817 :         out.setPrecision(MAX2(gPrecisionRandom, precision));
    1019         2817 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
    1020         2817 :         out.setPrecision(precision);
    1021              :     }
    1022         2817 :     if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
    1023         3872 :         out.writeAttr(SUMO_ATTR_REROUTE, true);
    1024              :     }
    1025         2817 :     if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
    1026              :         // could be set from stop
    1027              :         out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
    1028              :     }
    1029              :     // here starts the vehicle internal part (see loading)
    1030              :     // @note: remember to close the vehicle tag when calling this in a subclass!
    1031         5634 : }
    1032              : 
    1033              : 
    1034              : bool
    1035            0 : MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
    1036              :     UNUSED_PARAMETER(stop);
    1037              :     UNUSED_PARAMETER(distToStop);
    1038            0 :     return true;
    1039              : }
    1040              : 
    1041              : 
    1042              : bool
    1043   8101870465 : MSBaseVehicle::isStopped() const {
    1044   8101870465 :     return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
    1045              : }
    1046              : 
    1047              : 
    1048              : bool
    1049   2263152792 : MSBaseVehicle::isParking() const {
    1050   2310897248 :     return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
    1051       328883 :             && (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
    1052   2263360656 :             && (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
    1053              : }
    1054              : 
    1055              : 
    1056              : bool
    1057    606152047 : MSBaseVehicle::isJumping() const {
    1058    606152047 :     return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
    1059              : }
    1060              : 
    1061              : 
    1062              : bool
    1063      6254456 : MSBaseVehicle::isStoppedTriggered() const {
    1064      6254456 :     return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
    1065              : }
    1066              : 
    1067              : 
    1068              : bool
    1069        23904 : MSBaseVehicle::isStoppedParking() const {
    1070        23904 :     return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
    1071              : }
    1072              : 
    1073              : 
    1074              : bool
    1075        17180 : MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
    1076        17180 :     if (isStopped() || (checkFuture && hasStops())) {
    1077              :         const MSStop& stop = myStops.front();
    1078        18023 :         return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
    1079              :     }
    1080              :     return false;
    1081              : }
    1082              : 
    1083              : bool
    1084        11423 : MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
    1085              :     // Check if there is a parking area to be replaced
    1086        11423 :     if (parkingArea == 0) {
    1087              :         errorMsg = "new parkingArea is NULL";
    1088            0 :         return false;
    1089              :     }
    1090        11423 :     if (myStops.size() == 0) {
    1091              :         errorMsg = "vehicle has no stops";
    1092            0 :         return false;
    1093              :     }
    1094        11423 :     if (myStops.front().parkingarea == 0) {
    1095              :         errorMsg = "first stop is not at parkingArea";
    1096            0 :         return false;
    1097              :     }
    1098              :     MSStop& first = myStops.front();
    1099              :     SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
    1100        11423 :     std::string oldStopEdgeID = first.lane->getEdge().getID();
    1101              :     // merge subsequent duplicate stops equals to parking area
    1102        11443 :     for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
    1103          331 :         if (iter->parkingarea == parkingArea) {
    1104           20 :             stopPar.duration += iter->duration;
    1105           20 :             myStops.erase(iter++);
    1106              :         } else {
    1107              :             break;
    1108              :         }
    1109              :     }
    1110        11423 :     stopPar.lane = parkingArea->getLane().getID();
    1111        11423 :     stopPar.parkingarea = parkingArea->getID();
    1112        11423 :     stopPar.startPos = parkingArea->getBeginLanePosition();
    1113        11423 :     stopPar.endPos = parkingArea->getEndLanePosition();
    1114        11423 :     first.edge = myRoute->end(); // will be patched in replaceRoute
    1115        11423 :     first.lane = &parkingArea->getLane();
    1116        11423 :     first.parkingarea = parkingArea;
    1117              : 
    1118              :     // patch via edges
    1119        11423 :     std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
    1120        11423 :     if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
    1121          198 :         myParameter->via.erase(myParameter->via.begin());
    1122          198 :         myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
    1123              :     }
    1124              :     return true;
    1125              : }
    1126              : 
    1127              : 
    1128              : MSParkingArea*
    1129        58460 : MSBaseVehicle::getNextParkingArea() {
    1130              :     MSParkingArea* nextParkingArea = nullptr;
    1131        58460 :     if (!myStops.empty()) {
    1132        57501 :         SUMOVehicleParameter::Stop stopPar;
    1133        57501 :         MSStop stop = myStops.front();
    1134        57501 :         if (!stop.reached && stop.parkingarea != nullptr) {
    1135              :             nextParkingArea = stop.parkingarea;
    1136              :         }
    1137        57501 :     }
    1138        58460 :     return nextParkingArea;
    1139              : }
    1140              : 
    1141              : 
    1142              : MSParkingArea*
    1143        84817 : MSBaseVehicle::getCurrentParkingArea() {
    1144              :     MSParkingArea* currentParkingArea = nullptr;
    1145        84817 :     if (isParking()) {
    1146        84756 :         currentParkingArea = myStops.begin()->parkingarea;
    1147              :     }
    1148        84817 :     return currentParkingArea;
    1149              : }
    1150              : 
    1151              : 
    1152              : const std::vector<std::string>&
    1153           21 : MSBaseVehicle::getParkingBadges() const {
    1154           21 :     if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
    1155            7 :         return myParameter->parkingBadges;
    1156              :     } else {
    1157           14 :         return getVehicleType().getParkingBadges();
    1158              :     }
    1159              : }
    1160              : 
    1161              : 
    1162              : double
    1163      9168947 : MSBaseVehicle::basePos(const MSEdge* edge) const {
    1164      9168947 :     double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
    1165      9168947 :     if (hasStops()
    1166      9194474 :             && myStops.front().edge == myRoute->begin()
    1167      9194474 :             && (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
    1168        25499 :         result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
    1169              :     }
    1170      9168947 :     return result;
    1171              : }
    1172              : 
    1173              : 
    1174              : MSLane*
    1175          298 : MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
    1176          298 :     const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
    1177          298 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
    1178          298 :     if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
    1179            8 :         return nullptr;
    1180              :     }
    1181          580 :     const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
    1182          290 :     if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
    1183          290 :         const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
    1184          290 :         stop.edge = edgeID;
    1185          290 :         return edge->getOppositeEdge()->getLanes()[oppositeIndex];
    1186              :     }
    1187              :     return nullptr;
    1188              : }
    1189              : 
    1190              : 
    1191              : bool
    1192       126847 : MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
    1193              :                        MSRouteIterator* searchStart) {
    1194       126847 :     MSStop stop(stopPar);
    1195       126847 :     if (stopPar.lane == "") {
    1196         2498 :         MSEdge* e = MSEdge::dictionary(stopPar.edge);
    1197         2498 :         stop.lane = e->getFirstAllowed(getVClass());
    1198         2498 :         if (stop.lane == nullptr) {
    1199            0 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
    1200            0 :             return false;
    1201              :         }
    1202              :     } else {
    1203       124349 :         stop.lane = MSLane::dictionary(stopPar.lane);
    1204       124349 :         if (stop.lane == nullptr) {
    1205              :             // must be an opposite stop
    1206          145 :             SUMOVehicleParameter::Stop tmp = stopPar;
    1207          145 :             stop.lane = interpretOppositeStop(tmp);
    1208              :             assert(stop.lane != nullptr);
    1209          145 :         }
    1210       124349 :         if (!stop.lane->allowsVehicleClass(myType->getVehicleClass())) {
    1211           32 :             errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
    1212           16 :             return false;
    1213              :         }
    1214              :     }
    1215       126831 :     if (MSGlobals::gUseMesoSim) {
    1216        16342 :         stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
    1217        16342 :         if (stop.lane->isInternal()) {
    1218            2 :             errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
    1219            1 :             return false;
    1220              :         }
    1221              :     }
    1222       126830 :     stop.initPars(stopPar);
    1223       126830 :     if (stopPar.until != -1) {
    1224              :         // !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
    1225        41029 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
    1226              :     }
    1227       126830 :     if (stopPar.arrival != -1) {
    1228          597 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
    1229              :     }
    1230       126830 :     std::string stopType = "stop";
    1231       126830 :     std::string stopID = "";
    1232       126830 :     if (stop.busstop != nullptr) {
    1233              :         stopType = "busStop";
    1234        33545 :         stopID = stop.busstop->getID();
    1235        93285 :     } else if (stop.containerstop != nullptr) {
    1236              :         stopType = "containerStop";
    1237          734 :         stopID = stop.containerstop->getID();
    1238        92551 :     } else if (stop.chargingStation != nullptr) {
    1239              :         stopType = "chargingStation";
    1240         8152 :         stopID = stop.chargingStation->getID();
    1241        84399 :     } else if (stop.overheadWireSegment != nullptr) {
    1242              :         stopType = "overheadWireSegment";
    1243            0 :         stopID = stop.overheadWireSegment->getID();
    1244        84399 :     } else if (stop.parkingarea != nullptr) {
    1245              :         stopType = "parkingArea";
    1246        16201 :         stopID = stop.parkingarea->getID();
    1247              :     }
    1248       253660 :     const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
    1249              : 
    1250       126830 :     if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
    1251            0 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
    1252            0 :         return false;
    1253              :     }
    1254        58632 :     if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > stop.pars.endPos - stop.pars.startPos
    1255       186335 :             && MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
    1256          834 :         errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
    1257              :     }
    1258       126830 :     if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
    1259              :         // forbid access in case the parking requests other badges
    1260           14 :         errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
    1261            7 :         return false;
    1262              :     }
    1263       126823 :     const MSEdge* stopLaneEdge = &stop.lane->getEdge();
    1264              :     const MSEdge* stopEdge;
    1265       126823 :     if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
    1266              :         // stop lane is on the opposite side
    1267          145 :         stopEdge = stopLaneEdge->getOppositeEdge();
    1268          145 :         stop.isOpposite = true;
    1269              :     } else {
    1270              :         // if stop is on an internal edge the normal edge before the intersection is used
    1271       126678 :         stopEdge = stopLaneEdge->getNormalBefore();
    1272              :     }
    1273       126823 :     MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
    1274       126823 :     if (searchStart == nullptr) {
    1275       123389 :         searchStart = &myCurrEdge;
    1276       123389 :         if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
    1277              :             // already on the intersection but myCurrEdge is before it
    1278              :             searchStart = &succ;
    1279              :         }
    1280              :     }
    1281              : #ifdef DEBUG_ADD_STOP
    1282              :     if (DEBUG_COND) {
    1283              :         std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
    1284              :                   << " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
    1285              :                   << " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
    1286              :                   << "\n";
    1287              :     }
    1288              : #endif
    1289       126823 :     stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
    1290       126823 :     MSRouteIterator prevStopEdge = myCurrEdge;
    1291       126823 :     const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
    1292       126823 :     double prevStopPos = getPositionOnLane();
    1293              :     // where to insert the stop
    1294              :     std::list<MSStop>::iterator iter = myStops.begin();
    1295       126823 :     if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
    1296              :         iter = myStops.end();
    1297       103623 :         if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
    1298              :             prevStopEdge = myStops.back().edge;
    1299        38994 :             prevEdge = &myStops.back().lane->getEdge();
    1300        38994 :             prevStopPos = myStops.back().pars.endPos;
    1301        38994 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1302              :             if (prevStopEdge == stop.edge                // laneEdge check is insufficient for looped routes
    1303         6070 :                     && prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
    1304        45052 :                     && (prevStopPos > stop.pars.endPos ||
    1305         2481 :                         (prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
    1306          424 :                 stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
    1307              :             }
    1308              : #ifdef DEBUG_ADD_STOP
    1309              :             if (DEBUG_COND) {
    1310              :                 std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
    1311              :                           << " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
    1312              :             }
    1313              : #endif
    1314              :         }
    1315              :         // skip a number of occurences of stopEdge in looped route
    1316       103623 :         int skipLooped = stopPar.index - static_cast<int>(myStops.size());
    1317       103708 :         for (int j = 0; j < skipLooped; j++) {
    1318          231 :             auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
    1319          231 :             if (nextIt == myRoute->end()) {
    1320          146 :                 if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
    1321              :                     // only warn if the route loops over the stop edge at least once
    1322           28 :                     errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
    1323              :                 }
    1324          146 :                 break;
    1325              :             } else {
    1326           85 :                 stop.edge = nextIt;
    1327              :             }
    1328              :         }
    1329              :     } else {
    1330        23200 :         if (stopPar.index == STOP_INDEX_FIT) {
    1331        34976 :             while (iter != myStops.end() && (iter->edge < stop.edge ||
    1332         2574 :                                              (iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
    1333         2574 :                                              (stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
    1334              :                 prevStopEdge = iter->edge;
    1335        11875 :                 prevStopPos = iter->pars.endPos;
    1336              :                 ++iter;
    1337              :             }
    1338              :         } else {
    1339              :             int index = stopPar.index;
    1340           99 :             while (index > 0) {
    1341            0 :                 prevStopEdge = iter->edge;
    1342            0 :                 prevStopPos = iter->pars.endPos;
    1343              :                 ++iter;
    1344            0 :                 --index;
    1345              :             }
    1346              : #ifdef DEBUG_ADD_STOP
    1347              :             if (DEBUG_COND) {
    1348              :                 std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
    1349              :             }
    1350              : #endif
    1351           99 :             stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
    1352              :         }
    1353              :     }
    1354       127124 :     const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
    1355       126823 :     if (stop.edge == myRoute->end()) {
    1356           72 :         if (!wasTooClose) {
    1357          192 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
    1358              :         }
    1359           72 :         return false;
    1360              :     }
    1361              : 
    1362       126751 :     const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
    1363        32837 :                            prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
    1364              : 
    1365       126751 :     if (prevStopEdge > stop.edge ||
    1366              :             // a collision-stop happens after vehicle movement and may move the
    1367              :             // vehicle backwards on its lane (prevStopPos is the vehicle position)
    1368         1575 :             (tooClose && !stop.pars.collision)
    1369       253486 :             || (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
    1370              :         // check if the edge occurs again later in the route
    1371              :         //std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges())  << "\n";
    1372           16 :         if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
    1373           48 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
    1374              :         }
    1375           16 :         MSRouteIterator next = stop.edge + 1;
    1376           16 :         return addStop(stopPar, errorMsg, untilOffset, &next);
    1377              :     }
    1378       126735 :     if (wasTooClose) {
    1379              :         errorMsg = "";
    1380              :     }
    1381              :     // David.C:
    1382              :     //if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
    1383       126735 :     const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
    1384       126735 :     const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
    1385       126735 :     if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
    1386              :         return false;
    1387              :     }
    1388       126735 :     if (!hasDeparted() && myCurrEdge == stop.edge) {
    1389              :         double pos = -1;
    1390        26318 :         if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
    1391         4609 :             pos = myParameter->departPos;
    1392         4609 :             if (pos < 0.) {
    1393          194 :                 pos += (*myCurrEdge)->getLength();
    1394              :             }
    1395              :         }
    1396        26318 :         if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
    1397        19364 :             pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
    1398              :         }
    1399        26318 :         if (pos > stop.pars.endPos + endPosOffset) {
    1400           20 :             if (stop.edge != myRoute->end()) {
    1401              :                 // check if the edge occurs again later in the route
    1402           20 :                 MSRouteIterator next = stop.edge + 1;
    1403           20 :                 return addStop(stopPar, errorMsg, untilOffset, &next);
    1404              :             }
    1405            0 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
    1406            0 :             return false;
    1407              :         }
    1408              :     }
    1409       126715 :     if (iter != myStops.begin()) {
    1410              :         std::list<MSStop>::iterator iter2 = iter;
    1411              :         iter2--;
    1412        75559 :         if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
    1413        50850 :                 && (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
    1414            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1415           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1416           24 :                        + " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
    1417              :         }
    1418        50833 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1419            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1420           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1421           24 :                        + " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
    1422              :         }
    1423        50833 :         if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
    1424            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1425           18 :                        + "' set to start at " + time2string(stop.pars.arrival)
    1426           24 :                        + " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
    1427              :         }
    1428              :     } else {
    1429        92181 :         if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
    1430        75894 :                 && (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
    1431            6 :             errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1432           18 :                        + "' set to end at " + time2string(stop.getUntil())
    1433           24 :                        + " earlier than departure at " + time2string(getParameter().depart) + ".";
    1434              :         }
    1435              :     }
    1436       126715 :     if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
    1437           18 :         errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
    1438           54 :                    + "' set to end at " + time2string(stop.getUntil())
    1439           72 :                    + " earlier than arrival at " + time2string(stop.getArrival()) + ".";
    1440              :     }
    1441       126715 :     setSkips(stop, (int)myStops.size());
    1442       126715 :     myStops.insert(iter, stop);
    1443       126715 :     if (stopPar.tripId != "") {
    1444         2500 :         MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
    1445              :     }
    1446              :     //std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
    1447              :     //    << " routeIndex=" << (stop.edge - myRoute->begin())
    1448              :     //    << " stopIndex=" << std::distance(myStops.begin(), iter)
    1449              :     //    << " route=" << toString(myRoute->getEdges())  << "\n";
    1450              :     return true;
    1451              : }
    1452              : 
    1453              : 
    1454              : void
    1455       157292 : MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
    1456       157292 :     if (hasDeparted() && stop.edge > myRoute->begin()) {
    1457              :         // if the route is looped we must patch the index to ensure that state
    1458              :         // loading (and vehroute-output) encode the correct number of skips
    1459              :         int foundSkips = 0;
    1460              :         MSRouteIterator itPrev;
    1461              :         double prevEndPos;
    1462        60656 :         if (prevActiveStops > 0) {
    1463              :             assert((int)myStops.size() >= prevActiveStops);
    1464              :             auto prevStopIt = myStops.begin();
    1465        32180 :             std::advance(prevStopIt, prevActiveStops - 1);
    1466              :             const MSStop& prev = *prevStopIt;
    1467        32180 :             itPrev = prev.edge;
    1468        32180 :             prevEndPos = prev.pars.endPos;
    1469        28476 :         } else if (myPastStops.size() > 0) {
    1470        10728 :             itPrev = myRoute->begin() + myPastStops.back().routeIndex;
    1471        10728 :             prevEndPos = myPastStops.back().endPos;
    1472              :         } else {
    1473        17748 :             itPrev = myRoute->begin() + myParameter->departEdge;
    1474        17748 :             prevEndPos = myDepartPos;
    1475              :         }
    1476              :         //auto itPrevOrig = itPrev;
    1477        60656 :         if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
    1478              :             itPrev++;
    1479              :         }
    1480              :         //std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
    1481       564469 :         while (itPrev < stop.edge) {
    1482       503813 :             if (*itPrev == *stop.edge) {
    1483        19536 :                 foundSkips++;
    1484              :             }
    1485              :             itPrev++;
    1486              :         }
    1487              :         int newIndex = STOP_INDEX_END;
    1488        60656 :         if (foundSkips > 0) {
    1489              :             //if (getID() == "77_0_0") {
    1490              :             //    std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
    1491              :             //        << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
    1492              :             //        << " prevEdge=" << (*itPrevOrig)->getID()
    1493              :             //        << " prevIndex=" << (itPrevOrig - myRoute->begin())
    1494              :             //        << " skips=" << foundSkips << "\n";
    1495              :             //}
    1496         7033 :             newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
    1497              :         }
    1498        60656 :         const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
    1499              :     }
    1500       157292 : }
    1501              : 
    1502              : 
    1503              : void
    1504      6503374 : MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
    1505      6503374 :     if (addRouteStops) {
    1506      6507487 :         for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    1507              :             std::string errorMsg;
    1508         8541 :             if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
    1509           20 :                 throw ProcessError(errorMsg);
    1510              :             }
    1511         8531 :             if (errorMsg != "") {
    1512          694 :                 WRITE_WARNING(errorMsg);
    1513              :             }
    1514              :         }
    1515              :     }
    1516      6503364 :     const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
    1517      6592212 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    1518              :         std::string errorMsg;
    1519        88871 :         if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
    1520           46 :             throw ProcessError(errorMsg);
    1521              :         }
    1522        88848 :         if (errorMsg != "") {
    1523          452 :             WRITE_WARNING(errorMsg);
    1524              :         }
    1525              :     }
    1526      6503341 : }
    1527              : 
    1528              : 
    1529              : bool
    1530      1238535 : MSBaseVehicle::haveValidStopEdges(bool silent) const {
    1531      1238535 :     MSRouteIterator start = myCurrEdge;
    1532              :     int i = 0;
    1533              :     bool ok = true;
    1534      1291875 :     for (const MSStop& stop : myStops) {
    1535              :         MSRouteIterator it;
    1536        53340 :         if (stop.lane->isInternal()) {
    1537              :             // find the normal predecessor and ensure that the next route edge
    1538              :             // matches the successor of the internal edge successor
    1539            0 :             it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
    1540            0 :             if (it != myRoute->end() && (
    1541            0 :                         it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
    1542            0 :                 it = myRoute->end(); // signal failure
    1543              :             }
    1544              :         } else {
    1545        53340 :             it = std::find(start, myRoute->end(), &stop.lane->getEdge());
    1546              :         }
    1547        53340 :         if (it == myRoute->end()) {
    1548            0 :             if (!silent) {
    1549            0 :                 WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
    1550              :                              i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1551              :             }
    1552              :             ok = false;
    1553              :         } else {
    1554              :             MSRouteIterator it2;
    1555      2273165 :             for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
    1556      2269261 :                 if (it2 == stop.edge) {
    1557              :                     break;
    1558              :                 }
    1559              :             }
    1560        53340 :             if (it2 == myRoute->end()) {
    1561         3904 :                 if (!silent) {
    1562            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
    1563              :                                  i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
    1564              :                 }
    1565              :                 ok = false;
    1566        49436 :             } else if (it2 < start) {
    1567            0 :                 if (!silent) {
    1568            0 :                     WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
    1569              :                                  i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
    1570              :                 }
    1571              :                 ok = false;
    1572              :             } else {
    1573        49436 :                 start = stop.edge;
    1574              :             }
    1575              :         }
    1576        53340 :         i++;
    1577              :     }
    1578      1238535 :     return ok;
    1579              : }
    1580              : 
    1581              : 
    1582              : const ConstMSEdgeVector
    1583      2653024 : MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
    1584              :     assert(haveValidStopEdges());
    1585              :     ConstMSEdgeVector result;
    1586              :     const MSStop* prev = nullptr;
    1587      2653024 :     const MSEdge* internalSuccessor = nullptr;
    1588      2730066 :     for (const MSStop& stop : myStops) {
    1589        77042 :         if (stop.reached) {
    1590         9404 :             if (stop.pars.jump >= 0) {
    1591            0 :                 jumps.insert((int)result.size());
    1592              :             }
    1593         9404 :             continue;
    1594              :         }
    1595        67638 :         const double stopPos = stop.getEndPos(*this);
    1596              :         if ((prev == nullptr
    1597        28346 :                 || prev->edge != stop.edge
    1598         1322 :                 || (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
    1599        94662 :                 && *stop.edge != internalSuccessor) {
    1600        66316 :             result.push_back(*stop.edge);
    1601        66316 :             if (stop.lane->isInternal()) {
    1602            5 :                 internalSuccessor = stop.lane->getNextNormal();
    1603            5 :                 result.push_back(internalSuccessor);
    1604              :             } else {
    1605        66311 :                 internalSuccessor = nullptr;
    1606              :             }
    1607              :         }
    1608              :         prev = &stop;
    1609        67638 :         if (firstPos == INVALID_DOUBLE) {
    1610        39292 :             if (stop.parkingarea != nullptr) {
    1611         3269 :                 firstPos = MAX2(0., stopPos);
    1612              :             } else {
    1613        36023 :                 firstPos = stopPos;
    1614              :             }
    1615              :         }
    1616        67638 :         lastPos = stopPos;
    1617        67638 :         if (stop.pars.jump >= 0) {
    1618          780 :             jumps.insert((int)result.size() - 1);
    1619              :         }
    1620              :     }
    1621              :     //std::cout << "getStopEdges veh=" << getID() << " result=" << toString(result) << "\n";
    1622      2653024 :     return result;
    1623            0 : }
    1624              : 
    1625              : 
    1626              : std::vector<std::pair<int, double> >
    1627        21944 : MSBaseVehicle::getStopIndices() const {
    1628              :     std::vector<std::pair<int, double> > result;
    1629        45296 :     for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
    1630        46704 :         result.push_back(std::make_pair(
    1631        23352 :                              (int)(iter->edge - myRoute->begin()),
    1632        23352 :                              iter->getEndPos(*this)));
    1633              :     }
    1634        21944 :     return result;
    1635            0 : }
    1636              : 
    1637              : 
    1638              : MSStop&
    1639      5923212 : MSBaseVehicle::getNextStop() {
    1640              :     assert(myStops.size() > 0);
    1641      5923212 :     return myStops.front();
    1642              : }
    1643              : 
    1644              : SUMOTime
    1645      3948993 : MSBaseVehicle::getStopDuration() const {
    1646      3948993 :     if (isStopped()) {
    1647      1511098 :         return myStops.front().duration;
    1648              :     } else {
    1649              :         return 0;
    1650              :     }
    1651              : }
    1652              : 
    1653              : 
    1654              : MSStop&
    1655        14584 : MSBaseVehicle::getStop(int nextStopIndex) {
    1656        14584 :     if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
    1657            0 :         throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
    1658              :     }
    1659              :     auto stopIt = myStops.begin();
    1660              :     std::advance(stopIt, nextStopIndex);
    1661        14584 :     return *stopIt;
    1662              : }
    1663              : 
    1664              : 
    1665              : const SUMOVehicleParameter::Stop*
    1666       193225 : MSBaseVehicle::getNextStopParameter() const {
    1667       193225 :     if (hasStops()) {
    1668       107813 :         return &myStops.front().pars;
    1669              :     }
    1670              :     return nullptr;
    1671              : }
    1672              : 
    1673              : 
    1674              : bool
    1675        45969 : MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
    1676              :     //if the stop exists update the duration
    1677        72424 :     for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
    1678        49186 :         if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
    1679              :             // update existing stop
    1680        22731 :             if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
    1681        21238 :                 myStops.erase(iter);
    1682              :             } else {
    1683         1493 :                 iter->duration = stop.duration;
    1684         1493 :                 iter->triggered = stop.triggered;
    1685         1493 :                 iter->containerTriggered = stop.containerTriggered;
    1686         1493 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
    1687         1493 :                 const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
    1688              :             }
    1689              :             return true;
    1690              :         }
    1691              :     }
    1692        23238 :     const bool result = addStop(stop, errorMsg);
    1693        23238 :     if (result) {
    1694              :         /// XXX handle stops added out of order
    1695        23225 :         myParameter->stops.push_back(stop);
    1696              :     }
    1697              :     return result;
    1698              : }
    1699              : 
    1700              : 
    1701              : void
    1702          550 : MSBaseVehicle::unregisterWaiting() {
    1703          550 :     if (myAmRegisteredAsWaiting) {
    1704          392 :         MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
    1705          392 :         myAmRegisteredAsWaiting = false;
    1706              :     }
    1707          550 : }
    1708              : 
    1709              : 
    1710              : bool
    1711          833 : MSBaseVehicle::abortNextStop(int nextStopIndex) {
    1712          833 :     if (hasStops() && nextStopIndex < (int)myStops.size()) {
    1713          833 :         if (nextStopIndex == 0 && isStopped()) {
    1714           34 :             resumeFromStopping();
    1715              :         } else {
    1716              :             auto stopIt = myStops.begin();
    1717              :             std::advance(stopIt, nextStopIndex);
    1718          799 :             myStops.erase(stopIt);
    1719              :         }
    1720          833 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1721              :             // stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
    1722              :             auto stopIt2 = myParameter->stops.begin();
    1723              :             std::advance(stopIt2, nextStopIndex);
    1724            8 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
    1725              :         }
    1726          833 :         return true;
    1727              :     } else {
    1728              :         return false;
    1729              :     }
    1730              : }
    1731              : 
    1732              : 
    1733              : bool
    1734          133 : MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    1735          133 :     const int n = (int)myStops.size();
    1736          133 :     if (nextStopIndex < 0 || nextStopIndex >= n) {
    1737            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1738            5 :         return false;
    1739              :     }
    1740          128 :     if (nextStopIndex == 0 && isStopped()) {
    1741            7 :         errorMsg = TL("cannot replace reached stop");
    1742            7 :         return false;
    1743              :     }
    1744          121 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1745          121 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    1746          121 :     MSEdge* stopEdge = &stopLane->getEdge();
    1747              : 
    1748              :     auto itStop = myStops.begin();
    1749              :     std::advance(itStop, nextStopIndex);
    1750              :     MSStop& replacedStop = *itStop;
    1751              : 
    1752              :     // check parking access rights
    1753          121 :     if (stop.parkingarea != "") {
    1754            0 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    1755            0 :         if (pa != nullptr && !pa->accepts(this)) {
    1756            0 :             errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
    1757            0 :             return false;
    1758              :         }
    1759              :     }
    1760              : 
    1761          121 :     if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
    1762              :         // only replace stop attributes
    1763           10 :         const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    1764           10 :         replacedStop.initPars(stop);
    1765           10 :         return true;
    1766              :     }
    1767              : 
    1768          111 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    1769            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    1770            0 :         return false;
    1771              :     }
    1772              : 
    1773          111 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1774          111 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1775          111 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1776          111 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1777          111 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1778          111 :     MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
    1779          111 :     auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
    1780          111 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    1781              : 
    1782          111 :     bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
    1783              : 
    1784              :     ConstMSEdgeVector toNewStop;
    1785          111 :     if (!teleport) {
    1786           82 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    1787           82 :         if (toNewStop.size() == 0) {
    1788           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    1789            5 :             return false;
    1790              :         }
    1791              :     }
    1792              : 
    1793              :     ConstMSEdgeVector fromNewStop;
    1794          106 :     if (!newDestination) {
    1795          101 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    1796          101 :         if (fromNewStop.size() == 0) {
    1797            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    1798            0 :             return false;
    1799              :         }
    1800              :     }
    1801              : 
    1802          106 :     const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
    1803          106 :     replacedStop.initPars(stop);
    1804          106 :     replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
    1805          106 :     replacedStop.lane = stopLane;
    1806          106 :     if (MSGlobals::gUseMesoSim) {
    1807           18 :         replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
    1808           18 :         if (replacedStop.lane->isInternal()) {
    1809            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    1810            0 :             return false;
    1811              :         }
    1812              :     }
    1813              : 
    1814          106 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    1815              :     ConstMSEdgeVector newEdges; // only remaining
    1816          106 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    1817          106 :     if (!teleport) {
    1818           77 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    1819              :     } else {
    1820           29 :         newEdges.push_back(*itStart);
    1821              :     }
    1822          106 :     if (!newDestination) {
    1823          101 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    1824          101 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    1825              :     } else {
    1826            5 :         newEdges.push_back(stopEdge);
    1827              :     }
    1828              :     //std::cout << SIMTIME << " replaceStop veh=" << getID()
    1829              :     //    << " teleport=" << teleport
    1830              :     //    << " busStop=" << stop.busstop
    1831              :     //    << " oldEdges=" << oldRemainingEdges.size()
    1832              :     //    << " newEdges=" << newEdges.size()
    1833              :     //    << " toNewStop=" << toNewStop.size()
    1834              :     //    << " fromNewStop=" << fromNewStop.size()
    1835              :     //    << "\n";
    1836              : 
    1837          106 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    1838          106 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    1839          106 :     const double savings = previousCost - routeCost;
    1840          106 :     if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1841              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    1842            5 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
    1843              :     }
    1844          106 :     if (teleport) {
    1845              :         // let the vehicle jump rather than teleport
    1846              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    1847              :         // already configure to jump before the replaced stop)
    1848           29 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    1849              :             return false;
    1850              :         };
    1851              :     }
    1852          106 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    1853          111 : }
    1854              : 
    1855              : 
    1856              : bool
    1857           52 : MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
    1858           52 :     const int n = (int)myStops.size();
    1859           52 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    1860            0 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1861            0 :         return false;
    1862              :     }
    1863           52 :     if (nextStopIndex == 0 && isStopped()) {
    1864            0 :         errorMsg = TL("cannot reroute towards reached stop");
    1865            0 :         return false;
    1866              :     }
    1867           52 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1868              : 
    1869           52 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1870           52 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1871           52 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1872           52 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1873           52 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1874           52 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    1875           52 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    1876           52 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    1877              : 
    1878              :     ConstMSEdgeVector newBetween;
    1879           52 :     if (!teleport) {
    1880           15 :         router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
    1881           15 :         if (newBetween.size() == 0) {
    1882            0 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
    1883            0 :             return false;
    1884              :         }
    1885              :     }
    1886              : 
    1887           52 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    1888              :     ConstMSEdgeVector newEdges; // only remaining
    1889           52 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    1890           52 :     if (!teleport) {
    1891           15 :         newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
    1892              :     } else {
    1893           37 :         newEdges.push_back(*itStart);
    1894              :     }
    1895           52 :     newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    1896              :     //std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
    1897              :     //    << " oldEdges=" << oldRemainingEdges.size()
    1898              :     //    << " newEdges=" << newEdges.size()
    1899              :     //    << " toNewStop=" << toNewStop.size()
    1900              :     //    << " fromNewStop=" << fromNewStop.size()
    1901              :     //    << "\n";
    1902              : 
    1903           52 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    1904           52 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    1905           52 :     const double savings = previousCost - routeCost;
    1906              : 
    1907           52 :     if (teleport) {
    1908              :         // let the vehicle jump rather than teleport
    1909              :         // we add a jump-stop at the end of the edge (unless the vehicle is
    1910              :         // already configure to jump before the replaced stop)
    1911           37 :         if (!insertJump(nextStopIndex, itStart, errorMsg)) {
    1912              :             return false;
    1913              :         };
    1914              :     }
    1915           52 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    1916           52 : }
    1917              : 
    1918              : 
    1919              : bool
    1920           66 : MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
    1921              :     bool needJump = true;
    1922           66 :     if (nextStopIndex > 0) {
    1923              :         auto itPriorStop = myStops.begin();
    1924           48 :         std::advance(itPriorStop, nextStopIndex - 1);
    1925              :         const MSStop& priorStop = *itPriorStop;
    1926           48 :         if (priorStop.pars.jump >= 0) {
    1927              :             needJump = false;
    1928              :         }
    1929              :     }
    1930              :     if (needJump) {
    1931           47 :         SUMOVehicleParameter::Stop jumpStopPars;
    1932           47 :         jumpStopPars.endPos = (*itStart)->getLength();
    1933           47 :         jumpStopPars.speed = 1000;
    1934           47 :         jumpStopPars.jump = 0;
    1935              :         jumpStopPars.edge = (*itStart)->getID();
    1936           47 :         jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
    1937              :         MSLane* jumpStopLane = nullptr;
    1938           47 :         for (MSLane* cand : (*itStart)->getLanes()) {
    1939           47 :             if (cand->allowsVehicleClass(getVClass())) {
    1940              :                 jumpStopLane = cand;
    1941              :                 break;
    1942              :             }
    1943              :         }
    1944           47 :         if (jumpStopLane == nullptr) {
    1945            0 :             errorMsg = TL("unable to replace stop with teleporting");
    1946              :             return false;
    1947              :         }
    1948              :         auto itStop = myStops.begin();
    1949              :         std::advance(itStop, nextStopIndex);
    1950           47 :         MSStop jumpStop(jumpStopPars);
    1951           47 :         jumpStop.initPars(jumpStopPars);
    1952           47 :         jumpStop.lane = jumpStopLane;
    1953           47 :         jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
    1954           47 :         myStops.insert(itStop, jumpStop);
    1955           47 :         if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
    1956              :             // stops will be rebuilt from scratch so we must patch the stops in myParameter
    1957              :             auto it = myParameter->stops.begin() + nextStopIndex;
    1958            0 :             const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
    1959              :         }
    1960           47 :     }
    1961              :     return true;
    1962              : }
    1963              : 
    1964              : 
    1965              : bool
    1966          330 : MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
    1967          330 :     const int n = (int)myStops.size();
    1968          330 :     if (nextStopIndex < 0 || nextStopIndex > n) {
    1969            5 :         errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
    1970            5 :         return false;
    1971              :     }
    1972          325 :     if (nextStopIndex == 0 && isStopped()) {
    1973            7 :         errorMsg = TL("cannot insert stop before the currently reached stop");
    1974            7 :         return false;
    1975              :     }
    1976          318 :     const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
    1977          318 :     MSLane* stopLane = MSLane::dictionary(stop.lane);
    1978          318 :     MSEdge* stopEdge = &stopLane->getEdge();
    1979              : 
    1980          318 :     if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
    1981            0 :         errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
    1982            0 :         return false;
    1983              :     }
    1984              : 
    1985              :     // check parking access rights
    1986          318 :     if (stop.parkingarea != "") {
    1987          137 :         MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
    1988          137 :         if (pa != nullptr && !pa->accepts(this)) {
    1989            0 :             errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
    1990            0 :             return false;
    1991              :         }
    1992              :     }
    1993              : 
    1994          318 :     const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
    1995          318 :     std::vector<MSStop> stops(myStops.begin(), myStops.end());
    1996          318 :     const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
    1997          318 :     MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
    1998          318 :     double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
    1999          318 :     MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
    2000          318 :     auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
    2001          318 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
    2002              : 
    2003          318 :     bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
    2004              : 
    2005              :     ConstMSEdgeVector toNewStop;
    2006          318 :     if (!teleport) {
    2007          291 :         router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
    2008          291 :         if (toNewStop.size() == 0) {
    2009           15 :             errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
    2010            5 :             return false;
    2011              :         }
    2012              :     }
    2013              : 
    2014              :     ConstMSEdgeVector fromNewStop;
    2015          313 :     if (!newDestination) {
    2016          284 :         router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
    2017          284 :         if (fromNewStop.size() == 0) {
    2018            0 :             errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
    2019            0 :             return false;
    2020              :         }
    2021              :     }
    2022              : 
    2023              :     auto itStop = myStops.begin();
    2024              :     std::advance(itStop, nextStopIndex);
    2025          313 :     MSStop newStop(stop);
    2026          313 :     newStop.initPars(stop);
    2027          313 :     newStop.edge = myRoute->end(); // will be patched in replaceRoute
    2028          313 :     newStop.lane = stopLane;
    2029          313 :     if (MSGlobals::gUseMesoSim) {
    2030           66 :         newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
    2031           66 :         if (newStop.lane->isInternal()) {
    2032            0 :             errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
    2033            0 :             return false;
    2034              :         }
    2035              :     }
    2036          313 :     myStops.insert(itStop, newStop);
    2037              : 
    2038          313 :     ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
    2039              :     ConstMSEdgeVector newEdges; // only remaining
    2040          313 :     newEdges.insert(newEdges.end(), myCurrEdge, itStart);
    2041          313 :     if (!teleport) {
    2042          286 :         newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
    2043              :     } else {
    2044           27 :         newEdges.push_back(*itStart);
    2045              :     }
    2046          313 :     if (!newDestination) {
    2047          284 :         newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
    2048          284 :         newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
    2049              :     } else {
    2050           29 :         newEdges.push_back(stopEdge);
    2051              :     }
    2052              :     //std::cout << SIMTIME << " insertStop veh=" << getID()
    2053              :     //    << " teleport=" << teleport
    2054              :     //    << " busStop=" << stop.busstop
    2055              :     //    << " oldEdges=" << oldRemainingEdges.size()
    2056              :     //    << " newEdges=" << newEdges.size()
    2057              :     //    << " toNewStop=" << toNewStop.size()
    2058              :     //    << " fromNewStop=" << fromNewStop.size()
    2059              :     //    << "\n";
    2060              : 
    2061          313 :     const double routeCost = router.recomputeCosts(newEdges, this, t);
    2062          313 :     const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
    2063          313 :     const double savings = previousCost - routeCost;
    2064              : 
    2065          313 :     if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
    2066              :         // stops will be rebuilt from scratch so we must patch the stops in myParameter
    2067              :         auto it = myParameter->stops.begin() + nextStopIndex;
    2068           15 :         const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
    2069              :     }
    2070          313 :     return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
    2071          631 : }
    2072              : 
    2073              : 
    2074              : double
    2075            0 : MSBaseVehicle::getStateOfCharge() const {
    2076            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2077            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2078            0 :         return batteryOfVehicle->getActualBatteryCapacity();
    2079              :     } else {
    2080            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2081            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2082            0 :             return batteryOfVehicle->getActualBatteryCapacity();
    2083              :         }
    2084              :     }
    2085              :     return -1;
    2086              : }
    2087              : 
    2088              : 
    2089              : double
    2090            0 : MSBaseVehicle::getRelativeStateOfCharge() const {
    2091            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2092            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2093            0 :         return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2094              :     } else {
    2095            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2096            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2097            0 :             return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
    2098              :         }
    2099              :     }
    2100              :     return -1;
    2101              : }
    2102              : 
    2103              : 
    2104              : double
    2105            0 : MSBaseVehicle::getChargedEnergy() const {
    2106            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2107            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2108            0 :         return batteryOfVehicle->getEnergyCharged();
    2109              :     } else {
    2110            0 :         if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2111            0 :             MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2112            0 :             return batteryOfVehicle->getEnergyCharged();
    2113              :         }
    2114              :     }
    2115              :     return -1;
    2116              : }
    2117              : 
    2118              : 
    2119              : double
    2120            0 : MSBaseVehicle::getMaxChargeRate() const {
    2121            0 :     if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
    2122            0 :         MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
    2123            0 :         return batteryOfVehicle->getMaximumChargeRate();
    2124              :     }
    2125              :     return -1;
    2126              : }
    2127              : 
    2128              : 
    2129              : double
    2130            0 : MSBaseVehicle::getElecHybridCurrent() const {
    2131            0 :     if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
    2132            0 :         MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
    2133            0 :         return elecHybridDevice->getCurrentFromOverheadWire();
    2134              :     }
    2135              : 
    2136              :     return NAN;
    2137              : }
    2138              : 
    2139              : double
    2140          630 : MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
    2141          630 :     if (isOnRoad() || isIdling()) {
    2142          630 :         return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
    2143              :     } else {
    2144              :         return 0.;
    2145              :     }
    2146              : }
    2147              : 
    2148              : 
    2149              : const MSEdgeWeightsStorage&
    2150      5140878 : MSBaseVehicle::getWeightsStorage() const {
    2151      5140878 :     return _getWeightsStorage();
    2152              : }
    2153              : 
    2154              : 
    2155              : MSEdgeWeightsStorage&
    2156          650 : MSBaseVehicle::getWeightsStorage() {
    2157          650 :     return _getWeightsStorage();
    2158              : }
    2159              : 
    2160              : 
    2161              : MSEdgeWeightsStorage&
    2162      5141528 : MSBaseVehicle::_getWeightsStorage() const {
    2163      5141528 :     if (myEdgeWeights == nullptr) {
    2164        13328 :         myEdgeWeights = new MSEdgeWeightsStorage();
    2165              :     }
    2166      5141528 :     return *myEdgeWeights;
    2167              : }
    2168              : 
    2169              : 
    2170              : 
    2171              : 
    2172              : int
    2173      7250987 : MSBaseVehicle::getPersonNumber() const {
    2174      7250987 :     int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
    2175      7250987 :     return boarded + myParameter->personNumber;
    2176              : }
    2177              : 
    2178              : int
    2179            0 : MSBaseVehicle::getLeavingPersonNumber() const {
    2180              :     int leavingPersonNumber = 0;
    2181            0 :     const std::vector<MSTransportable*>& persons = getPersons();
    2182            0 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2183            0 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
    2184              :         const MSStop* stop = &myStops.front();
    2185            0 :         const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
    2186            0 :         if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
    2187            0 :             leavingPersonNumber++;
    2188              :         }
    2189              :     }
    2190            0 :     return leavingPersonNumber;
    2191              : }
    2192              : 
    2193              : std::vector<std::string>
    2194          165 : MSBaseVehicle::getPersonIDList() const {
    2195              :     std::vector<std::string> ret;
    2196          165 :     const std::vector<MSTransportable*>& persons = getPersons();
    2197          525 :     for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
    2198          360 :         ret.push_back((*it_p)->getID());
    2199              :     }
    2200          165 :     return ret;
    2201            0 : }
    2202              : 
    2203              : int
    2204      4394800 : MSBaseVehicle::getContainerNumber() const {
    2205      4394800 :     int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
    2206      4394800 :     return loaded + myParameter->containerNumber;
    2207              : }
    2208              : 
    2209              : 
    2210              : void
    2211          138 : MSBaseVehicle::removeTransportable(MSTransportable* t) {
    2212              :     // this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
    2213          138 :     if (myPersonDevice != nullptr) {
    2214          118 :         myPersonDevice->removeTransportable(t);
    2215              :     }
    2216          138 :     if (myContainerDevice != nullptr) {
    2217           20 :         myContainerDevice->removeTransportable(t);
    2218              :     }
    2219          138 : }
    2220              : 
    2221              : 
    2222              : const std::vector<MSTransportable*>&
    2223      6863987 : MSBaseVehicle::getPersons() const {
    2224      6863987 :     if (myPersonDevice == nullptr) {
    2225              :         return myEmptyTransportableVector;
    2226              :     } else {
    2227        13267 :         return myPersonDevice->getTransportables();
    2228              :     }
    2229              : }
    2230              : 
    2231              : 
    2232              : const std::vector<MSTransportable*>&
    2233      5628337 : MSBaseVehicle::getContainers() const {
    2234      5628337 :     if (myContainerDevice == nullptr) {
    2235              :         return myEmptyTransportableVector;
    2236              :     } else {
    2237         2906 :         return myContainerDevice->getTransportables();
    2238              :     }
    2239              : }
    2240              : 
    2241              : 
    2242              : bool
    2243          202 : MSBaseVehicle::isLineStop(double position) const {
    2244          202 :     if (myParameter->line == "") {
    2245              :         // not a public transport line
    2246              :         return false;
    2247              :     }
    2248          348 :     for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
    2249          209 :         if (stop.startPos <= position && position <= stop.endPos) {
    2250              :             return true;
    2251              :         }
    2252              :     }
    2253          164 :     for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
    2254           34 :         if (stop.startPos <= position && position <= stop.endPos) {
    2255              :             return true;
    2256              :         }
    2257              :     }
    2258              :     return false;
    2259              : }
    2260              : 
    2261              : 
    2262              : bool
    2263           45 : MSBaseVehicle::hasDevice(const std::string& deviceName) const {
    2264          144 :     for (MSDevice* const dev : myDevices) {
    2265          126 :         if (dev->deviceName() == deviceName) {
    2266              :             return true;
    2267              :         }
    2268              :     }
    2269              :     return false;
    2270              : }
    2271              : 
    2272              : 
    2273              : void
    2274            9 : MSBaseVehicle::createDevice(const std::string& deviceName) {
    2275            9 :     if (!hasDevice(deviceName)) {
    2276            9 :         if (deviceName == "rerouting") {
    2277           27 :             ((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
    2278            9 :             MSDevice_Routing::buildVehicleDevices(*this, myDevices);
    2279            9 :             if (hasDeparted()) {
    2280              :                 // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
    2281            0 :                 MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
    2282              :                 assert(routingDevice != 0);
    2283            0 :                 routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
    2284              :             }
    2285              :         } else {
    2286            0 :             throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
    2287              :         }
    2288              :     }
    2289            9 : }
    2290              : 
    2291              : 
    2292              : std::string
    2293        49534 : MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
    2294        57692 :     for (MSVehicleDevice* const dev : myDevices) {
    2295        57683 :         if (dev->deviceName() == deviceName) {
    2296        49525 :             return dev->getParameter(key);
    2297              :         }
    2298              :     }
    2299           27 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2300              : }
    2301              : 
    2302              : 
    2303              : void
    2304          207 : MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
    2305          342 :     for (MSVehicleDevice* const dev : myDevices) {
    2306          342 :         if (dev->deviceName() == deviceName) {
    2307          207 :             dev->setParameter(key, value);
    2308          207 :             return;
    2309              :         }
    2310              :     }
    2311            0 :     throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
    2312              : }
    2313              : 
    2314              : 
    2315              : void
    2316          842 : MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
    2317         1669 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
    2318          837 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
    2319          837 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2320              :         // checked in MSLink::ignoreFoe
    2321              :     } else {
    2322           15 :         throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
    2323              :     }
    2324          837 : }
    2325              : 
    2326              : 
    2327              : void
    2328           38 : MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
    2329              :     // handle some generic params first and then delegate to the carFollowModel itself
    2330           67 :     if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
    2331           17 :         getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
    2332           17 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
    2333              :         // checked in MSVehicle::planMove
    2334              :     } else {
    2335           21 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
    2336           21 :         if (microVeh) {
    2337              :             // remove 'carFollowModel.' prefix
    2338           21 :             const std::string attrName = key.substr(15);
    2339           21 :             microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
    2340              :         }
    2341              :     }
    2342           33 : }
    2343              : 
    2344              : 
    2345              : void
    2346      5104379 : MSBaseVehicle::initTransientModelParams() {
    2347              :     /* Design idea for additional junction model parameters:
    2348              :        We can distinguish between 3 levels of parameters
    2349              :        1. typically shared by multiple vehicles -> vType parameter
    2350              :        2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
    2351              :        3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
    2352              :        */
    2353      5372156 :     for (auto item : getParameter().getParametersMap()) {
    2354       535554 :         if (StringUtils::startsWith(item.first, "junctionModel.")) {
    2355          832 :             setJunctionModelParameter(item.first, item.second);
    2356       533890 :         } else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
    2357           17 :             setCarFollowModelParameter(item.first, item.second);
    2358              :         }
    2359              :     }
    2360     10208758 :     const std::string routingModeStr = getStringParam("device.rerouting.mode");
    2361              :     try {
    2362      5104379 :         int routingMode = StringUtils::toInt(routingModeStr);
    2363      5104379 :         if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
    2364              :             setRoutingMode(routingMode);
    2365              :         }
    2366            0 :     } catch (NumberFormatException&) {
    2367              :         // @todo interpret symbolic constants
    2368            0 :         throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
    2369            0 :     }
    2370      5104379 : }
    2371              : 
    2372              : 
    2373              : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
    2374        23113 : MSBaseVehicle::getRouterTT() const {
    2375        23113 :     if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
    2376          102 :         return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
    2377              :     } else {
    2378        23011 :         return MSNet::getInstance()->getRouterTT(getRNGIndex());
    2379              :     }
    2380              : }
    2381              : 
    2382              : 
    2383              : void
    2384        30338 : MSBaseVehicle::replaceVehicleType(MSVehicleType* type) {
    2385              :     assert(type != nullptr);
    2386              :     // save old parameters before possible type deletion
    2387        30338 :     const double oldMu = myType->getSpeedFactor().getParameter()[0];
    2388        30338 :     const double oldDev = myType->getSpeedFactor().getParameter()[1];
    2389        30338 :     if (myType->isVehicleSpecific() && type != myType) {
    2390          802 :         MSNet::getInstance()->getVehicleControl().removeVType(myType);
    2391              :     }
    2392              :     // adapt myChosenSpeedFactor to the new type
    2393        30338 :     if (oldDev == 0.) {
    2394              :         // old type had speedDev 0, reroll
    2395        22546 :         myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
    2396              :     } else {
    2397              :         // map old speedFactor onto new distribution
    2398         7792 :         const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
    2399         7792 :         const double newMu = type->getSpeedFactor().getParameter()[0];
    2400         7792 :         const double newDev = type->getSpeedFactor().getParameter()[1];
    2401         7792 :         myChosenSpeedFactor = newMu + distPoint * newDev;
    2402              :         // respect distribution limits
    2403         7792 :         myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
    2404         7797 :         myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
    2405              :     }
    2406        30338 :     myType = type;
    2407        30338 :     if (myEnergyParams != nullptr) {
    2408              :         myEnergyParams->setSecondary(type->getEmissionParameters());
    2409              :     }
    2410        30338 : }
    2411              : 
    2412              : 
    2413              : MSVehicleType&
    2414        93181 : MSBaseVehicle::getSingularType() {
    2415        93181 :     if (myType->isVehicleSpecific()) {
    2416              :         return *myType;
    2417              :     }
    2418         2198 :     MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
    2419         1099 :     replaceVehicleType(type);
    2420         1099 :     return *type;
    2421              : }
    2422              : 
    2423              : 
    2424              : int
    2425       508598 : MSBaseVehicle::getRNGIndex() const {
    2426       508598 :     const MSLane* const lane = getLane();
    2427       508598 :     if (lane == nullptr) {
    2428        14596 :         return getEdge()->getLanes()[0]->getRNGIndex();
    2429              :     } else {
    2430       494002 :         return lane->getRNGIndex();
    2431              :     }
    2432              : }
    2433              : 
    2434              : 
    2435              : SumoRNG*
    2436    672001405 : MSBaseVehicle::getRNG() const {
    2437    672001405 :     const MSLane* lane = getLane();
    2438    672001405 :     if (lane == nullptr) {
    2439         2745 :         return getEdge()->getLanes()[0]->getRNG();
    2440              :     } else {
    2441    671998660 :         return lane->getRNG();
    2442              :     }
    2443              : }
    2444              : 
    2445              : std::string
    2446        68325 : MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
    2447        68325 :     const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
    2448       136650 :     if (StringUtils::startsWith(key, "device.")) {
    2449       148602 :         StringTokenizer tok(key, ".");
    2450        49534 :         if (tok.size() < 3) {
    2451            0 :             error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
    2452            0 :             return "";
    2453              :         }
    2454              :         try {
    2455       148602 :             return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
    2456           18 :         } catch (InvalidArgument& e) {
    2457           54 :             error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
    2458           18 :             return "";
    2459           18 :         }
    2460        87116 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2461          316 :         if (microVeh == nullptr) {
    2462           36 :             error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
    2463           18 :             return "";
    2464              :         }
    2465          298 :         const std::string attrName = key.substr(16);
    2466              :         try {
    2467          298 :             return microVeh->getLaneChangeModel().getParameter(attrName);
    2468           36 :         } catch (InvalidArgument& e) {
    2469          108 :             error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
    2470           36 :             return "";
    2471           36 :         }
    2472        36950 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2473           16 :         if (microVeh == nullptr) {
    2474            0 :             error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
    2475            0 :             return "";
    2476              :         }
    2477           16 :         const std::string attrName = key.substr(15);
    2478              :         try {
    2479           16 :             return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
    2480            0 :         } catch (InvalidArgument& e) {
    2481            0 :             error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
    2482            0 :             return "";
    2483            0 :         }
    2484        18495 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2485          108 :         StringTokenizer tok(key, ".");
    2486           36 :         if (tok.size() != 3) {
    2487            0 :             error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
    2488            0 :             return "";
    2489              :         }
    2490           81 :         return hasDevice(tok.get(1)) ? "true" : "false";
    2491              :         // parking related parameters start here
    2492        18459 :     } else if (key == "parking.rerouteCount") {
    2493           15 :         return toString(getNumberParkingReroutes());
    2494        36816 :     } else if (StringUtils::startsWith(key, "parking.memory.")) {
    2495              :         std::vector<std::string> values;
    2496           65 :         if (getParkingMemory()) {
    2497           25 :             if (key == "parking.memory.IDList") {
    2498           30 :                 for (const auto& item : *getParkingMemory()) {
    2499           25 :                     values.push_back(item.first->getID());
    2500              :                 }
    2501           20 :             } else if (key == "parking.memory.score") {
    2502           30 :                 for (const auto& item : *getParkingMemory()) {
    2503           25 :                     values.push_back(item.second.score);
    2504              :                 }
    2505           15 :             } else if (key == "parking.memory.blockedAtTime") {
    2506           30 :                 for (const auto& item : *getParkingMemory()) {
    2507           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
    2508              :                 }
    2509           10 :             } else if (key == "parking.memory.blockedAtTimeLocal") {
    2510           30 :                 for (const auto& item : *getParkingMemory()) {
    2511           50 :                     values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
    2512              :                 }
    2513              :             } else {
    2514           10 :                 error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
    2515              :             }
    2516              :         }
    2517           65 :         return toString(values);
    2518           65 :     } else {
    2519              :         // default: custom user parameter
    2520        36686 :         return getParameter().getParameter(key, "");
    2521              :     }
    2522              : }
    2523              : 
    2524              : 
    2525              : void
    2526        30505 : MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
    2527        30505 :     if (myParkingMemory == nullptr) {
    2528            0 :         myParkingMemory = new StoppingPlaceMemory();
    2529              :     }
    2530        30505 :     myParkingMemory->rememberBlockedStoppingPlace(pa, local);
    2531        30505 : }
    2532              : 
    2533              : 
    2534              : void
    2535        12115 : MSBaseVehicle::resetParkingAreaScores() {
    2536        12115 :     if (myParkingMemory != nullptr) {
    2537        10591 :         myParkingMemory->resetStoppingPlaceScores();
    2538              :     }
    2539        12115 : }
    2540              : 
    2541              : 
    2542              : void
    2543          212 : MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
    2544          212 :     if (myChargingMemory == nullptr) {
    2545           44 :         myChargingMemory = new StoppingPlaceMemory();
    2546              :     }
    2547          212 :     myChargingMemory->rememberStoppingPlaceScore(cs, score);
    2548          212 : }
    2549              : 
    2550              : 
    2551              : void
    2552           80 : MSBaseVehicle::resetChargingStationScores() {
    2553           80 :     if (myChargingMemory != nullptr) {
    2554            4 :         myChargingMemory->resetStoppingPlaceScores();
    2555              :     }
    2556           80 : }
    2557              : 
    2558              : 
    2559              : void
    2560        54047 : MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
    2561        54047 :     if (myParkingMemory == nullptr) {
    2562         2024 :         myParkingMemory = new StoppingPlaceMemory();
    2563              :     }
    2564        54047 :     myParkingMemory->rememberStoppingPlaceScore(pa, score);
    2565        54047 : }
    2566              : 
    2567              : 
    2568              : SUMOTime
    2569        37537 : MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
    2570        37537 :     if (myParkingMemory == nullptr) {
    2571              :         return -1;
    2572              :     }
    2573        37537 :     return myParkingMemory->sawBlockedStoppingPlace(pa, local);
    2574              : }
    2575              : 
    2576              : 
    2577            0 : void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
    2578            0 :     if (myChargingMemory == nullptr) {
    2579            0 :         myChargingMemory = new StoppingPlaceMemory();
    2580              :     }
    2581            0 :     myChargingMemory->rememberBlockedStoppingPlace(cs, local);
    2582            0 : }
    2583              : 
    2584              : 
    2585              : SUMOTime
    2586          276 : MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
    2587          276 :     if (myChargingMemory == nullptr) {
    2588              :         return -1;
    2589              :     }
    2590           16 :     return myChargingMemory->sawBlockedStoppingPlace(cs, local);
    2591              : }
    2592              : 
    2593              : 
    2594              : #ifdef _DEBUG
    2595              : void
    2596              : MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
    2597              :     if (oc.isSet("movereminder-output.vehicles")) {
    2598              :         const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
    2599              :         myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
    2600              :     }
    2601              : }
    2602              : 
    2603              : 
    2604              : void
    2605              : MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
    2606              :     OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
    2607              :     od.openTag("movereminder");
    2608              :     od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
    2609              :     od.writeAttr("veh", getID());
    2610              :     od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
    2611              :     od.writeAttr("type", type);
    2612              :     od.writeAttr("pos", toString(pos));
    2613              :     od.writeAttr("keep", toString(keep));
    2614              :     od.closeTag();
    2615              : }
    2616              : #endif
    2617              : 
    2618              : 
    2619              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1