LCOV - code coverage report
Current view: top level - src/microsim - MSBaseVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.6 % 1357 1216
Test Date: 2025-12-06 15:35:27 Functions: 89.3 % 121 108

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

Generated by: LCOV version 2.0-1