LCOV - code coverage report
Current view: top level - src/libsumo - Vehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.6 % 1699 1523
Test Date: 2026-03-02 16:00:03 Functions: 99.5 % 188 187

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    Vehicle.cpp
      15              : /// @author  Jakob Erdmann
      16              : /// @author  Mirko Barthauer
      17              : /// @date    15.03.2017
      18              : ///
      19              : // C++ Vehicle API
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <foreign/tcpip/storage.h>
      24              : #include <utils/geom/GeomHelper.h>
      25              : #include <utils/common/MsgHandler.h>
      26              : #include <utils/common/StringTokenizer.h>
      27              : #include <utils/common/StringUtils.h>
      28              : #include <utils/gui/globjects/GUIGlObjectTypes.h>
      29              : #include <utils/emissions/PollutantsInterface.h>
      30              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      31              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      32              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      33              : #include <microsim/devices/MSDevice.h>
      34              : #include <microsim/MSEdgeWeightsStorage.h>
      35              : #include <microsim/MSStop.h>
      36              : #include <microsim/MSVehicle.h>
      37              : #include <microsim/MSVehicleControl.h>
      38              : #include <microsim/MSVehicleTransfer.h>
      39              : #include <microsim/MSVehicleType.h>
      40              : #include <microsim/MSInsertionControl.h>
      41              : #include <microsim/MSNet.h>
      42              : #include <microsim/MSEdge.h>
      43              : #include <microsim/MSLane.h>
      44              : #include <microsim/MSParkingArea.h>
      45              : #include <microsim/MSJunctionLogic.h>
      46              : #include <microsim/devices/MSDevice_Taxi.h>
      47              : #include <microsim/devices/MSDispatch_TraCI.h>
      48              : #include <mesosim/MEVehicle.h>
      49              : #include <libsumo/StorageHelper.h>
      50              : #include <libsumo/TraCIDefs.h>
      51              : #include <libsumo/TraCIConstants.h>
      52              : #include "Helper.h"
      53              : #include "Route.h"
      54              : #include "Polygon.h"
      55              : #include "Vehicle.h"
      56              : 
      57              : #define CALL_MICRO_FUN(veh, fun, mesoResult) ((dynamic_cast<MSVehicle*>(veh) == nullptr ? (mesoResult) : dynamic_cast<MSVehicle*>(veh)->fun))
      58              : #define CALL_MESO_FUN(veh, fun, microResult) ((dynamic_cast<MEVehicle*>(veh) == nullptr ? (microResult) : dynamic_cast<MEVehicle*>(veh)->fun))
      59              : 
      60              : // ===========================================================================
      61              : // debug defines
      62              : // ===========================================================================
      63              : //#define DEBUG_NEIGHBORS
      64              : //#define DEBUG_DYNAMIC_SHAPES
      65              : //#define DEBUG_MOVEXY
      66              : #define DEBUG_COND (veh->isSelected())
      67              : 
      68              : 
      69              : 
      70              : namespace libsumo {
      71              : // ===========================================================================
      72              : // static member initializations
      73              : // ===========================================================================
      74              : SubscriptionResults Vehicle::mySubscriptionResults;
      75              : ContextSubscriptionResults Vehicle::myContextSubscriptionResults;
      76              : 
      77              : 
      78              : // ===========================================================================
      79              : // static member definitions
      80              : // ===========================================================================
      81              : bool
      82      7629058 : Vehicle::isVisible(const SUMOVehicle* veh) {
      83      7629058 :     return veh->isOnRoad() || veh->isParking() || veh->wasRemoteControlled();
      84              : }
      85              : 
      86              : 
      87              : bool
      88        21487 : Vehicle::isOnInit(const std::string& vehID) {
      89        21487 :     SUMOVehicle* sumoVehicle = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
      90        21487 :     return sumoVehicle == nullptr || sumoVehicle->getLane() == nullptr;
      91              : }
      92              : 
      93              : 
      94              : std::vector<std::string>
      95       157670 : Vehicle::getIDList() {
      96            0 :     std::vector<std::string> ids;
      97       157670 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
      98      1712236 :     for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
      99      1554568 :         if (isVisible((*i).second)) {
     100      1534576 :             ids.push_back((*i).first);
     101              :         }
     102              :     }
     103       157668 :     return ids;
     104            2 : }
     105              : 
     106              : int
     107          146 : Vehicle::getIDCount() {
     108          146 :     return (int)getIDList().size();
     109              : }
     110              : 
     111              : 
     112              : double
     113       176112 : Vehicle::getSpeed(const std::string& vehID) {
     114       176112 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     115       176067 :     return isVisible(veh) ? veh->getSpeed() : INVALID_DOUBLE_VALUE;
     116              : }
     117              : 
     118              : double
     119           90 : Vehicle::getLateralSpeed(const std::string& vehID) {
     120           90 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     121           90 :     return isVisible(veh) ? CALL_MICRO_FUN(veh, getLaneChangeModel().getSpeedLat(), 0) : INVALID_DOUBLE_VALUE;
     122              : }
     123              : 
     124              : 
     125              : double
     126         4986 : Vehicle::getAcceleration(const std::string& vehID) {
     127         4986 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     128         4986 :     return isVisible(veh) ? CALL_MICRO_FUN(veh, getAcceleration(), 0) : INVALID_DOUBLE_VALUE;
     129              : }
     130              : 
     131              : 
     132              : double
     133         4139 : Vehicle::getSpeedWithoutTraCI(const std::string& vehID) {
     134         4139 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     135         4139 :     return isVisible(veh) ? CALL_MICRO_FUN(veh, getSpeedWithoutTraciInfluence(), veh->getSpeed()) : INVALID_DOUBLE_VALUE;
     136              : }
     137              : 
     138              : 
     139              : TraCIPosition
     140      1671546 : Vehicle::getPosition(const std::string& vehID, const bool includeZ) {
     141      1671546 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     142      1671541 :     if (isVisible(veh)) {
     143      1671372 :         return Helper::makeTraCIPosition(veh->getPosition(), includeZ);
     144              :     }
     145              :     return TraCIPosition();
     146              : }
     147              : 
     148              : 
     149              : TraCIPosition
     150          798 : Vehicle::getPosition3D(const std::string& vehID) {
     151          798 :     return getPosition(vehID, true);
     152              : }
     153              : 
     154              : 
     155              : double
     156          471 : Vehicle::getAngle(const std::string& vehID) {
     157          471 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     158          471 :     return isVisible(veh) ? GeomHelper::naviDegree(veh->getAngle()) : INVALID_DOUBLE_VALUE;
     159              : }
     160              : 
     161              : 
     162              : double
     163           18 : Vehicle::getSlope(const std::string& vehID) {
     164           18 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     165           18 :     return (veh->isOnRoad() || veh->isParking()) ? veh->getSlope() : INVALID_DOUBLE_VALUE;
     166              : }
     167              : 
     168              : 
     169              : std::string
     170      4215458 : Vehicle::getRoadID(const std::string& vehID) {
     171      4215458 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     172      4215458 :     return isVisible(veh) ? CALL_MICRO_FUN(veh, getLane()->getEdge().getID(), veh->getEdge()->getID()) : "";
     173              : }
     174              : 
     175              : 
     176              : std::string
     177        38164 : Vehicle::getLaneID(const std::string& vehID) {
     178        38164 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     179        38152 :     return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLane()->getID(), "") : "";
     180              : }
     181              : 
     182              : 
     183              : int
     184        32627 : Vehicle::getLaneIndex(const std::string& vehID) {
     185        32627 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     186        32622 :     if (veh->isOnRoad()) {
     187        32563 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
     188        32563 :         if (microVeh != nullptr) {
     189        32542 :             return microVeh->getLane()->getIndex();
     190              :         } else {
     191           21 :             MEVehicle* mesoVeh = dynamic_cast<MEVehicle*>(veh);
     192           21 :             return mesoVeh->getQueIndex();
     193              :         }
     194              :     } else {
     195              :         return INVALID_INT_VALUE;
     196              :     }
     197              : }
     198              : 
     199              : std::string
     200           98 : Vehicle::getSegmentID(const std::string& vehID) {
     201           98 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     202           94 :     return veh->isOnRoad() ? CALL_MESO_FUN(veh, getSegment()->getID(), "") : "";
     203              : }
     204              : 
     205              : int
     206           94 : Vehicle::getSegmentIndex(const std::string& vehID) {
     207           94 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     208           94 :     return veh->isOnRoad() ? CALL_MESO_FUN(veh, getSegment()->getIndex(), INVALID_INT_VALUE) : INVALID_INT_VALUE;
     209              : }
     210              : 
     211              : std::string
     212         2717 : Vehicle::getTypeID(const std::string& vehID) {
     213         2717 :     return Helper::getVehicleType(vehID).getID();
     214              : }
     215              : 
     216              : 
     217              : std::string
     218          135 : Vehicle::getRouteID(const std::string& vehID) {
     219          135 :     return Helper::getVehicle(vehID)->getRoute().getID();
     220              : }
     221              : 
     222              : 
     223              : double
     224           89 : Vehicle::getDeparture(const std::string& vehID) {
     225           89 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     226           89 :     return veh->hasDeparted() ? STEPS2TIME(veh->getDeparture()) : INVALID_DOUBLE_VALUE;
     227              : }
     228              : 
     229              : 
     230              : double
     231           89 : Vehicle::getDepartDelay(const std::string& vehID) {
     232           89 :     return STEPS2TIME(Helper::getVehicle(vehID)->getDepartDelay());
     233              : }
     234              : 
     235              : 
     236              : int
     237         3347 : Vehicle::getRouteIndex(const std::string& vehID) {
     238         3347 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     239         3347 :     return veh->hasDeparted() ? veh->getRoutePosition() : INVALID_INT_VALUE;
     240              : }
     241              : 
     242              : 
     243              : TraCIColor
     244          683 : Vehicle::getColor(const std::string& vehID) {
     245          683 :     return Helper::makeTraCIColor(Helper::getVehicle(vehID)->getParameter().color);
     246              : }
     247              : 
     248              : double
     249      4199369 : Vehicle::getLanePosition(const std::string& vehID) {
     250      4199369 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     251      4199364 :     return (veh->isOnRoad() || veh->isParking()) ? veh->getPositionOnLane() : INVALID_DOUBLE_VALUE;
     252              : }
     253              : 
     254              : double
     255         3571 : Vehicle::getLateralLanePosition(const std::string& vehID) {
     256         3571 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     257         3571 :     return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLateralPositionOnLane(), 0) : INVALID_DOUBLE_VALUE;
     258              : }
     259              : 
     260              : double
     261          451 : Vehicle::getCO2Emission(const std::string& vehID) {
     262          451 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     263          451 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::CO2>() : INVALID_DOUBLE_VALUE;
     264              : }
     265              : 
     266              : double
     267           91 : Vehicle::getCOEmission(const std::string& vehID) {
     268           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     269           91 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::CO>() : INVALID_DOUBLE_VALUE;
     270              : }
     271              : 
     272              : double
     273           91 : Vehicle::getHCEmission(const std::string& vehID) {
     274           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     275           91 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::HC>() : INVALID_DOUBLE_VALUE;
     276              : }
     277              : 
     278              : double
     279           91 : Vehicle::getPMxEmission(const std::string& vehID) {
     280           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     281           91 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::PM_X>() : INVALID_DOUBLE_VALUE;
     282              : }
     283              : 
     284              : double
     285           91 : Vehicle::getNOxEmission(const std::string& vehID) {
     286           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     287           91 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::NO_X>() : INVALID_DOUBLE_VALUE;
     288              : }
     289              : 
     290              : double
     291          371 : Vehicle::getFuelConsumption(const std::string& vehID) {
     292          371 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     293          371 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::FUEL>() : INVALID_DOUBLE_VALUE;
     294              : }
     295              : 
     296              : double
     297           91 : Vehicle::getNoiseEmission(const std::string& vehID) {
     298           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     299           91 :     return isVisible(veh) ? veh->getHarmonoise_NoiseEmissions() : INVALID_DOUBLE_VALUE;
     300              : }
     301              : 
     302              : double
     303          179 : Vehicle::getElectricityConsumption(const std::string& vehID) {
     304          179 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     305          179 :     return isVisible(veh) ? veh->getEmissions<PollutantsInterface::ELEC>() : INVALID_DOUBLE_VALUE;
     306              : }
     307              : 
     308              : int
     309          314 : Vehicle::getPersonNumber(const std::string& vehID) {
     310          314 :     return Helper::getVehicle(vehID)->getPersonNumber();
     311              : }
     312              : 
     313              : int
     314          327 : Vehicle::getPersonCapacity(const std::string& vehID) {
     315          327 :     return Helper::getVehicleType(vehID).getPersonCapacity();
     316              : }
     317              : 
     318              : 
     319              : double
     320           89 : Vehicle::getBoardingDuration(const std::string& vehID) {
     321           89 :     return STEPS2TIME(Helper::getVehicleType(vehID).getLoadingDuration(true));
     322              : }
     323              : 
     324              : 
     325              : std::vector<std::string>
     326          172 : Vehicle::getPersonIDList(const std::string& vehID) {
     327          172 :     return Helper::getVehicle(vehID)->getPersonIDList();
     328              : }
     329              : 
     330              : std::pair<std::string, double>
     331        39381 : Vehicle::getLeader(const std::string& vehID, double dist) {
     332        39381 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     333        39381 :     if (veh->isOnRoad()) {
     334        39305 :         std::pair<const MSVehicle* const, double> leaderInfo = veh->getLeader(dist, false);
     335        39305 :         const std::string leaderID = leaderInfo.first != nullptr ? leaderInfo.first->getID() : "";
     336        39305 :         double gap = leaderInfo.second;
     337              :         if (leaderInfo.first != nullptr
     338        31175 :                 && leaderInfo.first->getLane() != nullptr
     339        31175 :                 && leaderInfo.first->getLane()->isInternal()
     340          120 :                 && veh->getLane() != nullptr
     341        39425 :                 && (!veh->getLane()->isInternal()
     342            0 :                     || (veh->getLane()->getLinkCont().front()->getIndex() != leaderInfo.first->getLane()->getLinkCont().front()->getIndex()))) {
     343              :             // leader is a linkLeader (see MSLink::getLeaderInfo)
     344              :             // avoid internal gap values which may be negative (or -inf)
     345              :             gap = MAX2(0.0, gap);
     346              :         }
     347              :         return std::make_pair(leaderID, gap);
     348              :     } else {
     349              :         return std::make_pair("", -1);
     350              :     }
     351              : }
     352              : 
     353              : 
     354              : std::pair<std::string, double>
     355          243 : Vehicle::getFollower(const std::string& vehID, double dist) {
     356          243 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     357          239 :     if (veh->isOnRoad()) {
     358          231 :         std::pair<const MSVehicle* const, double> leaderInfo = veh->getFollower(dist);
     359              :         return std::make_pair(
     360          462 :                    leaderInfo.first != nullptr ? leaderInfo.first->getID() : "",
     361              :                    leaderInfo.second);
     362              :     } else {
     363              :         return std::make_pair("", -1);
     364              :     }
     365              : }
     366              : 
     367              : 
     368              : std::vector<TraCIJunctionFoe>
     369          158 : Vehicle::getJunctionFoes(const std::string& vehID, double dist) {
     370            0 :     std::vector<TraCIJunctionFoe> result;
     371          158 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     372          158 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     373          158 :     if (veh == nullptr) {
     374           60 :         WRITE_WARNING("getJunctionFoes not applicable for meso");
     375          128 :     } else if (veh->isOnRoad()) {
     376          128 :         if (dist == 0) {
     377           16 :             dist = veh->getCarFollowModel().brakeGap(veh->getSpeed()) + veh->getVehicleType().getMinGap();
     378              :         }
     379            0 :         const std::vector<const MSLane*> internalLanes;
     380              :         // distance to the end of the lane
     381          128 :         double curDist = -veh->getPositionOnLane();
     382          380 :         for (const MSLane* lane : veh->getUpcomingLanesUntil(dist)) {
     383          252 :             curDist += lane->getLength();
     384          252 :             if (lane->isInternal()) {
     385          116 :                 const MSLink* exitLink = lane->getLinkCont().front();
     386              :                 int foeIndex = 0;
     387              :                 const std::vector<MSLink::ConflictInfo>& conflicts = exitLink->getConflicts();
     388          116 :                 const MSJunctionLogic* logic = exitLink->getJunction()->getLogic();
     389          348 :                 for (const MSLane* foeLane : exitLink->getFoeLanes()) {
     390          232 :                     const MSLink::ConflictInfo& ci = conflicts[foeIndex];
     391          232 :                     if (ci.flag == MSLink::CONFLICT_NO_INTERSECTION) {
     392          112 :                         continue;
     393              :                     }
     394          120 :                     const double distBehindCrossing = ci.lengthBehindCrossing;
     395          120 :                     const MSLink* foeExitLink = foeLane->getLinkCont().front();
     396          120 :                     const double distToCrossing = curDist - distBehindCrossing;
     397          120 :                     const double foeDistBehindCrossing = ci.getFoeLengthBehindCrossing(foeExitLink);
     398          300 :                     for (auto item : foeExitLink->getApproaching()) {
     399              :                         const SUMOVehicle* foe = item.first;
     400              :                         TraCIJunctionFoe jf;
     401              :                         jf.foeId = foe->getID();
     402          180 :                         jf.egoDist = distToCrossing;
     403              :                         // approach information is from the start of the previous step
     404              :                         // but the foe vehicle then moved within that steop
     405          180 :                         const double prevFoeDist = SPEED2DIST(MSGlobals::gSemiImplicitEulerUpdate
     406              :                                                               ? foe->getSpeed()
     407              :                                                               : (foe->getSpeed() + foe->getPreviousSpeed()) / 2);
     408          180 :                         jf.foeDist = item.second.dist - foeDistBehindCrossing - prevFoeDist;
     409          180 :                         jf.egoExitDist = jf.egoDist + ci.conflictSize;
     410          180 :                         jf.foeExitDist = jf.foeDist + ci.getFoeConflictSize(foeExitLink);
     411              :                         jf.egoLane = lane->getID();
     412              :                         jf.foeLane = foeLane->getID();
     413          180 :                         jf.egoResponse = logic->getResponseFor(exitLink->getIndex()).test(foeExitLink->getIndex());
     414          180 :                         jf.foeResponse = logic->getResponseFor(foeExitLink->getIndex()).test(exitLink->getIndex());
     415          180 :                         result.push_back(jf);
     416          180 :                     }
     417          120 :                     foeIndex++;
     418              :                 }
     419              :             }
     420          128 :         }
     421          128 :     }
     422          158 :     return result;
     423            0 : }
     424              : 
     425              : 
     426              : double
     427          247 : Vehicle::getWaitingTime(const std::string& vehID) {
     428          247 :     return STEPS2TIME(Helper::getVehicle(vehID)->getWaitingTime());
     429              : }
     430              : 
     431              : 
     432              : double
     433          125 : Vehicle::getAccumulatedWaitingTime(const std::string& vehID) {
     434          125 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     435          125 :     return CALL_MICRO_FUN(veh, getAccumulatedWaitingSeconds(), INVALID_DOUBLE_VALUE);
     436              : }
     437              : 
     438              : 
     439              : double
     440          119 : Vehicle::getAdaptedTraveltime(const std::string& vehID, double time, const std::string& edgeID) {
     441          119 :     MSEdge* edge = Helper::getEdge(edgeID);
     442          119 :     double value = INVALID_DOUBLE_VALUE;
     443          119 :     Helper::getVehicle(vehID)->getWeightsStorage().retrieveExistingTravelTime(edge, time, value);
     444          119 :     return value;
     445              : }
     446              : 
     447              : 
     448              : double
     449          115 : Vehicle::getEffort(const std::string& vehID, double time, const std::string& edgeID) {
     450          115 :     MSEdge* edge = Helper::getEdge(edgeID);
     451          115 :     double value = INVALID_DOUBLE_VALUE;
     452          115 :     Helper::getVehicle(vehID)->getWeightsStorage().retrieveExistingEffort(edge, time, value);
     453          115 :     return value;
     454              : }
     455              : 
     456              : 
     457              : bool
     458           90 : Vehicle::isRouteValid(const std::string& vehID) {
     459              :     std::string msg;
     460          180 :     return Helper::getVehicle(vehID)->hasValidRoute(msg);
     461              : }
     462              : 
     463              : 
     464              : std::vector<std::string>
     465         3605 : Vehicle::getRoute(const std::string& vehID) {
     466            0 :     std::vector<std::string> result;
     467         3605 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     468         3605 :     const MSRoute& r = veh->getRoute();
     469        11903 :     for (MSRouteIterator i = r.begin(); i != r.end(); ++i) {
     470         8298 :         result.push_back((*i)->getID());
     471              :     }
     472         3605 :     return result;
     473            0 : }
     474              : 
     475              : 
     476              : int
     477           92 : Vehicle::getSignals(const std::string& vehID) {
     478           92 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     479           92 :     return CALL_MICRO_FUN(veh, getSignals(), MSVehicle::VEH_SIGNAL_NONE);
     480              : }
     481              : 
     482              : 
     483              : std::vector<TraCIBestLanesData>
     484           94 : Vehicle::getBestLanes(const std::string& vehID) {
     485            0 :     std::vector<TraCIBestLanesData> result;
     486           94 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(Helper::getVehicle(vehID));
     487           94 :     if (veh != nullptr && veh->isOnRoad()) {
     488          130 :         for (const MSVehicle::LaneQ& lq : veh->getBestLanes()) {
     489              :             TraCIBestLanesData bld;
     490           85 :             bld.laneID = lq.lane->getID();
     491           85 :             bld.length = lq.length;
     492           85 :             bld.occupation = lq.nextOccupation;
     493           85 :             bld.bestLaneOffset = lq.bestLaneOffset;
     494           85 :             bld.allowsContinuation = lq.allowsContinuation;
     495          318 :             for (const MSLane* const lane : lq.bestContinuations) {
     496          233 :                 if (lane != nullptr) {
     497          233 :                     bld.continuationLanes.push_back(lane->getID());
     498              :                 }
     499              :             }
     500           85 :             result.emplace_back(bld);
     501              :         }
     502              :     }
     503           94 :     return result;
     504            0 : }
     505              : 
     506              : 
     507              : std::vector<TraCINextTLSData>
     508         1346 : Vehicle::getNextTLS(const std::string& vehID) {
     509            0 :     std::vector<TraCINextTLSData> result;
     510         1346 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     511         1331 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     512         1331 :     if (veh != nullptr) {
     513              :         int view = 1;
     514         1094 :         double seen = veh->getEdge()->getLength() - veh->getPositionOnLane();
     515         1094 :         if (vehicle->isOnRoad()) {
     516         1055 :             const MSLane* lane = veh->getLane();
     517         1055 :             const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation(lane);
     518         1055 :             seen = lane->getLength() - veh->getPositionOnLane();
     519         1055 :             std::vector<MSLink*>::const_iterator linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
     520         2964 :             while (!lane->isLinkEnd(linkIt)) {
     521         1909 :                 if (!lane->getEdge().isInternal()) {
     522          915 :                     if ((*linkIt)->isTLSControlled()) {
     523              :                         TraCINextTLSData ntd;
     524          670 :                         ntd.id = (*linkIt)->getTLLogic()->getID();
     525          670 :                         ntd.tlIndex = (*linkIt)->getTLIndex();
     526          670 :                         ntd.dist = seen;
     527          670 :                         ntd.state = (char)(*linkIt)->getState();
     528          670 :                         result.push_back(ntd);
     529              :                     }
     530              :                 }
     531         1909 :                 lane = (*linkIt)->getViaLaneOrLane();
     532         1909 :                 if (!lane->getEdge().isInternal()) {
     533          966 :                     view++;
     534              :                 }
     535         1909 :                 seen += lane->getLength();
     536         1909 :                 linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
     537              :             }
     538              :         }
     539              :         // consider edges beyond bestLanes
     540         1094 :         const int remainingEdges = (int)(veh->getRoute().end() - veh->getCurrentRouteEdge()) - view;
     541              :         //std::cout << SIMTIME << " remainingEdges=" << remainingEdges << " seen=" << seen << " view=" << view << " best=" << toString(bestLaneConts) << "\n";
     542         2238 :         for (int i = 0; i < remainingEdges; i++) {
     543         1144 :             const MSEdge* prev = *(veh->getCurrentRouteEdge() + view + i - 1);
     544         1144 :             const MSEdge* next = *(veh->getCurrentRouteEdge() + view + i);
     545         1144 :             const std::vector<MSLane*>* allowed = prev->allowedLanes(*next, veh->getVClass());
     546         1144 :             if (allowed != nullptr && allowed->size() != 0) {
     547         1258 :                 for (const MSLink* const link : allowed->front()->getLinkCont()) {
     548         1258 :                     if (&link->getLane()->getEdge() == next) {
     549         1144 :                         if (link->isTLSControlled()) {
     550              :                             TraCINextTLSData ntd;
     551              :                             ntd.id = link->getTLLogic()->getID();
     552          735 :                             ntd.tlIndex = link->getTLIndex();
     553          735 :                             ntd.dist = seen;
     554          735 :                             ntd.state = (char)link->getState();
     555          735 :                             result.push_back(ntd);
     556              :                         }
     557         1144 :                         seen += next->getLength() + link->getInternalLengthsAfter();
     558         1144 :                         break;
     559              :                     }
     560              :                 }
     561              :             } else {
     562              :                 // invalid route, cannot determine nextTLS
     563              :                 break;
     564              :             }
     565              :         }
     566              : 
     567              :     } else {
     568          474 :         WRITE_WARNING("getNextTLS not yet implemented for meso");
     569              :     }
     570         1331 :     return result;
     571           15 : }
     572              : 
     573              : std::vector<TraCINextStopData>
     574           93 : Vehicle::getNextStops(const std::string& vehID) {
     575           93 :     return getStops(vehID, 0);
     576              : }
     577              : 
     578              : std::vector<libsumo::TraCIConnection>
     579           36 : Vehicle::getNextLinks(const std::string& vehID) {
     580            0 :     std::vector<libsumo::TraCIConnection> result;
     581           36 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     582           36 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     583           36 :     if (!vehicle->isOnRoad()) {
     584              :         return result;
     585              :     }
     586           36 :     if (veh != nullptr) {
     587           36 :         const MSLane* lane = veh->getLane();
     588           36 :         const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation(lane);
     589              :         int view = 1;
     590           36 :         const SUMOTime currTime = MSNet::getInstance()->getCurrentTimeStep();
     591           36 :         std::vector<MSLink*>::const_iterator linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
     592          100 :         while (!lane->isLinkEnd(linkIt)) {
     593           64 :             if (!lane->getEdge().isInternal()) {
     594           56 :                 const MSLink* link = (*linkIt);
     595          112 :                 const std::string approachedLane = link->getLane() != nullptr ? link->getLane()->getID() : "";
     596              :                 const bool hasPrio = link->havePriority();
     597              :                 const double speed = MIN2(lane->getSpeedLimit(), link->getLane()->getSpeedLimit());
     598           56 :                 const bool isOpen = link->opened(currTime, speed, speed, veh->getLength(),
     599           56 :                                                  veh->getImpatience(), veh->getVehicleType().getCarFollowModel().getMaxDecel(),
     600           56 :                                                  veh->getWaitingTime(), veh->getLateralPositionOnLane(), nullptr, false, veh);
     601           56 :                 const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
     602           64 :                 const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
     603           56 :                 const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
     604           56 :                 const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
     605              :                 const double length = link->getLength();
     606          168 :                 result.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
     607              :             }
     608           64 :             lane = (*linkIt)->getViaLaneOrLane();
     609           64 :             if (!lane->getEdge().isInternal()) {
     610           56 :                 view++;
     611              :             }
     612           64 :             linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
     613              :         }
     614              :         // consider edges beyond bestLanes
     615           36 :         const int remainingEdges = (int)(veh->getRoute().end() - veh->getCurrentRouteEdge()) - view;
     616           36 :         for (int i = 0; i < remainingEdges; i++) {
     617            0 :             const MSEdge* prev = *(veh->getCurrentRouteEdge() + view + i - 1);
     618            0 :             const MSEdge* next = *(veh->getCurrentRouteEdge() + view + i);
     619            0 :             const std::vector<MSLane*>* allowed = prev->allowedLanes(*next, veh->getVClass());
     620            0 :             if (allowed != nullptr && allowed->size() != 0) {
     621            0 :                 for (const MSLink* const link : allowed->front()->getLinkCont()) {
     622            0 :                     if (&link->getLane()->getEdge() == next) {
     623              :                         const std::string approachedLane = link->getLane() != nullptr ? link->getLane()->getID() : "";
     624              :                         const bool hasPrio = link->havePriority();
     625              :                         const double speed = MIN2(lane->getSpeedLimit(), link->getLane()->getSpeedLimit());
     626            0 :                         const bool isOpen = link->opened(currTime, speed, speed, veh->getLength(),
     627            0 :                                                          veh->getImpatience(), veh->getVehicleType().getCarFollowModel().getMaxDecel(),
     628            0 :                                                          veh->getWaitingTime(), veh->getLateralPositionOnLane(), nullptr, false, veh);
     629            0 :                         const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
     630            0 :                         const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
     631            0 :                         const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
     632            0 :                         const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
     633              :                         const double length = link->getLength();
     634            0 :                         result.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
     635              :                     }
     636              :                 }
     637              :             } else {
     638              :                 // invalid route, cannot determine nextTLS
     639              :                 break;
     640              :             }
     641              :         }
     642              :     } else {
     643            0 :         WRITE_WARNING("getNextLinks not yet implemented for meso");
     644              :     }
     645              :     return result;
     646            0 : }
     647              : 
     648              : std::vector<TraCINextStopData>
     649         3581 : Vehicle::getStops(const std::string& vehID, int limit) {
     650            0 :     std::vector<TraCINextStopData> result;
     651         3581 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     652         3576 :     if (limit < 0) {
     653              :         // return past stops up to the given limit
     654              :         const StopParVector& pastStops = vehicle->getPastStops();
     655          420 :         const int n = (int)pastStops.size();
     656         1209 :         for (int i = MAX2(0, n + limit); i < n; i++) {
     657         1578 :             result.push_back(Helper::buildStopData(pastStops[i]));
     658              :         }
     659              :     } else {
     660        10233 :         for (const MSStop& stop : vehicle->getStops()) {
     661         7525 :             if (!stop.pars.collision) {
     662         7525 :                 TraCINextStopData nsd = Helper::buildStopData(stop.pars);
     663         7525 :                 nsd.duration = STEPS2TIME(stop.duration);
     664         7525 :                 result.push_back(nsd);
     665         7525 :                 if (limit > 0 && (int)result.size() >= limit) {
     666              :                     break;
     667              :                 }
     668         7525 :             }
     669              :         }
     670              :     }
     671         3576 :     return result;
     672            5 : }
     673              : 
     674              : 
     675              : int
     676         1801 : Vehicle::getStopState(const std::string& vehID) {
     677         1801 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     678         1801 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     679         1801 :     if (veh == nullptr) {
     680          411 :         WRITE_WARNING("getStopState not yet implemented for meso");
     681          411 :         return 0;
     682              :     }
     683              :     int result = 0;
     684         1390 :     if (veh->isStopped()) {
     685          258 :         const MSStop& stop = veh->getNextStop();
     686          258 :         result = stop.getStateFlagsOld();
     687              :     }
     688              :     return result;
     689              : }
     690              : 
     691              : 
     692              : double
     693          637 : Vehicle::getDistance(const std::string& vehID) {
     694          637 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     695          632 :     if (veh->hasDeparted()) {
     696          587 :         return veh->getOdometer();
     697              :     } else {
     698              :         return INVALID_DOUBLE_VALUE;
     699              :     }
     700              : }
     701              : 
     702              : 
     703              : double
     704         3115 : Vehicle::getDrivingDistance(const std::string& vehID, const std::string& edgeID, double pos, int laneIndex) {
     705         3115 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     706         3115 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
     707         3115 :     if (veh->isOnRoad()) {
     708         3070 :         const MSLane* lane = microVeh != nullptr ? veh->getLane() : veh->getEdge()->getLanes()[0];
     709         6140 :         double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), pos,
     710         3070 :                           lane, Helper::getLaneChecking(edgeID, laneIndex, pos), veh->getRoutePosition());
     711         3070 :         if (distance == std::numeric_limits<double>::max()) {
     712              :             return INVALID_DOUBLE_VALUE;
     713              :         }
     714              :         return distance;
     715              :     } else {
     716              :         return INVALID_DOUBLE_VALUE;
     717              :     }
     718              : }
     719              : 
     720              : 
     721              : double
     722           91 : Vehicle::getDrivingDistance2D(const std::string& vehID, double x, double y) {
     723           91 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     724           91 :     if (veh == nullptr) {
     725              :         return INVALID_DOUBLE_VALUE;
     726              :     }
     727           91 :     if (veh->isOnRoad()) {
     728           46 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
     729           46 :         const MSLane* lane = microVeh != nullptr ? veh->getLane() : veh->getEdge()->getLanes()[0];
     730           46 :         std::pair<MSLane*, double> roadPos = Helper::convertCartesianToRoadMap(Position(x, y), veh->getVehicleType().getVehicleClass());
     731           92 :         double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), roadPos.second,
     732           46 :                           lane, roadPos.first, veh->getRoutePosition());
     733           46 :         if (distance == std::numeric_limits<double>::max()) {
     734              :             return INVALID_DOUBLE_VALUE;
     735              :         }
     736           36 :         return distance;
     737              :     } else {
     738              :         return INVALID_DOUBLE_VALUE;
     739              :     }
     740              : }
     741              : 
     742              : 
     743              : double
     744           89 : Vehicle::getReferenceDistance(const std::string& vehID) {
     745           89 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     746           89 :     if (veh->hasDeparted()) {
     747           44 :         double lanePos = veh->getPositionOnLane();
     748           44 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
     749           44 :         if (microVeh != nullptr && microVeh->getLane()->isInternal()) {
     750            0 :             lanePos = microVeh->getRoute().getDistanceBetween(0., lanePos, microVeh->getEdge()->getLanes()[0], microVeh->getLane(),
     751            0 :                     microVeh->getRoutePosition());
     752              :         }
     753           44 :         return veh->getEdge()->getDistanceAt(lanePos);
     754              :     } else {
     755              :         return INVALID_DOUBLE_VALUE;
     756              :     }
     757              : }
     758              : 
     759              : 
     760              : double
     761           89 : Vehicle::getAllowedSpeed(const std::string& vehID) {
     762           89 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     763           89 :     return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLane()->getVehicleMaxSpeed(veh), veh->getEdge()->getVehicleMaxSpeed(veh)) : INVALID_DOUBLE_VALUE;
     764              : }
     765              : 
     766              : 
     767              : double
     768          193 : Vehicle::getSpeedFactor(const std::string& vehID) {
     769          193 :     return Helper::getVehicle(vehID)->getChosenSpeedFactor();
     770              : }
     771              : 
     772              : 
     773              : int
     774           76 : Vehicle::getSpeedMode(const std::string& vehID) {
     775           76 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     776           76 :     return CALL_MICRO_FUN(veh, getInfluencer().getSpeedMode(), INVALID_INT_VALUE);
     777              : }
     778              : 
     779              : 
     780              : int
     781          178 : Vehicle::getLaneChangeMode(const std::string& vehID) {
     782          178 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     783          178 :     return CALL_MICRO_FUN(veh, getInfluencer().getLaneChangeMode(), INVALID_INT_VALUE);
     784              : }
     785              : 
     786              : 
     787              : int
     788          187 : Vehicle::getRoutingMode(const std::string& vehID) {
     789          187 :     return Helper::getVehicle(vehID)->getRoutingMode();
     790              : }
     791              : 
     792              : 
     793              : std::string
     794           90 : Vehicle::getLine(const std::string& vehID) {
     795           90 :     return Helper::getVehicle(vehID)->getParameter().line;
     796              : }
     797              : 
     798              : 
     799              : std::vector<std::string>
     800           90 : Vehicle::getVia(const std::string& vehID) {
     801           90 :     return Helper::getVehicle(vehID)->getParameter().via;
     802              : }
     803              : 
     804              : 
     805              : std::pair<int, int>
     806        16371 : Vehicle::getLaneChangeState(const std::string& vehID, int direction) {
     807        16371 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     808        16371 :     auto undefined = std::make_pair((int)LCA_UNKNOWN, (int)LCA_UNKNOWN);
     809        16371 :     return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLaneChangeModel().getSavedState(direction), undefined) : undefined;
     810              : }
     811              : 
     812              : 
     813              : std::string
     814        50001 : Vehicle::getParameter(const std::string& vehID, const std::string& key) {
     815        50001 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     816              :     std::string error;
     817        50001 :     std::string result = veh->getPrefixedParameter(key, error);
     818        50001 :     if (error != "") {
     819          170 :         throw TraCIException(error);
     820              :     }
     821        49916 :     return result;
     822              : }
     823              : 
     824              : 
     825          104 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Vehicle)
     826              : 
     827              : 
     828              : std::vector<std::pair<std::string, double> >
     829         4288 : Vehicle::getNeighbors(const std::string& vehID, const int mode) {
     830         4288 :     int dir = (1 & mode) != 0 ? -1 : 1;
     831         4288 :     bool queryLeaders = (2 & mode) != 0;
     832         4288 :     bool blockersOnly = (4 & mode) != 0;
     833         4288 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     834         4288 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     835            0 :     std::vector<std::pair<std::string, double> > result;
     836         4288 :     if (veh == nullptr) {
     837              :         return result;
     838              :     }
     839              : #ifdef DEBUG_NEIGHBORS
     840              :     if (DEBUG_COND) {
     841              :         std::cout << "getNeighbors() for veh '" << vehID << "': dir=" << dir
     842              :                   << ", queryLeaders=" << queryLeaders
     843              :                   << ", blockersOnly=" << blockersOnly << std::endl;
     844              :     }
     845              : #endif
     846         4288 :     if (veh->getLaneChangeModel().isOpposite()) {
     847              :         // getParallelLane works relative to lane forward direction
     848          120 :         dir *= -1;
     849              :     }
     850              : 
     851         4288 :     MSLane* targetLane = veh->getLane()->getParallelLane(dir);
     852         4288 :     if (targetLane == nullptr) {
     853              :         return result;
     854              :     }
     855              :     // need to recompute leaders and followers (#8119)
     856         3708 :     const bool opposite = &veh->getLane()->getEdge() != &targetLane->getEdge();
     857         3708 :     MSLeaderDistanceInfo neighbors(targetLane->getWidth(), nullptr, 0.);
     858         3708 :     if (queryLeaders) {
     859         1850 :         if (opposite) {
     860          290 :             double pos = targetLane->getOppositePos(veh->getPositionOnLane());
     861          290 :             neighbors = targetLane->getFollowersOnConsecutive(veh, pos, true);
     862              :         } else {
     863         1560 :             targetLane->addLeaders(veh, veh->getPositionOnLane(), neighbors);
     864              :         }
     865              :     } else {
     866         1858 :         if (opposite) {
     867          290 :             double pos = targetLane->getOppositePos(veh->getPositionOnLane());
     868          290 :             targetLane->addLeaders(veh, pos, neighbors);
     869          290 :             neighbors.fixOppositeGaps(true);
     870              :         } else {
     871         1568 :             neighbors = targetLane->getFollowersOnConsecutive(veh, veh->getBackPositionOnLane(), true);
     872              :         }
     873              :     }
     874         3708 :     if (blockersOnly) {
     875              :         // filter out vehicles that aren't blocking
     876         1850 :         MSLeaderDistanceInfo blockers(targetLane->getWidth(), nullptr, 0.);
     877         6040 :         for (int i = 0; i < neighbors.numSublanes(); i++) {
     878         4190 :             CLeaderDist n = neighbors[i];
     879         4190 :             if (n.first != nullptr) {
     880              :                 const MSVehicle* follower = veh;
     881              :                 const MSVehicle* leader = n.first;
     882         2665 :                 if (!queryLeaders) {
     883              :                     std::swap(follower, leader);
     884              :                 }
     885         5330 :                 const double secureGap = (follower->getCarFollowModel().getSecureGap(
     886         2665 :                                               follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
     887         2665 :                                           * follower->getLaneChangeModel().getSafetyFactor());
     888         2665 :                 if (n.second < secureGap) {
     889         1170 :                     blockers.addLeader(n.first, n.second, 0, i);
     890              :                 }
     891              :             }
     892              :         }
     893         1850 :         neighbors = blockers;
     894         1850 :     }
     895              : 
     896         3708 :     if (neighbors.hasVehicles()) {
     897         6575 :         for (int i = 0; i < neighbors.numSublanes(); i++) {
     898         4720 :             CLeaderDist n = neighbors[i];
     899         4720 :             if (n.first != nullptr &&
     900              :                     // avoid duplicates
     901         1995 :                     (result.size() == 0 || result.back().first != n.first->getID())) {
     902         2360 :                 result.push_back(std::make_pair(n.first->getID(), n.second));
     903              :             }
     904              :         }
     905              :     }
     906              :     return result;
     907         3708 : }
     908              : 
     909              : 
     910              : double
     911          542 : Vehicle::getFollowSpeed(const std::string& vehID, double speed, double gap, double leaderSpeed, double leaderMaxDecel, const std::string& leaderID) {
     912          542 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     913          542 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     914          542 :     if (veh == nullptr) {
     915            0 :         WRITE_ERROR("getFollowSpeed not applicable for meso");
     916            0 :         return INVALID_DOUBLE_VALUE;
     917              :     }
     918          542 :     MSVehicle* leader = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(leaderID));
     919          542 :     return veh->getCarFollowModel().followSpeed(veh, speed, gap, leaderSpeed, leaderMaxDecel, leader, MSCFModel::CalcReason::FUTURE);
     920              : }
     921              : 
     922              : 
     923              : double
     924           17 : Vehicle::getSecureGap(const std::string& vehID, double speed, double leaderSpeed, double leaderMaxDecel, const std::string& leaderID) {
     925           17 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     926           17 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     927           17 :     if (veh == nullptr) {
     928            0 :         WRITE_ERROR("getSecureGap not applicable for meso");
     929            0 :         return INVALID_DOUBLE_VALUE;
     930              :     }
     931           17 :     MSVehicle* leader = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(leaderID));
     932           17 :     return veh->getCarFollowModel().getSecureGap(veh, leader, speed, leaderSpeed, leaderMaxDecel);
     933              : }
     934              : 
     935              : 
     936              : double
     937           17 : Vehicle::getStopSpeed(const std::string& vehID, const double speed, double gap) {
     938           17 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
     939           17 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
     940           17 :     if (veh == nullptr) {
     941            0 :         WRITE_ERROR("getStopSpeed not applicable for meso");
     942            0 :         return INVALID_DOUBLE_VALUE;
     943              :     }
     944           17 :     return veh->getCarFollowModel().stopSpeed(veh, speed, gap, MSCFModel::CalcReason::FUTURE);
     945              : }
     946              : 
     947              : double
     948         1866 : Vehicle::getStopDelay(const std::string& vehID) {
     949         1866 :     return Helper::getVehicle(vehID)->getStopDelay();
     950              : }
     951              : 
     952              : 
     953              : double
     954          116 : Vehicle::getImpatience(const std::string& vehID) {
     955          116 :     return Helper::getVehicle(vehID)->getImpatience();
     956              : }
     957              : 
     958              : 
     959              : double
     960         1865 : Vehicle::getStopArrivalDelay(const std::string& vehID) {
     961         1865 :     double result = Helper::getVehicle(vehID)->getStopArrivalDelay();
     962         1865 :     if (result == INVALID_DOUBLE) {
     963              :         return INVALID_DOUBLE_VALUE;
     964              :     } else {
     965         1368 :         return result;
     966              :     }
     967              : }
     968              : 
     969              : double
     970           89 : Vehicle::getTimeLoss(const std::string& vehID) {
     971           89 :     return Helper::getVehicle(vehID)->getTimeLossSeconds();
     972              : }
     973              : 
     974              : std::vector<std::string>
     975        10016 : Vehicle::getTaxiFleet(int taxiState) {
     976            0 :     std::vector<std::string> result;
     977        24486 :     for (MSDevice_Taxi* taxi : MSDevice_Taxi::getFleet()) {
     978        14470 :         if (taxi->getHolder().hasDeparted()) {
     979              :             if (taxiState == -1
     980        10184 :                     || (taxiState == 0 && taxi->getState() == 0)
     981        21374 :                     || (taxiState != 0 && (taxi->getState() & taxiState) == taxiState)) {
     982         6383 :                 result.push_back(taxi->getHolder().getID());
     983              :             }
     984              :         }
     985              :     }
     986        10016 :     return result;
     987            0 : }
     988              : 
     989              : std::vector<std::string>
     990          185 : Vehicle::getLoadedIDList() {
     991            0 :     std::vector<std::string> ids;
     992          185 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
     993          558 :     for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
     994          373 :         ids.push_back(i->first);
     995              :     }
     996          185 :     return ids;
     997            0 : }
     998              : 
     999              : std::vector<std::string>
    1000          140 : Vehicle::getTeleportingIDList() {
    1001            0 :     std::vector<std::string> ids;
    1002          140 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
    1003          486 :     for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
    1004          346 :         SUMOVehicle* veh = i->second;
    1005          346 :         if (veh->hasDeparted() && !isVisible(veh)) {
    1006           60 :             ids.push_back(veh->getID());
    1007              :         }
    1008              :     }
    1009          140 :     return ids;
    1010            0 : }
    1011              : 
    1012              : std::string
    1013           76 : Vehicle::getEmissionClass(const std::string& vehID) {
    1014           76 :     return PollutantsInterface::getName(Helper::getVehicleType(vehID).getEmissionClass());
    1015              : }
    1016              : 
    1017              : std::string
    1018           36 : Vehicle::getShapeClass(const std::string& vehID) {
    1019           36 :     return getVehicleShapeName(Helper::getVehicleType(vehID).getGuiShape());
    1020              : }
    1021              : 
    1022              : 
    1023              : double
    1024           38 : Vehicle::getLength(const std::string& vehID) {
    1025           38 :     return Helper::getVehicleType(vehID).getLength();
    1026              : }
    1027              : 
    1028              : 
    1029              : double
    1030           38 : Vehicle::getAccel(const std::string& vehID) {
    1031           38 :     return Helper::getVehicleType(vehID).getCarFollowModel().getMaxAccel();
    1032              : }
    1033              : 
    1034              : 
    1035              : double
    1036          225 : Vehicle::getDecel(const std::string& vehID) {
    1037          225 :     return Helper::getVehicleType(vehID).getCarFollowModel().getMaxDecel();
    1038              : }
    1039              : 
    1040              : 
    1041           42 : double Vehicle::getEmergencyDecel(const std::string& vehID) {
    1042           42 :     return Helper::getVehicleType(vehID).getCarFollowModel().getEmergencyDecel();
    1043              : }
    1044              : 
    1045              : 
    1046           38 : double Vehicle::getApparentDecel(const std::string& vehID) {
    1047           38 :     return Helper::getVehicleType(vehID).getCarFollowModel().getApparentDecel();
    1048              : }
    1049              : 
    1050              : 
    1051           38 : double Vehicle::getActionStepLength(const std::string& vehID) {
    1052           38 :     return Helper::getVehicleType(vehID).getActionStepLengthSecs();
    1053              : }
    1054              : 
    1055              : 
    1056           89 : double Vehicle::getLastActionTime(const std::string& vehID) {
    1057           89 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    1058           89 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    1059           89 :     if (microVeh != nullptr) {
    1060           80 :         return STEPS2TIME(microVeh->getLastActionTime());
    1061              :     } else {
    1062            9 :         MEVehicle* mesoVeh = dynamic_cast<MEVehicle*>(veh);
    1063            9 :         return STEPS2TIME(mesoVeh->getEventTime());
    1064              :     }
    1065              : }
    1066              : 
    1067              : 
    1068              : double
    1069           38 : Vehicle::getTau(const std::string& vehID) {
    1070           38 :     return Helper::getVehicleType(vehID).getCarFollowModel().getHeadwayTime();
    1071              : }
    1072              : 
    1073              : 
    1074              : double
    1075           40 : Vehicle::getImperfection(const std::string& vehID) {
    1076           40 :     return Helper::getVehicleType(vehID).getCarFollowModel().getImperfection();
    1077              : }
    1078              : 
    1079              : 
    1080              : double
    1081           36 : Vehicle::getSpeedDeviation(const std::string& vehID) {
    1082           36 :     return Helper::getVehicleType(vehID).getSpeedFactor().getParameter(1);
    1083              : }
    1084              : 
    1085              : 
    1086              : std::string
    1087           36 : Vehicle::getVehicleClass(const std::string& vehID) {
    1088           36 :     return toString(Helper::getVehicleType(vehID).getVehicleClass());
    1089              : }
    1090              : 
    1091              : 
    1092              : double
    1093           90 : Vehicle::getMinGap(const std::string& vehID) {
    1094           90 :     return Helper::getVehicleType(vehID).getMinGap();
    1095              : }
    1096              : 
    1097              : 
    1098              : double
    1099           89 : Vehicle::getMinGapLat(const std::string& vehID) {
    1100              :     try {
    1101          125 :         return StringUtils::toDouble(getParameter(vehID, "laneChangeModel.minGapLat"));
    1102           53 :     } catch (const TraCIException&) {
    1103              :         // legacy behavior
    1104           53 :         return Helper::getVehicleType(vehID).getMinGapLat();
    1105           53 :     }
    1106              : }
    1107              : 
    1108              : 
    1109              : double
    1110           38 : Vehicle::getMaxSpeed(const std::string& vehID) {
    1111           38 :     return Helper::getVehicleType(vehID).getMaxSpeed();
    1112              : }
    1113              : 
    1114              : 
    1115              : double
    1116           36 : Vehicle::getMaxSpeedLat(const std::string& vehID) {
    1117           36 :     return Helper::getVehicleType(vehID).getMaxSpeedLat();
    1118              : }
    1119              : 
    1120              : 
    1121              : std::string
    1122           36 : Vehicle::getLateralAlignment(const std::string& vehID) {
    1123           36 :     return toString(Helper::getVehicleType(vehID).getPreferredLateralAlignment());
    1124              : }
    1125              : 
    1126              : 
    1127              : double
    1128           38 : Vehicle::getWidth(const std::string& vehID) {
    1129           38 :     return Helper::getVehicleType(vehID).getWidth();
    1130              : }
    1131              : 
    1132              : 
    1133              : double
    1134           36 : Vehicle::getHeight(const std::string& vehID) {
    1135           36 :     return Helper::getVehicleType(vehID).getHeight();
    1136              : }
    1137              : 
    1138              : 
    1139              : double
    1140           44 : Vehicle::getMass(const std::string& vehID) {
    1141           44 :     return Helper::getVehicleType(vehID).getMass();
    1142              : }
    1143              : 
    1144              : 
    1145              : void
    1146        43704 : Vehicle::setStop(const std::string& vehID,
    1147              :                  const std::string& edgeID,
    1148              :                  double pos,
    1149              :                  int laneIndex,
    1150              :                  double duration,
    1151              :                  int flags,
    1152              :                  double startPos,
    1153              :                  double until) {
    1154        43704 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1155              :     SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
    1156        43700 :                                           pos, laneIndex, startPos, flags, duration, until);
    1157              :     std::string error;
    1158        43719 :     if (!vehicle->addTraciStop(stopPars, error)) {
    1159           38 :         throw TraCIException(error);
    1160              :     }
    1161        43700 : }
    1162              : 
    1163              : 
    1164              : void
    1165          216 : Vehicle::replaceStop(const std::string& vehID,
    1166              :                      int nextStopIndex,
    1167              :                      const std::string& edgeID,
    1168              :                      double pos,
    1169              :                      int laneIndex,
    1170              :                      double duration,
    1171              :                      int flags,
    1172              :                      double startPos,
    1173              :                      double until,
    1174              :                      int teleport) {
    1175          216 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1176              :     std::string error;
    1177          216 :     if (edgeID == "") {
    1178              :         // only remove stop
    1179           88 :         const bool ok = vehicle->abortNextStop(nextStopIndex);
    1180           88 :         if (teleport != 0) {
    1181          121 :             if (!vehicle->rerouteBetweenStops(nextStopIndex, "traci:replaceStop", (teleport & 1), error)) {
    1182            0 :                 throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (" + error + ").");
    1183              :             }
    1184              :         } else {
    1185           36 :             MSVehicle* msVeh = dynamic_cast<MSVehicle*>(vehicle);
    1186           36 :             if (msVeh->getLane() != nullptr) {
    1187           28 :                 msVeh->updateBestLanes(true);
    1188              :             }
    1189              :         }
    1190           88 :         if (!ok) {
    1191            0 :             throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (invalid nextStopIndex).");
    1192              :         }
    1193              :     } else {
    1194              :         SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
    1195          128 :                                               pos, laneIndex, startPos, flags, duration, until);
    1196              : 
    1197          128 :         if (!vehicle->replaceStop(nextStopIndex, stopPars, "traci:replaceStop", teleport != 0, error)) {
    1198           34 :             throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (" + error + ").");
    1199              :         }
    1200          128 :     }
    1201          199 : }
    1202              : 
    1203              : 
    1204              : void
    1205          144 : Vehicle::insertStop(const std::string& vehID,
    1206              :                     int nextStopIndex,
    1207              :                     const std::string& edgeID,
    1208              :                     double pos,
    1209              :                     int laneIndex,
    1210              :                     double duration,
    1211              :                     int flags,
    1212              :                     double startPos,
    1213              :                     double until,
    1214              :                     int teleport) {
    1215          144 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1216              :     SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
    1217          144 :                                           pos, laneIndex, startPos, flags, duration, until);
    1218              : 
    1219              :     std::string error;
    1220          156 :     if (!vehicle->insertStop(nextStopIndex, stopPars, "traci:insertStop", teleport != 0, error)) {
    1221           34 :         throw TraCIException("Stop insertion failed for vehicle '" + vehID + "' (" + error + ").");
    1222              :     }
    1223          139 : }
    1224              : 
    1225              : 
    1226              : std::string
    1227          441 : Vehicle::getStopParameter(const std::string& vehID, int nextStopIndex, const std::string& param, bool customParam) {
    1228          441 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1229              :     try {
    1230          441 :         if (nextStopIndex >= (int)vehicle->getStops().size() || (nextStopIndex < 0 && -nextStopIndex > (int)vehicle->getPastStops().size())) {
    1231            0 :             throw ProcessError("Invalid stop index " + toString(nextStopIndex)
    1232            0 :                                + " (has " + toString(vehicle->getPastStops().size()) + " past stops and " + toString(vehicle->getStops().size()) + " remaining stops)");
    1233              : 
    1234              :         }
    1235              :         const SUMOVehicleParameter::Stop& pars = (nextStopIndex >= 0
    1236          441 :                 ? vehicle->getStop(nextStopIndex).pars
    1237          198 :                 : vehicle->getPastStops()[vehicle->getPastStops().size() + nextStopIndex]);
    1238          441 :         if (customParam) {
    1239              :             // custom user parameter
    1240           20 :             return pars.getParameter(param, "");
    1241              :         }
    1242              : 
    1243          431 :         if (param == toString(SUMO_ATTR_EDGE)) {
    1244              :             return pars.edge;
    1245          404 :         } else if (param == toString(SUMO_ATTR_LANE)) {
    1246           72 :             return toString(SUMOXMLDefinitions::getIndexFromLane(pars.lane));
    1247          760 :         } else if (param == toString(SUMO_ATTR_BUS_STOP)
    1248          760 :                    || param == toString(SUMO_ATTR_TRAIN_STOP)) {
    1249              :             return pars.busstop;
    1250          380 :         } else if (param == toString(SUMO_ATTR_CONTAINER_STOP)) {
    1251              :             return pars.containerstop;
    1252          380 :         } else if (param == toString(SUMO_ATTR_CHARGING_STATION)) {
    1253              :             return pars.chargingStation;
    1254          380 :         } else if (param == toString(SUMO_ATTR_PARKING_AREA)) {
    1255              :             return pars.parkingarea;
    1256          380 :         } else if (param == toString(SUMO_ATTR_STARTPOS)) {
    1257           19 :             return toString(pars.startPos);
    1258          361 :         } else if (param == toString(SUMO_ATTR_ENDPOS)) {
    1259           19 :             return toString(pars.endPos);
    1260          342 :         } else if (param == toString(SUMO_ATTR_POSITION_LAT)) {
    1261           19 :             return toString(pars.posLat == INVALID_DOUBLE ? INVALID_DOUBLE_VALUE : pars.posLat);
    1262          323 :         } else if (param == toString(SUMO_ATTR_ARRIVAL)) {
    1263           19 :             return pars.arrival < 0 ? "-1" : time2string(pars.arrival);
    1264          304 :         } else if (param == toString(SUMO_ATTR_DURATION)) {
    1265           19 :             return pars.duration < 0 ? "-1" : time2string(pars.duration);
    1266          285 :         } else if (param == toString(SUMO_ATTR_UNTIL)) {
    1267           19 :             return pars.until < 0 ? "-1" : time2string(pars.until);
    1268          266 :         } else if (param == toString(SUMO_ATTR_EXTENSION)) {
    1269           19 :             return pars.extension < 0 ? "-1" : time2string(pars.extension);
    1270          247 :         } else if (param == toString(SUMO_ATTR_INDEX)) {
    1271           19 :             return toString(nextStopIndex + vehicle->getPastStops().size());
    1272          228 :         } else if (param == toString(SUMO_ATTR_PARKING)) {
    1273           19 :             return toString(pars.parking);
    1274          209 :         } else if (param == toString(SUMO_ATTR_TRIGGERED)) {
    1275           19 :             return joinToString(pars.getTriggers(), " ");
    1276          190 :         } else if (param == toString(SUMO_ATTR_EXPECTED)) {
    1277           19 :             return joinToString(pars.awaitedPersons, " ");
    1278          171 :         } else if (param == toString(SUMO_ATTR_EXPECTED_CONTAINERS)) {
    1279            0 :             return joinToString(pars.awaitedContainers, " ");
    1280          171 :         } else if (param == toString(SUMO_ATTR_PERMITTED)) {
    1281           19 :             return joinToString(pars.permitted, " ");
    1282          152 :         } else if (param == toString(SUMO_ATTR_ACTTYPE)) {
    1283              :             return pars.actType;
    1284          133 :         } else if (param == toString(SUMO_ATTR_TRIP_ID)) {
    1285              :             return pars.tripId;
    1286          114 :         } else if (param == toString(SUMO_ATTR_SPLIT)) {
    1287              :             return pars.split;
    1288           95 :         } else if (param == toString(SUMO_ATTR_JOIN)) {
    1289              :             return pars.join;
    1290           76 :         } else if (param == toString(SUMO_ATTR_LINE)) {
    1291              :             return pars.line;
    1292           57 :         } else if (param == toString(SUMO_ATTR_SPEED)) {
    1293           19 :             return toString(pars.speed);
    1294           38 :         } else if (param == toString(SUMO_ATTR_STARTED)) {
    1295           19 :             return pars.started < 0 ? "-1" : time2string(pars.started);
    1296           19 :         } else if (param == toString(SUMO_ATTR_ENDED)) {
    1297           19 :             return pars.ended < 0 ? "-1" : time2string(pars.ended);
    1298            0 :         } else if (param == toString(SUMO_ATTR_ONDEMAND)) {
    1299            0 :             return toString(pars.onDemand);
    1300            0 :         } else if (param == toString(SUMO_ATTR_JUMP)) {
    1301            0 :             return pars.jump < 0 ? "-1" : time2string(pars.jump);
    1302            0 :         } else if (param == toString(SUMO_ATTR_JUMP_UNTIL)) {
    1303            0 :             return pars.jumpUntil < 0 ? "-1" : time2string(pars.jumpUntil);
    1304              :         } else {
    1305            0 :             throw ProcessError(TLF("Unsupported parameter '%'", param));
    1306              :         }
    1307            0 :     } catch (ProcessError& e) {
    1308            0 :         throw TraCIException("Could not get stop parameter for vehicle '" + vehID + "' (" + e.what() + ")");
    1309            0 :     }
    1310              : }
    1311              : 
    1312              : 
    1313              : 
    1314              : void
    1315          187 : Vehicle::setStopParameter(const std::string& vehID, int nextStopIndex,
    1316              :                           const std::string& param, const std::string& value,
    1317              :                           bool customParam) {
    1318          187 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1319              :     try {
    1320          187 :         MSStop& stop = vehicle->getStop(nextStopIndex);
    1321          187 :         SUMOVehicleParameter::Stop& pars = const_cast<SUMOVehicleParameter::Stop&>(stop.pars);
    1322          187 :         if (customParam) {
    1323           10 :             pars.setParameter(param, value);
    1324           10 :             return;
    1325              :         }
    1326              :         std::string error;
    1327          354 :         if (param == toString(SUMO_ATTR_EDGE)
    1328          349 :                 || param == toString(SUMO_ATTR_BUS_STOP)
    1329          345 :                 || param == toString(SUMO_ATTR_TRAIN_STOP)
    1330          345 :                 || param == toString(SUMO_ATTR_CONTAINER_STOP)
    1331          345 :                 || param == toString(SUMO_ATTR_CHARGING_STATION)
    1332          345 :                 || param == toString(SUMO_ATTR_PARKING_AREA)
    1333          517 :                 || param == toString(SUMO_ATTR_LANE)
    1334              :            ) {
    1335           14 :             int laneIndex = stop.lane->getIndex();
    1336           14 :             int flags = pars.getFlags() & 3;
    1337              :             std::string edgeOrStopID = value;
    1338           14 :             if (param == toString(SUMO_ATTR_LANE)) {
    1339            5 :                 laneIndex = StringUtils::toInt(value);
    1340            5 :                 edgeOrStopID = pars.edge;
    1341           18 :             } else if (param == toString(SUMO_ATTR_BUS_STOP)
    1342           14 :                        || param == toString(SUMO_ATTR_TRAIN_STOP)) {
    1343            4 :                 flags |= 8;
    1344            5 :             } else if (param == toString(SUMO_ATTR_CONTAINER_STOP)) {
    1345            0 :                 flags |= 16;
    1346            5 :             } else if (param == toString(SUMO_ATTR_CHARGING_STATION)) {
    1347            0 :                 flags |= 32;
    1348            5 :             } else if (param == toString(SUMO_ATTR_PARKING_AREA)) {
    1349            0 :                 flags |= 64;
    1350              :             }
    1351              :             // special case: replace stop
    1352           14 :             replaceStop(vehID, nextStopIndex, edgeOrStopID, pars.endPos, laneIndex, STEPS2TIME(pars.duration),
    1353           14 :                         flags, pars.startPos, STEPS2TIME(pars.until), 0);
    1354              : 
    1355          163 :         } else if (param == toString(SUMO_ATTR_STARTPOS)) {
    1356           20 :             pars.startPos = StringUtils::toDouble(value);
    1357           20 :             pars.parametersSet |= STOP_START_SET;
    1358          143 :         } else if (param == toString(SUMO_ATTR_ENDPOS)) {
    1359            5 :             pars.endPos = StringUtils::toDouble(value);
    1360            5 :             pars.parametersSet |= STOP_END_SET;
    1361          138 :         } else if (param == toString(SUMO_ATTR_POSITION_LAT)) {
    1362            5 :             pars.posLat = StringUtils::toDouble(value);
    1363            5 :             pars.parametersSet |= STOP_POSLAT_SET;
    1364          133 :         } else if (param == toString(SUMO_ATTR_ARRIVAL)) {
    1365            5 :             pars.arrival = string2time(value);
    1366            5 :             pars.parametersSet |= STOP_ARRIVAL_SET;
    1367          128 :         } else if (param == toString(SUMO_ATTR_DURATION)) {
    1368           10 :             pars.duration = string2time(value);
    1369           10 :             pars.parametersSet |= STOP_DURATION_SET;
    1370              :             // also update dynamic value
    1371           10 :             stop.initPars(pars);
    1372          118 :         } else if (param == toString(SUMO_ATTR_UNTIL)) {
    1373            5 :             pars.until = string2time(value);
    1374            5 :             pars.parametersSet |= STOP_UNTIL_SET;
    1375          113 :         } else if (param == toString(SUMO_ATTR_EXTENSION)) {
    1376           10 :             pars.extension = string2time(value);
    1377           10 :             pars.parametersSet |= STOP_EXTENSION_SET;
    1378          103 :         } else if (param == toString(SUMO_ATTR_INDEX)) {
    1379            0 :             throw TraCIException("Changing stop index is not supported");
    1380          103 :         } else if (param == toString(SUMO_ATTR_PARKING)) {
    1381            5 :             pars.parking = SUMOVehicleParameter::parseParkingType(value);
    1382            5 :             pars.parametersSet |= STOP_PARKING_SET;
    1383           98 :         } else if (param == toString(SUMO_ATTR_TRIGGERED)) {
    1384           10 :             if (pars.speed > 0 && value != "") {
    1385            0 :                 throw ProcessError(TLF("Waypoint (speed = %) at index % does not support triggers", pars.speed, nextStopIndex));
    1386              :             }
    1387           10 :             SUMOVehicleParameter::parseStopTriggers(StringTokenizer(value).getVector(), false, pars);
    1388           10 :             pars.parametersSet |= STOP_TRIGGER_SET;
    1389              :             // also update dynamic value
    1390           10 :             stop.initPars(pars);
    1391           88 :         } else if (param == toString(SUMO_ATTR_EXPECTED)) {
    1392           30 :             pars.awaitedPersons = StringTokenizer(value).getSet();
    1393           15 :             pars.parametersSet |= STOP_EXPECTED_SET;
    1394              :             // also update dynamic value
    1395           15 :             stop.initPars(pars);
    1396           73 :         } else if (param == toString(SUMO_ATTR_EXPECTED_CONTAINERS)) {
    1397            0 :             pars.awaitedContainers = StringTokenizer(value).getSet();
    1398            0 :             pars.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
    1399              :             // also update dynamic value
    1400            0 :             stop.initPars(pars);
    1401           73 :         } else if (param == toString(SUMO_ATTR_PERMITTED)) {
    1402           10 :             pars.permitted = StringTokenizer(value).getSet();
    1403            5 :             pars.parametersSet |= STOP_PERMITTED_SET;
    1404           68 :         } else if (param == toString(SUMO_ATTR_ACTTYPE)) {
    1405            5 :             pars.actType = value;
    1406           63 :         } else if (param == toString(SUMO_ATTR_TRIP_ID)) {
    1407            5 :             pars.tripId = value;
    1408            5 :             pars.parametersSet |= STOP_TRIP_ID_SET;
    1409           58 :         } else if (param == toString(SUMO_ATTR_SPLIT)) {
    1410            5 :             pars.split = value;
    1411            5 :             pars.parametersSet |= STOP_SPLIT_SET;
    1412           53 :         } else if (param == toString(SUMO_ATTR_JOIN)) {
    1413            5 :             pars.join = value;
    1414            5 :             pars.parametersSet |= STOP_JOIN_SET;
    1415              :             // also update dynamic value
    1416            5 :             stop.initPars(pars);
    1417           48 :         } else if (param == toString(SUMO_ATTR_LINE)) {
    1418            5 :             pars.line = value;
    1419            5 :             pars.parametersSet |= STOP_LINE_SET;
    1420           43 :         } else if (param == toString(SUMO_ATTR_SPEED)) {
    1421           10 :             const double speed = StringUtils::toDouble(value);
    1422           15 :             if (speed > 0 && pars.getTriggers().size() > 0) {
    1423           10 :                 throw ProcessError(TLF("Triggered stop at index % cannot be changed into a waypoint by setting speed to %", nextStopIndex, speed));
    1424              :             }
    1425            5 :             pars.speed = speed;
    1426            5 :             pars.parametersSet |= STOP_SPEED_SET;
    1427           33 :         } else if (param == toString(SUMO_ATTR_STARTED)) {
    1428            5 :             pars.started = string2time(value);
    1429            5 :             pars.parametersSet |= STOP_STARTED_SET;
    1430           28 :         } else if (param == toString(SUMO_ATTR_ENDED)) {
    1431            5 :             pars.ended = string2time(value);
    1432            5 :             pars.parametersSet |= STOP_ENDED_SET;
    1433           23 :         } else if (param == toString(SUMO_ATTR_ONDEMAND)) {
    1434            5 :             pars.onDemand = StringUtils::toBool(value);
    1435            5 :             pars.parametersSet |= STOP_ONDEMAND_SET;
    1436           18 :         } else if (param == toString(SUMO_ATTR_JUMP)) {
    1437           18 :             pars.jump = string2time(value);
    1438           18 :             pars.parametersSet |= STOP_JUMP_SET;
    1439            5 :         } else if (param == toString(SUMO_ATTR_JUMP_UNTIL)) {
    1440            0 :             pars.jumpUntil = string2time(value);
    1441            0 :             pars.parametersSet |= STOP_JUMP_UNTIL_SET;
    1442              :         } else {
    1443            0 :             throw ProcessError(TLF("Unsupported parameter '%'", param));
    1444              :         }
    1445            5 :     } catch (ProcessError& e) {
    1446           10 :         throw TraCIException("Could not set stop parameter for vehicle '" + vehID + "' (" + e.what() + ")");
    1447            5 :     }
    1448              : }
    1449              : 
    1450              : 
    1451              : void
    1452           20 : Vehicle::rerouteParkingArea(const std::string& vehID, const std::string& parkingAreaID) {
    1453           20 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1454           20 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1455           20 :     if (veh == nullptr) {
    1456            0 :         WRITE_WARNING("rerouteParkingArea not yet implemented for meso");
    1457            0 :         return;
    1458              :     }
    1459              :     std::string error;
    1460              :     // Forward command to vehicle
    1461           20 :     if (!veh->rerouteParkingArea(parkingAreaID, error)) {
    1462            0 :         throw TraCIException(error);
    1463              :     }
    1464              : }
    1465              : 
    1466              : void
    1467           12 : Vehicle::resume(const std::string& vehID) {
    1468           12 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1469           12 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1470           12 :     if (veh == nullptr) {
    1471            2 :         WRITE_WARNING("resume not yet implemented for meso");
    1472            2 :         return;
    1473              :     }
    1474           10 :     if (!veh->hasStops()) {
    1475            0 :         throw TraCIException("Failed to resume vehicle '" + veh->getID() + "', it has no stops.");
    1476              :     }
    1477           10 :     if (!veh->resumeFromStopping()) {
    1478            0 :         const MSStop& sto = veh->getNextStop();
    1479            0 :         std::ostringstream strs;
    1480            0 :         strs << "reached: " << sto.reached;
    1481            0 :         strs << ", duration:" << sto.duration;
    1482            0 :         strs << ", edge:" << (*sto.edge)->getID();
    1483            0 :         strs << ", startPos: " << sto.pars.startPos;
    1484              :         std::string posStr = strs.str();
    1485            0 :         throw TraCIException("Failed to resume from stopping for vehicle '" + veh->getID() + "', " + posStr);
    1486            0 :     }
    1487              : }
    1488              : 
    1489              : 
    1490              : void
    1491        21111 : Vehicle::changeTarget(const std::string& vehID, const std::string& edgeID) {
    1492        21111 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    1493        21111 :     const MSEdge* destEdge = MSEdge::dictionary(edgeID);
    1494        21111 :     const bool onInit = isOnInit(vehID);
    1495        21111 :     if (destEdge == nullptr) {
    1496            2 :         throw TraCIException("Destination edge '" + edgeID + "' is not known.");
    1497              :     }
    1498              :     // change the final edge of the route and reroute
    1499              :     try {
    1500        21110 :         const bool success = veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:changeTarget",
    1501              :                                           veh->getRouterTT(), onInit, false, false, destEdge);
    1502        21110 :         if (!success) {
    1503           20 :             throw TraCIException("ChangeTarget failed for vehicle '" + veh->getID() + "', destination edge '" + edgeID + "' unreachable.");
    1504              :         }
    1505            0 :     } catch (ProcessError& e) {
    1506            0 :         throw TraCIException(e.what());
    1507            0 :     }
    1508        21100 : }
    1509              : 
    1510              : 
    1511              : void
    1512         7572 : Vehicle::changeLane(const std::string& vehID, int laneIndex, double duration) {
    1513              :     try {
    1514         7572 :         checkTimeBounds(duration);
    1515            0 :     } catch (ProcessError&) {
    1516            0 :         throw TraCIException("Duration parameter exceeds the time value range.");
    1517            0 :     }
    1518         7572 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1519         7572 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1520         7572 :     if (veh == nullptr) {
    1521            0 :         WRITE_ERROR("changeLane not applicable for meso");
    1522            0 :         return;
    1523              :     }
    1524              : 
    1525            0 :     std::vector<std::pair<SUMOTime, int> > laneTimeLine;
    1526         7572 :     laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
    1527         7572 :     laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
    1528         7572 :     veh->getInfluencer().setLaneTimeLine(laneTimeLine);
    1529         7572 : }
    1530              : 
    1531              : void
    1532          275 : Vehicle::changeLaneRelative(const std::string& vehID, int indexOffset, double duration) {
    1533              :     try {
    1534          275 :         checkTimeBounds(duration);
    1535            0 :     } catch (ProcessError&) {
    1536            0 :         throw TraCIException("Duration parameter exceeds the time value range.");
    1537            0 :     }
    1538          275 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1539          275 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1540          275 :     if (veh == nullptr) {
    1541            2 :         WRITE_ERROR("changeLaneRelative not applicable for meso");
    1542            2 :         return;
    1543              :     }
    1544              : 
    1545            0 :     std::vector<std::pair<SUMOTime, int> > laneTimeLine;
    1546          273 :     int laneIndex = veh->getLaneIndex() + indexOffset;
    1547          273 :     if (laneIndex < 0 && !veh->getLaneChangeModel().isOpposite()) {
    1548           20 :         if (veh->getLaneIndex() == -1) {
    1549            0 :             WRITE_WARNINGF(TL("Ignoring changeLaneRelative for vehicle '%' that isn't on the road"), vehID);
    1550              :         } else {
    1551           60 :             WRITE_WARNINGF(TL("Ignoring indexOffset % for vehicle '%' on laneIndex %."), indexOffset, vehID, veh->getLaneIndex());
    1552              :         }
    1553              :     } else {
    1554          253 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
    1555          253 :         laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
    1556          253 :         veh->getInfluencer().setLaneTimeLine(laneTimeLine);
    1557              :     }
    1558          273 : }
    1559              : 
    1560              : 
    1561              : void
    1562          337 : Vehicle::changeSublane(const std::string& vehID, double latDist) {
    1563          337 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1564          337 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1565          337 :     if (veh == nullptr) {
    1566            1 :         WRITE_ERROR("changeSublane not applicable for meso");
    1567            1 :         return;
    1568              :     }
    1569              : 
    1570          336 :     veh->getInfluencer().setSublaneChange(latDist);
    1571              : }
    1572              : 
    1573              : 
    1574              : void
    1575        22943 : Vehicle::add(const std::string& vehID,
    1576              :              const std::string& routeID,
    1577              :              const std::string& typeID,
    1578              :              const std::string& depart,
    1579              :              const std::string& departLane,
    1580              :              const std::string& departPos,
    1581              :              const std::string& departSpeed,
    1582              :              const std::string& arrivalLane,
    1583              :              const std::string& arrivalPos,
    1584              :              const std::string& arrivalSpeed,
    1585              :              const std::string& fromTaz,
    1586              :              const std::string& toTaz,
    1587              :              const std::string& line,
    1588              :              int /*personCapacity*/,
    1589              :              int personNumber) {
    1590        22943 :     SUMOVehicle* veh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
    1591        22943 :     if (veh != nullptr) {
    1592            2 :         throw TraCIException("The vehicle '" + vehID + "' to add already exists.");
    1593              :     }
    1594              : 
    1595        22942 :     SUMOVehicleParameter vehicleParams;
    1596              :     vehicleParams.id = vehID;
    1597        22942 :     MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
    1598        22942 :     if (!vehicleType) {
    1599            4 :         throw TraCIException("Invalid type '" + typeID + "' for vehicle '" + vehID + "'.");
    1600              :     }
    1601        22940 :     if (typeID != "DEFAULT_VEHTYPE") {
    1602              :         vehicleParams.vtypeid = typeID;
    1603        21841 :         vehicleParams.parametersSet |= VEHPARS_VTYPE_SET;
    1604              :     }
    1605        22940 :     if (SUMOVehicleParserHelper::isInternalRouteID(routeID)) {
    1606            0 :         WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
    1607              :     }
    1608        22940 :     ConstMSRoutePtr route = MSRoute::dictionary(routeID);
    1609        22940 :     if (!route) {
    1610           44 :         if (routeID == "") {
    1611              :             // assume, route was intentionally left blank because the caller
    1612              :             // intends to control the vehicle remotely
    1613              :             SUMOVehicleClass vclass = vehicleType->getVehicleClass();
    1614           43 :             const std::string dummyRouteID = "DUMMY_ROUTE_" + SumoVehicleClassStrings.getString(vclass);
    1615           86 :             route = MSRoute::dictionary(dummyRouteID);
    1616           43 :             if (route == nullptr) {
    1617         4585 :                 for (MSEdge* e : MSEdge::getAllEdges()) {
    1618         4585 :                     if (e->getFunction() == SumoXMLEdgeFunc::NORMAL && (e->getPermissions() & vclass) == vclass) {
    1619            0 :                         std::vector<std::string>  edges;
    1620           43 :                         edges.push_back(e->getID());
    1621           43 :                         libsumo::Route::add(dummyRouteID, edges);
    1622              :                         break;
    1623           43 :                     }
    1624              :                 }
    1625              :             }
    1626           86 :             route = MSRoute::dictionary(dummyRouteID);
    1627           43 :             if (!route) {
    1628            0 :                 throw TraCIException("Could not build dummy route for vehicle class: '" + SumoVehicleClassStrings.getString(vehicleType->getVehicleClass()) + "'");
    1629              :             }
    1630              :         } else {
    1631            2 :             throw TraCIException("Invalid route '" + routeID + "' for vehicle '" + vehID + "'.");
    1632              :         }
    1633              :     }
    1634              :     // check if the route implies a trip
    1635        22939 :     if (route->getEdges().size() == 2) {
    1636        22457 :         const MSEdgeVector& succ = route->getEdges().front()->getSuccessors();
    1637        22457 :         if (std::find(succ.begin(), succ.end(), route->getEdges().back()) == succ.end()) {
    1638           65 :             vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
    1639              :         }
    1640              :     }
    1641        22939 :     if (fromTaz != "" || toTaz != "") {
    1642           15 :         vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
    1643              :     }
    1644              :     std::string error;
    1645        45878 :     if (!SUMOVehicleParameter::parseDepart(depart, "vehicle", vehID, vehicleParams.depart, vehicleParams.departProcedure, error)) {
    1646            0 :         throw TraCIException(error);
    1647              :     }
    1648        22939 :     if (vehicleParams.departProcedure == DepartDefinition::GIVEN && vehicleParams.depart < MSNet::getInstance()->getCurrentTimeStep()) {
    1649            9 :         vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
    1650           27 :         WRITE_WARNINGF(TL("Departure time for vehicle '%' is in the past; using current time instead."), vehID);
    1651        22930 :     } else if (vehicleParams.departProcedure == DepartDefinition::NOW) {
    1652        22888 :         vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
    1653              :     }
    1654        45878 :     if (!SUMOVehicleParameter::parseDepartLane(departLane, "vehicle", vehID, vehicleParams.departLane, vehicleParams.departLaneProcedure, error)) {
    1655           10 :         throw TraCIException(error);
    1656              :     }
    1657        45868 :     if (!SUMOVehicleParameter::parseDepartPos(departPos, "vehicle", vehID, vehicleParams.departPos, vehicleParams.departPosProcedure, error)) {
    1658            0 :         throw TraCIException(error);
    1659              :     }
    1660        45868 :     if (!SUMOVehicleParameter::parseDepartSpeed(departSpeed, "vehicle", vehID, vehicleParams.departSpeed, vehicleParams.departSpeedProcedure, error)) {
    1661            0 :         throw TraCIException(error);
    1662              :     }
    1663        45868 :     if (!SUMOVehicleParameter::parseArrivalLane(arrivalLane, "vehicle", vehID, vehicleParams.arrivalLane, vehicleParams.arrivalLaneProcedure, error)) {
    1664            0 :         throw TraCIException(error);
    1665              :     }
    1666        45868 :     if (!SUMOVehicleParameter::parseArrivalPos(arrivalPos, "vehicle", vehID, vehicleParams.arrivalPos, vehicleParams.arrivalPosProcedure, error)) {
    1667            0 :         throw TraCIException(error);
    1668              :     }
    1669        45890 :     if (!SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeed, "vehicle", vehID, vehicleParams.arrivalSpeed, vehicleParams.arrivalSpeedProcedure, error)) {
    1670            0 :         throw TraCIException(error);
    1671              :     }
    1672              :     // mark non-default attributes
    1673        22934 :     if (departLane != "first") {
    1674        21874 :         vehicleParams.parametersSet |= VEHPARS_DEPARTLANE_SET;
    1675              :     }
    1676        22934 :     if (departPos != "base") {
    1677        22069 :         vehicleParams.parametersSet |= VEHPARS_DEPARTPOS_SET;
    1678              :     }
    1679        22934 :     if (departSpeed != "0") {
    1680        21835 :         vehicleParams.parametersSet |= VEHPARS_DEPARTSPEED_SET;
    1681              :     }
    1682        22934 :     if (arrivalLane != "current") {
    1683           15 :         vehicleParams.parametersSet |= VEHPARS_ARRIVALLANE_SET;
    1684              :     }
    1685        22934 :     if (arrivalPos != "max") {
    1686           10 :         vehicleParams.parametersSet |= VEHPARS_ARRIVALPOS_SET;
    1687              :     }
    1688        22934 :     if (arrivalSpeed != "current") {
    1689            5 :         vehicleParams.parametersSet |= VEHPARS_ARRIVALSPEED_SET;
    1690              :     }
    1691        22934 :     if (fromTaz != "") {
    1692           10 :         vehicleParams.parametersSet |= VEHPARS_FROM_TAZ_SET;
    1693              :     }
    1694        22934 :     if (toTaz != "") {
    1695           10 :         vehicleParams.parametersSet |= VEHPARS_TO_TAZ_SET;
    1696              :     }
    1697        22934 :     if (line != "") {
    1698           18 :         vehicleParams.parametersSet |= VEHPARS_LINE_SET;
    1699              :     }
    1700        22934 :     if (personNumber != 0) {
    1701            0 :         vehicleParams.parametersSet |= VEHPARS_PERSON_NUMBER_SET;
    1702              :     }
    1703              :     // build vehicle
    1704              :     vehicleParams.fromTaz = fromTaz;
    1705              :     vehicleParams.toTaz = toTaz;
    1706              :     vehicleParams.line = line;
    1707              :     //vehicleParams.personCapacity = personCapacity;
    1708        22934 :     vehicleParams.personNumber = personNumber;
    1709              : 
    1710        22934 :     SUMOVehicleParameter* params = new SUMOVehicleParameter(vehicleParams);
    1711              :     SUMOVehicle* vehicle = nullptr;
    1712              :     try {
    1713        22951 :         vehicle = MSNet::getInstance()->getVehicleControl().buildVehicle(params, route, vehicleType, true, MSVehicleControl::VehicleDefinitionSource::LIBSUMO);
    1714        22934 :         if (fromTaz == "" && !route->getEdges().front()->validateDepartSpeed(*vehicle)) {
    1715            5 :             MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
    1716           10 :             throw TraCIException("Departure speed for vehicle '" + vehID + "' is too high for the departure edge '" + route->getEdges().front()->getID() + "'.");
    1717              :         }
    1718              :         std::string msg;
    1719        22929 :         if (vehicle->getRouteValidity(true, true, &msg) != MSBaseVehicle::ROUTE_VALID) {
    1720            5 :             MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
    1721           10 :             throw TraCIException("Vehicle '" + vehID + "' has no valid route (" + msg + "). ");
    1722              :         }
    1723        22917 :         MSNet::getInstance()->getVehicleControl().addVehicle(vehicleParams.id, vehicle);
    1724        22917 :         if (vehicleParams.departProcedure != DepartDefinition::TRIGGERED && vehicleParams.departProcedure != DepartDefinition::CONTAINER_TRIGGERED) {
    1725        22897 :             MSNet::getInstance()->getInsertionControl().add(vehicle);
    1726              :         }
    1727           17 :     } catch (ProcessError& e) {
    1728            7 :         if (vehicle != nullptr) {
    1729            7 :             MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
    1730              :         }
    1731           14 :         throw TraCIException(e.what());
    1732            7 :     }
    1733        22942 : }
    1734              : 
    1735              : 
    1736              : void
    1737         7815 : Vehicle::moveToXY(const std::string& vehID, const std::string& edgeID, const int laneIndex,
    1738              :                   const double x, const double y, double angle, const int keepRoute, double matchThreshold) {
    1739         7815 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1740         7815 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1741         7815 :     if (veh == nullptr) {
    1742            5 :         WRITE_WARNING("moveToXY not yet implemented for meso");
    1743            5 :         return;
    1744              :     }
    1745         7810 :     const bool doKeepRoute = (keepRoute & 1) != 0 && veh->getID() != "VTD_EGO";
    1746         7810 :     const bool mayLeaveNetwork = (keepRoute & 2) != 0;
    1747         7810 :     const bool ignorePermissions = (keepRoute & 4) != 0;
    1748         7810 :     const bool setLateralPos = (MSGlobals::gLateralResolution > 0 || mayLeaveNetwork);
    1749         7810 :     SUMOVehicleClass vClass = ignorePermissions ? SVC_IGNORING : veh->getVClass();
    1750              :     // process
    1751        15620 :     const std::string origID = edgeID + "_" + toString(laneIndex);
    1752              :     // @todo add an interpretation layer for OSM derived origID values (without lane index)
    1753              :     Position pos(x, y);
    1754              : #ifdef DEBUG_MOVEXY
    1755              :     const double origAngle = angle;
    1756              : #endif
    1757              :     // angle must be in [0,360] because it will be compared against those returned by naviDegree()
    1758              :     // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
    1759         7810 :     if (angle != INVALID_DOUBLE_VALUE) {
    1760         2846 :         while (angle >= 360.) {
    1761            0 :             angle -= 360.;
    1762              :         }
    1763         2856 :         while (angle < 0.) {
    1764           10 :             angle += 360.;
    1765              :         }
    1766              :     }
    1767              : 
    1768              : #ifdef DEBUG_MOVEXY
    1769              :     std::cout << std::endl << SIMTIME << " moveToXY veh=" << veh->getID() << " vehPos=" << veh->getPosition()
    1770              :               << " lane=" << Named::getIDSecure(veh->getLane()) << " lanePos=" << vehicle->getPositionOnLane() << std::endl;
    1771              :     std::cout << " wantedPos=" << pos << " origID=" << origID << " laneIndex=" << laneIndex << " origAngle=" << origAngle << " angle=" << angle << " keepRoute=" << keepRoute << std::endl;
    1772              : #endif
    1773              : 
    1774            0 :     ConstMSEdgeVector edges;
    1775         7810 :     MSLane* lane = nullptr;
    1776              :     double lanePos;
    1777              :     double lanePosLat = 0;
    1778         7810 :     double bestDistance = std::numeric_limits<double>::max();
    1779         7810 :     int routeOffset = 0;
    1780              :     bool found;
    1781         7810 :     double maxRouteDistance = matchThreshold;
    1782              :     /* EGO vehicle is known to have a fixed route. @todo make this into a parameter of the TraCI call */
    1783         7810 :     if (doKeepRoute) {
    1784              :         // case a): vehicle is on its earlier route
    1785              :         //  we additionally assume it is moving forward (SUMO-limit);
    1786              :         //  note that the route ("edges") is not changed in this case
    1787              : 
    1788         5138 :         found = Helper::moveToXYMap_matchingRoutePosition(pos, origID,
    1789         5138 :                 veh->getRoute().getEdges(), veh->getRoutePosition(),
    1790              :                 vClass, setLateralPos,
    1791              :                 bestDistance, &lane, lanePos, routeOffset);
    1792              :         // @note silenty ignoring mapping failure
    1793              :     } else {
    1794         2672 :         const double speed = pos.distanceTo2D(veh->getPosition()); // !!!veh->getSpeed();
    1795         5344 :         found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, origID, angle,
    1796         2672 :                                     speed, veh->getRoute().getEdges(), veh->getRoutePosition(), veh->getLane(), veh->getPositionOnLane(), veh->isOnRoad(),
    1797         2672 :                                     vClass, GeomHelper::naviDegree(veh->getAngle()), setLateralPos,
    1798              :                                     bestDistance, &lane, lanePos, routeOffset, edges);
    1799              :     }
    1800         7810 :     if ((found && bestDistance <= maxRouteDistance) || mayLeaveNetwork) {
    1801              :         // optionally compute lateral offset
    1802         7803 :         pos.setz(veh->getPosition().z());
    1803         7803 :         if (found && setLateralPos) {
    1804         5133 :             const double perpDist = lane->getShape().distance2D(pos, false);
    1805         5133 :             if (perpDist != GeomHelper::INVALID_OFFSET) {
    1806              :                 lanePosLat = perpDist;
    1807         5133 :                 if (!mayLeaveNetwork) {
    1808           57 :                     lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - MSGlobals::gLateralResolution));
    1809              :                 }
    1810              :                 // figure out whether the offset is to the left or to the right
    1811         5133 :                 PositionVector tmp = lane->getShape();
    1812              :                 try {
    1813         5133 :                     tmp.move2side(-lanePosLat); // moved to left
    1814            0 :                 } catch (ProcessError&) {
    1815            0 :                     WRITE_WARNINGF(TL("Could not determine position on lane '%' at lateral position %."), lane->getID(), toString(-lanePosLat));
    1816            0 :                 }
    1817              :                 //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
    1818         5133 :                 if (tmp.distance2D(pos) > perpDist) {
    1819              :                     lanePosLat = -lanePosLat;
    1820              :                 }
    1821         5133 :             }
    1822         5133 :             pos.setz(lane->geometryPositionAtOffset(lanePos).z());
    1823              :         }
    1824         7803 :         if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
    1825              :             // mapped position may differ from pos
    1826         2529 :             pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
    1827              :         }
    1828              :         assert((found && lane != 0) || (!found && lane == 0));
    1829              :         assert(!std::isnan(lanePos));
    1830         7803 :         if (angle == INVALID_DOUBLE_VALUE) {
    1831         4959 :             if (lane != nullptr) {
    1832         4819 :                 angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
    1833              :             } else {
    1834              :                 // compute angle outside road network from old and new position
    1835          140 :                 angle = GeomHelper::naviDegree(veh->getPosition().angleTo2D(pos));
    1836              :             }
    1837              :         }
    1838              :         // use the best we have
    1839              : #ifdef DEBUG_MOVEXY
    1840              :         std::cout << SIMTIME << " veh=" << vehID + " moveToXYResult lane='" << Named::getIDSecure(lane) << "' lanePos=" << lanePos << " lanePosLat=" << lanePosLat << "\n";
    1841              : #endif
    1842         7803 :         Helper::setRemoteControlled(veh, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
    1843         7803 :         if (!veh->isOnRoad()) {
    1844          206 :             MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
    1845              :         }
    1846              :     } else {
    1847            7 :         if (lane == nullptr) {
    1848            3 :             throw TraCIException("Could not map vehicle '" + vehID + "', no road found within " + toString(maxRouteDistance) + "m.");
    1849              :         } else {
    1850           18 :             throw TraCIException("Could not map vehicle '" + vehID + "', distance to road is " + toString(bestDistance) + ".");
    1851              :         }
    1852              :     }
    1853         7810 : }
    1854              : 
    1855              : void
    1856           50 : Vehicle::slowDown(const std::string& vehID, double speed, double duration) {
    1857              :     try {
    1858           50 :         checkTimeBounds(duration);
    1859            0 :     } catch (ProcessError&) {
    1860            0 :         throw TraCIException("Duration parameter exceeds the time value range.");
    1861            0 :     }
    1862           50 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1863           50 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1864           50 :     if (veh == nullptr) {
    1865            6 :         WRITE_ERROR("slowDown not applicable for meso");
    1866            6 :         return;
    1867              :     }
    1868              : 
    1869            0 :     std::vector<std::pair<SUMOTime, double> > speedTimeLine;
    1870           44 :     speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh->getSpeed()));
    1871           44 :     speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), speed));
    1872           44 :     veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
    1873           44 : }
    1874              : 
    1875              : void
    1876           61 : Vehicle::openGap(const std::string& vehID, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, const std::string& referenceVehID) {
    1877              :     try {
    1878           61 :         checkTimeBounds(duration);
    1879            0 :     } catch (ProcessError&) {
    1880            0 :         throw TraCIException("Duration parameter exceeds the time value range.");
    1881            0 :     }
    1882           61 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1883           61 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1884           61 :     if (veh == nullptr) {
    1885            0 :         WRITE_ERROR("openGap not applicable for meso");
    1886            0 :         return;
    1887              :     }
    1888              : 
    1889              :     MSVehicle* refVeh = nullptr;
    1890           61 :     if (referenceVehID != "") {
    1891           13 :         refVeh = dynamic_cast<MSVehicle*>(Helper::getVehicle(referenceVehID));
    1892              :     }
    1893           61 :     const double originalTau = veh->getVehicleType().getCarFollowModel().getHeadwayTime();
    1894           61 :     if (newTimeHeadway == -1) {
    1895              :         newTimeHeadway = originalTau;
    1896              :     }
    1897           61 :     if (originalTau > newTimeHeadway) {
    1898            4 :         WRITE_WARNING("Ignoring openGap(). New time headway must not be smaller than the original.");
    1899            4 :         return;
    1900              :     }
    1901           57 :     veh->getInfluencer().activateGapController(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel, refVeh);
    1902              : }
    1903              : 
    1904              : void
    1905            8 : Vehicle::deactivateGapControl(const std::string& vehID) {
    1906            8 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1907            8 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1908            8 :     if (veh == nullptr) {
    1909            0 :         WRITE_ERROR("deactivateGapControl not applicable for meso");
    1910            0 :         return;
    1911              :     }
    1912              : 
    1913            8 :     if (veh->hasInfluencer()) {
    1914            8 :         veh->getInfluencer().deactivateGapController();
    1915              :     }
    1916              : }
    1917              : 
    1918              : void
    1919            0 : Vehicle::requestToC(const std::string& vehID, double leadTime) {
    1920            0 :     setParameter(vehID, "device.toc.requestToC", toString(leadTime));
    1921            0 : }
    1922              : 
    1923              : void
    1924         5733 : Vehicle::setSpeed(const std::string& vehID, double speed) {
    1925         5733 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1926         5732 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1927         5732 :     if (veh == nullptr) {
    1928            6 :         WRITE_WARNING("setSpeed not yet implemented for meso");
    1929            6 :         return;
    1930              :     }
    1931              : 
    1932            0 :     std::vector<std::pair<SUMOTime, double> > speedTimeLine;
    1933         5726 :     if (speed >= 0) {
    1934         5691 :         speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), speed));
    1935         5691 :         speedTimeLine.push_back(std::make_pair(SUMOTime_MAX - DELTA_T, speed));
    1936              :     }
    1937         5726 :     veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
    1938         5726 : }
    1939              : 
    1940              : void
    1941           12 : Vehicle::setAcceleration(const std::string& vehID, double acceleration, double duration) {
    1942              :     try {
    1943           12 :         checkTimeBounds(duration);
    1944            0 :     } catch (ProcessError&) {
    1945            0 :         throw TraCIException("Duration parameter exceeds the time value range.");
    1946            0 :     }
    1947           12 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1948           12 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1949           12 :     if (veh == nullptr) {
    1950            3 :         WRITE_WARNING("setAcceleration not yet implemented for meso");
    1951            3 :         return;
    1952              :     }
    1953              : 
    1954           12 :     double targetSpeed = std::max(veh->getSpeed() + acceleration * duration, 0.0);
    1955            0 :     std::vector<std::pair<SUMOTime, double>> speedTimeLine;
    1956            9 :     speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh->getSpeed()));
    1957            9 :     speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), targetSpeed));
    1958            9 :     veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
    1959            9 : }
    1960              : 
    1961              : void
    1962          243 : Vehicle::setPreviousSpeed(const std::string& vehID, double prevSpeed, double prevAcceleration) {
    1963          243 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1964          243 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1965          243 :     if (veh == nullptr) {
    1966            2 :         WRITE_WARNING("setPreviousSpeed not yet implemented for meso");
    1967            2 :         return;
    1968              :     }
    1969          241 :     if (prevAcceleration == INVALID_DOUBLE_VALUE) {
    1970              :         prevAcceleration = std::numeric_limits<double>::min();
    1971              :     }
    1972          241 :     veh->setPreviousSpeed(prevSpeed, prevAcceleration);
    1973              : }
    1974              : 
    1975              : void
    1976         1611 : Vehicle::setSpeedMode(const std::string& vehID, int speedMode) {
    1977         1611 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1978         1611 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1979         1611 :     if (veh == nullptr) {
    1980            5 :         WRITE_WARNING("setSpeedMode not yet implemented for meso");
    1981            5 :         return;
    1982              :     }
    1983              : 
    1984         1606 :     veh->getInfluencer().setSpeedMode(speedMode);
    1985              : }
    1986              : 
    1987              : void
    1988          450 : Vehicle::setLaneChangeMode(const std::string& vehID, int laneChangeMode) {
    1989          450 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    1990          450 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    1991          450 :     if (veh == nullptr) {
    1992            0 :         WRITE_ERROR("setLaneChangeMode not applicable for meso");
    1993            0 :         return;
    1994              :     }
    1995              : 
    1996          450 :     veh->getInfluencer().setLaneChangeMode(laneChangeMode);
    1997              : }
    1998              : 
    1999              : void
    2000          225 : Vehicle::setRoutingMode(const std::string& vehID, int routingMode) {
    2001          225 :     Helper::getVehicle(vehID)->setRoutingMode(routingMode);
    2002          225 : }
    2003              : 
    2004              : void
    2005          257 : Vehicle::setType(const std::string& vehID, const std::string& typeID) {
    2006          257 :     MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
    2007          257 :     if (vehicleType == nullptr) {
    2008            0 :         throw TraCIException("Vehicle type '" + typeID + "' is not known");
    2009              :     }
    2010          257 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2011          257 :     veh->replaceVehicleType(vehicleType);
    2012          257 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    2013          257 :     if (microVeh != nullptr && microVeh->isOnRoad()) {
    2014          239 :         microVeh->updateBestLanes(true);
    2015          239 :         microVeh->updateLaneBruttoSum();
    2016              :     }
    2017          257 : }
    2018              : 
    2019              : void
    2020           27 : Vehicle::setRouteID(const std::string& vehID, const std::string& routeID) {
    2021           27 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2022           27 :     ConstMSRoutePtr r = MSRoute::dictionary(routeID);
    2023           27 :     if (r == nullptr) {
    2024            2 :         throw TraCIException("The route '" + routeID + "' is not known.");
    2025              :     }
    2026           26 :     if (SUMOVehicleParserHelper::isInternalRouteID(routeID)) {
    2027            3 :         WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
    2028              :     }
    2029              :     std::string msg;
    2030           52 :     if (!veh->hasValidRoute(msg, r)) {
    2031            5 :         WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), veh->getID(), msg);
    2032            1 :         if (MSGlobals::gCheckRoutes) {
    2033            2 :             throw TraCIException("Route replacement failed for " + veh->getID());
    2034              :         }
    2035              :     }
    2036              : 
    2037              :     std::string errorMsg;
    2038           76 :     if (!veh->replaceRoute(r, "traci:setRouteID", veh->getLane() == nullptr, 0, true, true, &errorMsg)) {
    2039            2 :         throw TraCIException("Route replacement failed for vehicle '" + veh->getID() + "' (" + errorMsg + ").");
    2040              :     }
    2041           24 : }
    2042              : 
    2043              : void
    2044            1 : Vehicle::setRoute(const std::string& vehID, const std::string& edgeID) {
    2045            3 :     setRoute(vehID, std::vector<std::string>({edgeID}));
    2046            0 : }
    2047              : 
    2048              : 
    2049              : void
    2050           38 : Vehicle::setRoute(const std::string& vehID, const std::vector<std::string>& edgeIDs) {
    2051           38 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2052            0 :     ConstMSEdgeVector edges;
    2053           38 :     const bool onInit = veh->getLane() == nullptr;
    2054              :     try {
    2055           71 :         MSEdge::parseEdgesList(edgeIDs, edges, "<unknown>");
    2056           33 :         if (edges.size() > 0 && edges.front()->isInternal()) {
    2057            9 :             if (edges.size() == 1) {
    2058              :                 // avoid crashing due to lack of normal edges in route (#5390)
    2059            5 :                 edges.push_back(edges.back()->getLanes()[0]->getNextNormal());
    2060              :             } else {
    2061              :                 // avoid internal edge in final route
    2062            4 :                 if (edges.front() == &veh->getLane()->getEdge()) {
    2063              :                     edges.erase(edges.begin());
    2064              :                 }
    2065              :             }
    2066              :         }
    2067            5 :     } catch (ProcessError& e) {
    2068           10 :         throw TraCIException("Invalid edge list for vehicle '" + veh->getID() + "' (" + e.what() + ")");
    2069            5 :     }
    2070              :     std::string errorMsg;
    2071           69 :     if (!veh->replaceRouteEdges(edges, -1, 0, "traci:setRoute", onInit, true, true, &errorMsg)) {
    2072            6 :         throw TraCIException("Route replacement failed for vehicle '" + veh->getID() + "' (" + errorMsg + ").");
    2073              :     }
    2074           38 : }
    2075              : 
    2076              : 
    2077              : void
    2078            9 : Vehicle::setLateralLanePosition(const std::string& vehID, double posLat) {
    2079            9 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2080            9 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    2081            9 :     if (veh != nullptr) {
    2082              :         veh->setLateralPositionOnLane(posLat);
    2083              :     } else {
    2084            2 :         WRITE_ERROR("setLateralLanePosition not applicable for meso");
    2085              :     }
    2086            9 : }
    2087              : 
    2088              : 
    2089              : void
    2090          279 : Vehicle::updateBestLanes(const std::string& vehID) {
    2091          279 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2092          279 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    2093          279 :     if (veh == nullptr) {
    2094            1 :         WRITE_ERROR("updateBestLanes not applicable for meso");
    2095            1 :         return;
    2096              :     }
    2097          278 :     if (veh->isOnRoad()) {
    2098          270 :         veh->updateBestLanes(true);
    2099              :     }
    2100              : }
    2101              : 
    2102              : 
    2103              : void
    2104          196 : Vehicle::setAdaptedTraveltime(const std::string& vehID, const std::string& edgeID,
    2105              :                               double time, double begSeconds, double endSeconds) {
    2106          196 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2107          196 :     MSEdge* edge = MSEdge::dictionary(edgeID);
    2108          196 :     if (edge == nullptr) {
    2109            0 :         throw TraCIException("Edge '" + edgeID + "' is not known.");
    2110              :     }
    2111          196 :     if (time != INVALID_DOUBLE_VALUE) {
    2112              :         // add time
    2113          187 :         if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
    2114              :             // clean up old values before setting whole range
    2115          159 :             while (veh->getWeightsStorage().knowsTravelTime(edge)) {
    2116            0 :                 veh->getWeightsStorage().removeTravelTime(edge);
    2117              :             }
    2118              :         }
    2119          187 :         veh->getWeightsStorage().addTravelTime(edge, begSeconds, endSeconds, time);
    2120              :     } else {
    2121              :         // remove time
    2122           18 :         while (veh->getWeightsStorage().knowsTravelTime(edge)) {
    2123            9 :             veh->getWeightsStorage().removeTravelTime(edge);
    2124              :         }
    2125              :     }
    2126          196 : }
    2127              : 
    2128              : 
    2129              : void
    2130           32 : Vehicle::setEffort(const std::string& vehID, const std::string& edgeID,
    2131              :                    double effort, double begSeconds, double endSeconds) {
    2132           32 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2133           32 :     MSEdge* edge = MSEdge::dictionary(edgeID);
    2134           32 :     if (edge == nullptr) {
    2135            0 :         throw TraCIException("Edge '" + edgeID + "' is not known.");
    2136              :     }
    2137           32 :     if (effort != INVALID_DOUBLE_VALUE) {
    2138              :         // add effort
    2139           23 :         if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
    2140              :             // clean up old values before setting whole range
    2141            9 :             while (veh->getWeightsStorage().knowsEffort(edge)) {
    2142            0 :                 veh->getWeightsStorage().removeEffort(edge);
    2143              :             }
    2144              :         }
    2145           23 :         veh->getWeightsStorage().addEffort(edge, begSeconds, endSeconds, effort);
    2146              :     } else {
    2147              :         // remove effort
    2148           18 :         while (veh->getWeightsStorage().knowsEffort(edge)) {
    2149            9 :             veh->getWeightsStorage().removeEffort(edge);
    2150              :         }
    2151              :     }
    2152           32 : }
    2153              : 
    2154              : 
    2155              : void
    2156          365 : Vehicle::rerouteTraveltime(const std::string& vehID, const bool currentTravelTimes) {
    2157          365 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2158          365 :     const int routingMode = veh->getRoutingMode();
    2159          365 :     if (currentTravelTimes && routingMode == ROUTING_MODE_DEFAULT) {
    2160              :         veh->setRoutingMode(ROUTING_MODE_AGGREGATED_CUSTOM);
    2161              :     }
    2162          365 :     veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteTraveltime",
    2163          365 :                  veh->getRouterTT(), isOnInit(vehID));
    2164          365 :     if (currentTravelTimes && routingMode == ROUTING_MODE_DEFAULT) {
    2165              :         veh->setRoutingMode(routingMode);
    2166              :     }
    2167          365 : }
    2168              : 
    2169              : 
    2170              : void
    2171           11 : Vehicle::rerouteEffort(const std::string& vehID) {
    2172           11 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2173           22 :     veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteEffort",
    2174           11 :                  MSNet::getInstance()->getRouterEffort(veh->getRNGIndex()), isOnInit(vehID));
    2175           11 : }
    2176              : 
    2177              : 
    2178              : void
    2179           20 : Vehicle::setSignals(const std::string& vehID, int signals) {
    2180           20 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2181           20 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    2182           20 :     if (veh == nullptr) {
    2183            1 :         WRITE_ERROR("setSignals not applicable for meso");
    2184            1 :         return;
    2185              :     }
    2186              : 
    2187              :     // set influencer to make the change persistent
    2188           19 :     veh->getInfluencer().setSignals(signals);
    2189              :     // set them now so that getSignals returns the correct value
    2190              :     veh->switchOffSignal(0x0fffffff);
    2191           19 :     if (signals >= 0) {
    2192              :         veh->switchOnSignal(signals);
    2193              :     }
    2194              : }
    2195              : 
    2196              : 
    2197              : void
    2198          508 : Vehicle::moveTo(const std::string& vehID, const std::string& laneID, double pos, int reason) {
    2199          508 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2200          508 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    2201          508 :     if (veh == nullptr) {
    2202           10 :         WRITE_WARNING("moveTo not yet implemented for meso");
    2203          375 :         return;
    2204              :     }
    2205              : 
    2206          498 :     MSLane* l = MSLane::dictionary(laneID);
    2207          498 :     if (l == nullptr) {
    2208            2 :         throw TraCIException("Unknown lane '" + laneID + "'.");
    2209              :     }
    2210          497 :     if (veh->getLane() == l) {
    2211          365 :         veh->setTentativeLaneAndPosition(l, pos, veh->getLateralPositionOnLane());
    2212          365 :         return;
    2213              :     }
    2214              :     MSEdge* destinationEdge = &l->getEdge();
    2215          132 :     const MSEdge* destinationRouteEdge = destinationEdge->getNormalBefore();
    2216          132 :     if (!veh->isOnRoad() && veh->getParameter().wasSet(VEHPARS_FORCE_REROUTE) && veh->getRoute().getEdges().size() == 2) {
    2217              :         // it's a trip that wasn't routeted yet (likely because the vehicle was added in this step. Find a route now
    2218           10 :         veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:moveTo-tripInsertion",
    2219              :                      veh->getRouterTT(), true);
    2220              :     }
    2221              :     // find edge in the remaining route
    2222          132 :     MSRouteIterator it = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), destinationRouteEdge);
    2223          132 :     if (it == veh->getRoute().end()) {
    2224              :         // find edge in the edges that were already passed
    2225           38 :         it = std::find(veh->getRoute().begin(), veh->getRoute().end(), destinationRouteEdge);
    2226              :     }
    2227          132 :     if (it == veh->getRoute().end() ||
    2228              :             // internal edge must continue the route
    2229           10 :             (destinationEdge->isInternal() &&
    2230           10 :              ((it + 1) == veh->getRoute().end()
    2231           10 :               || l->getNextNormal() != *(it + 1)))) {
    2232           32 :         throw TraCIException("Lane '" + laneID + "' is not on the route of vehicle '" + vehID + "'.");
    2233              :     }
    2234          116 :     Position oldPos = vehicle->getPosition();
    2235          116 :     veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
    2236          116 :     if (veh->getLane() != nullptr) {
    2237              :         // correct odometer which gets incremented via onRemovalFromNet->leaveLane
    2238           86 :         veh->addToOdometer(-veh->getLane()->getLength());
    2239           86 :         veh->getMutableLane()->removeVehicle(veh, MSMoveReminder::NOTIFICATION_TELEPORT, false);
    2240              :     } else {
    2241           30 :         veh->setTentativeLaneAndPosition(l, pos);
    2242              :     }
    2243          116 :     const int oldRouteIndex = veh->getRoutePosition();
    2244          116 :     const int newRouteIndex = (int)(it - veh->getRoute().begin());
    2245          116 :     if (oldRouteIndex > newRouteIndex) {
    2246              :         // more odometer correction needed
    2247              :         veh->addToOdometer(-l->getLength());
    2248              :     }
    2249          116 :     veh->resetRoutePosition(newRouteIndex, veh->getParameter().departLaneProcedure);
    2250          116 :     if (!veh->isOnRoad()) {
    2251          116 :         MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
    2252          116 :         MSVehicleTransfer::getInstance()->remove(veh);
    2253              :     }
    2254              :     MSMoveReminder::Notification moveReminderReason;
    2255          116 :     if (veh->hasDeparted()) {
    2256           86 :         if (reason == MOVE_TELEPORT) {
    2257              :             moveReminderReason = MSMoveReminder::NOTIFICATION_TELEPORT;
    2258           82 :         } else if (reason == MOVE_NORMAL) {
    2259              :             moveReminderReason = MSMoveReminder::NOTIFICATION_JUNCTION;
    2260           78 :         } else if (reason == MOVE_AUTOMATIC) {
    2261              :             Position newPos = l->geometryPositionAtOffset(pos);
    2262              :             const double dist = newPos.distanceTo2D(oldPos);
    2263           78 :             if (dist < SPEED2DIST(veh->getMaxSpeed())) {
    2264              :                 moveReminderReason = MSMoveReminder::NOTIFICATION_JUNCTION;
    2265              :             } else {
    2266              :                 moveReminderReason = MSMoveReminder::NOTIFICATION_TELEPORT;
    2267              :             }
    2268              :         } else {
    2269            0 :             throw TraCIException("Invalid moveTo reason '" + toString(reason) + "' for vehicle '" + vehID + "'.");
    2270              :         }
    2271              :     } else {
    2272              :         moveReminderReason = MSMoveReminder::NOTIFICATION_DEPARTED;
    2273              :     }
    2274          116 :     l->forceVehicleInsertion(veh, pos, moveReminderReason);
    2275              : }
    2276              : 
    2277              : 
    2278              : void
    2279           17 : Vehicle::setActionStepLength(const std::string& vehID, double actionStepLength, bool resetActionOffset) {
    2280           17 :     if (actionStepLength < 0.0) {
    2281            0 :         WRITE_ERROR("Invalid action step length (<0). Ignoring command setActionStepLength().");
    2282            0 :         return;
    2283              :     }
    2284           17 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2285           17 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
    2286           17 :     if (veh == nullptr) {
    2287            3 :         WRITE_ERROR("setActionStepLength not applicable for meso");
    2288            3 :         return;
    2289              :     }
    2290              : 
    2291           14 :     if (actionStepLength == 0.) {
    2292            0 :         veh->resetActionOffset();
    2293              :     } else {
    2294           14 :         veh->setActionStepLength(actionStepLength, resetActionOffset);
    2295              :     }
    2296              : }
    2297              : 
    2298              : 
    2299              : void
    2300            4 : Vehicle::setBoardingDuration(const std::string& vehID, double boardingDuration)  {
    2301              :     try {
    2302            4 :         checkTimeBounds(boardingDuration);
    2303            0 :     } catch (ProcessError&) {
    2304            0 :         throw TraCIException("BoardingDuration parameter exceeds the time value range.");
    2305            0 :     }
    2306            4 :     Helper::getVehicle(vehID)->getSingularType().setBoardingDuration(TIME2STEPS(boardingDuration));
    2307            4 : }
    2308              : 
    2309              : 
    2310              : void
    2311           27 : Vehicle::setImpatience(const std::string& vehID, double impatience)  {
    2312           27 :     MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
    2313           27 :     const double normalImpatience = vehicle->getImpatience();
    2314           27 :     vehicle->getBaseInfluencer().setExtraImpatience(impatience - normalImpatience);
    2315           27 : }
    2316              : 
    2317              : 
    2318              : void
    2319           30 : Vehicle::remove(const std::string& vehID, char reason) {
    2320           30 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2321              :     MSMoveReminder::Notification n = MSMoveReminder::NOTIFICATION_ARRIVED;
    2322              :     switch (reason) {
    2323              :         case REMOVE_TELEPORT:
    2324              :             // XXX semantics unclear
    2325              :             // n = MSMoveReminder::NOTIFICATION_TELEPORT;
    2326              :             n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
    2327              :             break;
    2328              :         case REMOVE_PARKING:
    2329              :             // XXX semantics unclear
    2330              :             // n = MSMoveReminder::NOTIFICATION_PARKING;
    2331              :             n = MSMoveReminder::NOTIFICATION_ARRIVED;
    2332              :             break;
    2333              :         case REMOVE_ARRIVED:
    2334              :             n = MSMoveReminder::NOTIFICATION_ARRIVED;
    2335              :             break;
    2336              :         case REMOVE_VAPORIZED:
    2337              :             n = MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI;
    2338              :             break;
    2339              :         case REMOVE_TELEPORT_ARRIVED:
    2340              :             n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
    2341              :             break;
    2342            0 :         default:
    2343            0 :             throw TraCIException("Unknown removal status.");
    2344              :     }
    2345           30 :     if (veh->hasDeparted()) {
    2346           26 :         veh->onRemovalFromNet(n);
    2347           26 :         MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    2348           26 :         if (microVeh != nullptr) {
    2349           24 :             if (veh->getLane() != nullptr) {
    2350           24 :                 microVeh->getMutableLane()->removeVehicle(dynamic_cast<MSVehicle*>(veh), n);
    2351              :             }
    2352           24 :             MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
    2353              :         }
    2354           26 :         MSNet::getInstance()->getVehicleControl().removePending();
    2355              :     } else {
    2356            4 :         MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
    2357            4 :         MSNet::getInstance()->getVehicleControl().deleteVehicle(veh, true);
    2358              :     }
    2359           30 : }
    2360              : 
    2361              : 
    2362              : void
    2363          179 : Vehicle::setColor(const std::string& vehID, const TraCIColor& col) {
    2364          179 :     const SUMOVehicleParameter& p = Helper::getVehicle(vehID)->getParameter();
    2365          179 :     p.color.set((unsigned char)col.r, (unsigned char)col.g, (unsigned char)col.b, (unsigned char)col.a);
    2366          179 :     p.parametersSet |= VEHPARS_COLOR_SET;
    2367          179 : }
    2368              : 
    2369              : 
    2370              : void
    2371         6497 : Vehicle::setSpeedFactor(const std::string& vehID, double factor) {
    2372         6497 :     Helper::getVehicle(vehID)->setChosenSpeedFactor(factor);
    2373         6497 : }
    2374              : 
    2375              : 
    2376              : void
    2377           14 : Vehicle::setLine(const std::string& vehID, const std::string& line) {
    2378           14 :     Helper::getVehicle(vehID)->getParameter().line = line;
    2379           14 : }
    2380              : 
    2381              : 
    2382              : void
    2383           19 : Vehicle::setVia(const std::string& vehID, const std::vector<std::string>& edgeList) {
    2384           19 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2385              :     try {
    2386              :         // ensure edges exist
    2387            0 :         ConstMSEdgeVector edges;
    2388           19 :         MSEdge::parseEdgesList(edgeList, edges, "<via-edges>");
    2389           19 :     } catch (ProcessError& e) {
    2390            0 :         throw TraCIException(e.what());
    2391            0 :     }
    2392           19 :     veh->getParameter().via = edgeList;
    2393           19 : }
    2394              : 
    2395              : 
    2396              : void
    2397           45 : Vehicle::setLength(const std::string& vehID, double length) {
    2398           45 :     Helper::getVehicle(vehID)->getSingularType().setLength(length);
    2399           45 : }
    2400              : 
    2401              : 
    2402              : void
    2403           17 : Vehicle::setMaxSpeed(const std::string& vehID, double speed) {
    2404           17 :     Helper::getVehicle(vehID)->getSingularType().setMaxSpeed(speed);
    2405           17 : }
    2406              : 
    2407              : 
    2408              : void
    2409            4 : Vehicle::setVehicleClass(const std::string& vehID, const std::string& clazz) {
    2410            4 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2411            4 :     veh->getSingularType().setVClass(getVehicleClassID(clazz));
    2412            4 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    2413            4 :     if (microVeh != nullptr && microVeh->isOnRoad()) {
    2414            4 :         microVeh->updateBestLanes(true);
    2415              :     }
    2416            4 : }
    2417              : 
    2418              : 
    2419              : void
    2420            4 : Vehicle::setShapeClass(const std::string& vehID, const std::string& clazz) {
    2421            4 :     Helper::getVehicle(vehID)->getSingularType().setShape(getVehicleShapeID(clazz));
    2422            4 : }
    2423              : 
    2424              : 
    2425              : void
    2426           10 : Vehicle::setEmissionClass(const std::string& vehID, const std::string& clazz) {
    2427           10 :     Helper::getVehicle(vehID)->getSingularType().setEmissionClass(PollutantsInterface::getClassByName(clazz));
    2428            9 : }
    2429              : 
    2430              : 
    2431              : void
    2432            5 : Vehicle::setWidth(const std::string& vehID, double width) {
    2433            5 :     Helper::getVehicle(vehID)->getSingularType().setWidth(width);
    2434            5 : }
    2435              : 
    2436              : 
    2437              : void
    2438            4 : Vehicle::setHeight(const std::string& vehID, double height) {
    2439            4 :     Helper::getVehicle(vehID)->getSingularType().setHeight(height);
    2440            4 : }
    2441              : 
    2442              : 
    2443              : void
    2444            4 : Vehicle::setMass(const std::string& vehID, double mass) {
    2445            4 :     Helper::getVehicle(vehID)->getSingularType().setMass(mass);
    2446            4 : }
    2447              : 
    2448              : 
    2449              : void
    2450           14 : Vehicle::setMinGap(const std::string& vehID, double minGap) {
    2451           14 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2452           14 :     veh->getSingularType().setMinGap(minGap);
    2453           14 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    2454           14 :     if (microVeh != nullptr && microVeh->isOnRoad()) {
    2455           12 :         microVeh->updateLaneBruttoSum();
    2456              :     }
    2457           14 : }
    2458              : 
    2459              : 
    2460              : void
    2461            9 : Vehicle::setAccel(const std::string& vehID, double accel) {
    2462            9 :     Helper::getVehicle(vehID)->getSingularType().setAccel(accel);
    2463            7 : }
    2464              : 
    2465              : 
    2466              : void
    2467            5 : Vehicle::setDecel(const std::string& vehID, double decel) {
    2468            5 :     VehicleType::setDecel(Helper::getVehicle(vehID)->getSingularType().getID(), decel);
    2469            5 : }
    2470              : 
    2471              : 
    2472              : void
    2473            9 : Vehicle::setEmergencyDecel(const std::string& vehID, double decel) {
    2474            9 :     VehicleType::setEmergencyDecel(Helper::getVehicle(vehID)->getSingularType().getID(), decel);
    2475            9 : }
    2476              : 
    2477              : 
    2478              : void
    2479            5 : Vehicle::setApparentDecel(const std::string& vehID, double decel) {
    2480            5 :     Helper::getVehicle(vehID)->getSingularType().setApparentDecel(decel);
    2481            5 : }
    2482              : 
    2483              : 
    2484              : void
    2485            9 : Vehicle::setImperfection(const std::string& vehID, double imperfection) {
    2486            9 :     Helper::getVehicle(vehID)->getSingularType().setImperfection(imperfection);
    2487            9 : }
    2488              : 
    2489              : 
    2490              : void
    2491            5 : Vehicle::setTau(const std::string& vehID, double tau) {
    2492            5 :     Helper::getVehicle(vehID)->getSingularType().setTau(tau);
    2493            5 : }
    2494              : 
    2495              : 
    2496              : void
    2497            9 : Vehicle::setMinGapLat(const std::string& vehID, double minGapLat) {
    2498              :     try {
    2499           18 :         setParameter(vehID, "laneChangeModel.minGapLat", toString(minGapLat));
    2500            5 :     } catch (TraCIException&) {
    2501              :         // legacy behavior
    2502            5 :         Helper::getVehicle(vehID)->getSingularType().setMinGapLat(minGapLat);
    2503            5 :     }
    2504            9 : }
    2505              : 
    2506              : 
    2507              : void
    2508            4 : Vehicle::setMaxSpeedLat(const std::string& vehID, double speed) {
    2509            4 :     Helper::getVehicle(vehID)->getSingularType().setMaxSpeedLat(speed);
    2510            4 : }
    2511              : 
    2512              : 
    2513              : void
    2514            4 : Vehicle::setLateralAlignment(const std::string& vehID, const std::string& latAlignment) {
    2515              :     double lao;
    2516              :     LatAlignmentDefinition lad;
    2517            4 :     if (SUMOVTypeParameter::parseLatAlignment(latAlignment, lao, lad)) {
    2518            4 :         Helper::getVehicle(vehID)->getSingularType().setPreferredLateralAlignment(lad, lao);
    2519              :     } else {
    2520            0 :         throw TraCIException("Unknown value '" + latAlignment + "' when setting latAlignment for vehID '" + vehID + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
    2521              :     }
    2522            4 : }
    2523              : 
    2524              : 
    2525              : void
    2526          478 : Vehicle::setParameter(const std::string& vehID, const std::string& key, const std::string& value) {
    2527          478 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2528          476 :     MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
    2529          952 :     if (StringUtils::startsWith(key, "device.")) {
    2530          624 :         StringTokenizer tok(key, ".");
    2531          208 :         if (tok.size() < 3) {
    2532            0 :             throw TraCIException("Invalid device parameter '" + key + "' for vehicle '" + vehID + "'");
    2533              :         }
    2534              :         try {
    2535          624 :             veh->setDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2), value);
    2536            0 :         } catch (InvalidArgument& e) {
    2537            0 :             throw TraCIException("Vehicle '" + vehID + "' does not support device parameter '" + key + "' (" + e.what() + ").");
    2538            0 :         }
    2539          744 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    2540           27 :         if (microVeh == nullptr) {
    2541            6 :             throw TraCIException("Meso Vehicle '" + vehID + "' does not support laneChangeModel parameters.");
    2542              :         }
    2543           24 :         const std::string attrName = key.substr(16);
    2544           28 :         if (attrName == toString(SUMO_ATTR_LCA_CONTRIGHT)) {
    2545              :             // special case: not used within lcModel
    2546            3 :             veh->getSingularType().setLcContRight(value);
    2547              :         } else {
    2548              :             try {
    2549           21 :                 microVeh->getLaneChangeModel().setParameter(attrName, value);
    2550            4 :             } catch (InvalidArgument& e) {
    2551            8 :                 throw TraCIException("Vehicle '" + vehID + "' does not support laneChangeModel parameter '" + key + "' (" + e.what() + ").");
    2552            4 :             }
    2553              :         }
    2554          482 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    2555           21 :         if (microVeh == nullptr) {
    2556            0 :             throw TraCIException("Meso Vehicle '" + vehID + "' does not support carFollowModel parameters.");
    2557              :         }
    2558              :         try {
    2559           21 :             veh->setCarFollowModelParameter(key, value);
    2560            5 :         } catch (InvalidArgument& e) {
    2561           10 :             throw TraCIException("Vehicle '" + vehID + "' does not support carFollowModel parameter '" + key + "' (" + e.what() + ").");
    2562            5 :         }
    2563          440 :     } else if (StringUtils::startsWith(key, "junctionModel.")) {
    2564              :         try {
    2565              :             // use the whole key (including junctionModel prefix)
    2566           10 :             veh->setJunctionModelParameter(key, value);
    2567            5 :         } catch (InvalidArgument& e) {
    2568              :             // error message includes id since it is also used for xml input
    2569           10 :             throw TraCIException(e.what());
    2570            5 :         }
    2571          219 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    2572           27 :         StringTokenizer tok(key, ".");
    2573            9 :         if (tok.size() != 3) {
    2574            0 :             throw TraCIException("Invalid request for device status change. Expected format is 'has.DEVICENAME.device'");
    2575              :         }
    2576            9 :         const std::string deviceName = tok.get(1);
    2577              :         bool create;
    2578              :         try {
    2579            9 :             create = StringUtils::toBool(value);
    2580            0 :         } catch (BoolFormatException&) {
    2581            0 :             throw TraCIException("Changing device status requires a 'true' or 'false'");
    2582            0 :         }
    2583            9 :         if (!create) {
    2584            0 :             throw TraCIException("Device removal is not supported for device of type '" + deviceName + "'");
    2585              :         }
    2586              :         try {
    2587            9 :             veh->createDevice(deviceName);
    2588            0 :         } catch (InvalidArgument& e) {
    2589            0 :             throw TraCIException("Cannot create vehicle device (" + std::string(e.what()) + ").");
    2590            0 :         }
    2591            9 :     } else {
    2592          201 :         ((SUMOVehicleParameter&)veh->getParameter()).setParameter(key, value);
    2593              :     }
    2594          459 : }
    2595              : 
    2596              : 
    2597              : void
    2598           42 : Vehicle::highlight(const std::string& vehID, const TraCIColor& col, double size, const int alphaMax, const double duration, const int type) {
    2599              : 
    2600              :     // NOTE: Code is duplicated in large parts in POI.cpp
    2601           42 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2602              : 
    2603              :     // Center of the highlight circle
    2604           42 :     Position center = veh->getPosition();
    2605           42 :     const double l2 = veh->getLength() * 0.5;
    2606           42 :     center.sub(cos(veh->getAngle())*l2, sin(veh->getAngle())*l2);
    2607              :     // Size of the highlight circle
    2608           42 :     if (size <= 0) {
    2609           42 :         size = veh->getLength() * 0.7;
    2610              :     }
    2611              :     // Make polygon shape
    2612              :     const unsigned int nPoints = 34;
    2613           42 :     const PositionVector circlePV = GeomHelper::makeRing(size, size + 1., center, nPoints);
    2614           42 :     TraCIPositionVector circle = Helper::makeTraCIPositionVector(circlePV);
    2615              : 
    2616              : #ifdef DEBUG_DYNAMIC_SHAPES
    2617              :     std::cout << SIMTIME << " Vehicle::highlight() for vehicle '" << vehID << "'\n"
    2618              :               << " circle: " << circlePV << std::endl;
    2619              : #endif
    2620              : 
    2621              :     // Find a free polygon id
    2622           42 :     int i = 0;
    2623           84 :     std::string polyID = veh->getID() + "_hl" + toString(i);
    2624          142 :     while (Polygon::exists(polyID)) {
    2625           16 :         polyID = veh->getID() + "_hl" + toString(++i);
    2626              :     }
    2627              :     // Line width
    2628              :     double lw = 0.;
    2629              :     // Layer
    2630              :     double lyr = 0.;
    2631           42 :     if (MSNet::getInstance()->isGUINet()) {
    2632              :         lyr = GLO_VEHICLE + 0.01;
    2633           16 :         lyr += (type + 1) / 257.;
    2634              :     }
    2635              :     // Make Polygon
    2636           84 :     Polygon::addHighlightPolygon(vehID, type, polyID, circle, col, true, "highlight", (int)lyr, lw);
    2637              : 
    2638              :     // Animation time line
    2639              :     double maxAttack = 1.0; // maximal fade-in time
    2640            0 :     std::vector<double> timeSpan;
    2641           42 :     if (duration > 0.) {
    2642           70 :         timeSpan = {0, MIN2(maxAttack, duration / 3.), 2.*duration / 3., duration};
    2643              :     }
    2644              :     // Alpha time line
    2645            0 :     std::vector<double> alphaSpan;
    2646           42 :     if (alphaMax > 0.) {
    2647           52 :         alphaSpan = {0., (double) alphaMax, (double)(alphaMax) / 3., 0.};
    2648              :     }
    2649              :     // Attach dynamics
    2650           42 :     Polygon::addDynamics(polyID, vehID, timeSpan, alphaSpan, false, true);
    2651           84 : }
    2652              : 
    2653              : void
    2654          227 : Vehicle::dispatchTaxi(const std::string& vehID,  const std::vector<std::string>& reservations) {
    2655          227 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
    2656          227 :     MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(veh->getDevice(typeid(MSDevice_Taxi)));
    2657          227 :     if (!veh->hasDeparted()) {
    2658           10 :         throw TraCIException("Vehicle '" + vehID + "' has not yet departed");
    2659              :     }
    2660          222 :     if (taxi == nullptr) {
    2661            0 :         throw TraCIException("Vehicle '" + vehID + "' is not a taxi");
    2662              :     }
    2663              :     MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
    2664          222 :     if (dispatcher == nullptr) {
    2665            0 :         throw TraCIException("Cannot dispatch taxi because no reservations have been made");
    2666              :     }
    2667          222 :     MSDispatch_TraCI* traciDispatcher = dynamic_cast<MSDispatch_TraCI*>(dispatcher);
    2668          222 :     if (traciDispatcher == nullptr) {
    2669           30 :         throw TraCIException("device.taxi.dispatch-algorithm 'traci' has not been loaded");
    2670              :     }
    2671          207 :     if (reservations.size() == 0) {
    2672            0 :         throw TraCIException("No reservations have been specified for vehicle '" + vehID + "'");
    2673              :     }
    2674              :     try {
    2675          207 :         traciDispatcher->interpretDispatch(taxi, reservations);
    2676            4 :     } catch (InvalidArgument& e) {
    2677            8 :         throw TraCIException("Could not interpret reservations for vehicle '" + vehID + "' (" + e.what() + ").");
    2678            4 :     }
    2679          203 : }
    2680              : 
    2681        31060 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Vehicle, VEHICLE)
    2682              : 
    2683              : 
    2684              : void
    2685           34 : Vehicle::subscribeLeader(const std::string& vehID, double dist, double begin, double end) {
    2686           34 :     subscribe(vehID, std::vector<int>({ libsumo::VAR_LEADER }), begin, end,
    2687          102 :     libsumo::TraCIResults({ {libsumo::VAR_LEADER, std::make_shared<libsumo::TraCIDouble>(dist)} }));
    2688           34 : }
    2689              : 
    2690              : 
    2691              : void
    2692           86 : Vehicle::addSubscriptionFilterLanes(const std::vector<int>& lanes, bool noOpposite, double downstreamDist, double upstreamDist) {
    2693           86 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_LANES);
    2694           86 :     if (s != nullptr) {
    2695           86 :         s->filterLanes = lanes;
    2696              :     }
    2697           86 :     if (noOpposite) {
    2698            2 :         addSubscriptionFilterNoOpposite();
    2699              :     }
    2700           86 :     if (downstreamDist != INVALID_DOUBLE_VALUE) {
    2701            4 :         addSubscriptionFilterDownstreamDistance(downstreamDist);
    2702              :     }
    2703           86 :     if (upstreamDist != INVALID_DOUBLE_VALUE) {
    2704            4 :         addSubscriptionFilterUpstreamDistance(upstreamDist);
    2705              :     }
    2706           86 : }
    2707              : 
    2708              : 
    2709              : void
    2710           28 : Vehicle::addSubscriptionFilterNoOpposite() {
    2711           28 :     Helper::addSubscriptionFilter(SUBS_FILTER_NOOPPOSITE);
    2712           28 : }
    2713              : 
    2714              : 
    2715              : void
    2716          102 : Vehicle::addSubscriptionFilterDownstreamDistance(double dist) {
    2717          102 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_DOWNSTREAM_DIST);
    2718          102 :     if (s != nullptr) {
    2719          102 :         s->filterDownstreamDist = dist;
    2720              :     }
    2721          102 : }
    2722              : 
    2723              : 
    2724              : void
    2725           86 : Vehicle::addSubscriptionFilterUpstreamDistance(double dist) {
    2726           86 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_UPSTREAM_DIST);
    2727           86 :     if (s != nullptr) {
    2728           86 :         s->filterUpstreamDist = dist;
    2729              :     }
    2730           86 : }
    2731              : 
    2732              : 
    2733              : void
    2734            2 : Vehicle::addSubscriptionFilterCFManeuver(double downstreamDist, double upstreamDist) {
    2735            2 :     addSubscriptionFilterLeadFollow(std::vector<int>({0}));
    2736            2 :     if (downstreamDist != INVALID_DOUBLE_VALUE) {
    2737            0 :         addSubscriptionFilterDownstreamDistance(downstreamDist);
    2738              :     }
    2739            2 :     if (upstreamDist != INVALID_DOUBLE_VALUE) {
    2740            0 :         addSubscriptionFilterUpstreamDistance(upstreamDist);
    2741              :     }
    2742              : 
    2743            2 : }
    2744              : 
    2745              : 
    2746              : void
    2747            8 : Vehicle::addSubscriptionFilterLCManeuver(int direction, bool noOpposite, double downstreamDist, double upstreamDist) {
    2748            0 :     std::vector<int> lanes;
    2749            8 :     if (direction == INVALID_INT_VALUE) {
    2750              :         // Using default: both directions
    2751            2 :         lanes = std::vector<int>({-1, 0, 1});
    2752            6 :     } else if (direction != -1 && direction != 1) {
    2753            0 :         WRITE_WARNINGF(TL("Ignoring lane change subscription filter with non-neighboring lane offset direction=%."), direction);
    2754              :     } else {
    2755            6 :         lanes = std::vector<int>({0, direction});
    2756              :     }
    2757            8 :     addSubscriptionFilterLeadFollow(lanes);
    2758            8 :     if (noOpposite) {
    2759            0 :         addSubscriptionFilterNoOpposite();
    2760              :     }
    2761            8 :     if (downstreamDist != INVALID_DOUBLE_VALUE) {
    2762            0 :         addSubscriptionFilterDownstreamDistance(downstreamDist);
    2763              :     }
    2764            8 :     if (upstreamDist != INVALID_DOUBLE_VALUE) {
    2765            0 :         addSubscriptionFilterUpstreamDistance(upstreamDist);
    2766              :     }
    2767            8 : }
    2768              : 
    2769              : 
    2770              : void
    2771           10 : Vehicle::addSubscriptionFilterLeadFollow(const std::vector<int>& lanes) {
    2772           10 :     Helper::addSubscriptionFilter(SUBS_FILTER_LEAD_FOLLOW);
    2773           10 :     addSubscriptionFilterLanes(lanes);
    2774           10 : }
    2775              : 
    2776              : 
    2777              : void
    2778           16 : Vehicle::addSubscriptionFilterTurn(double downstreamDist, double foeDistToJunction) {
    2779           16 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_TURN);
    2780           16 :     if (downstreamDist != INVALID_DOUBLE_VALUE) {
    2781           16 :         addSubscriptionFilterDownstreamDistance(downstreamDist);
    2782              :     }
    2783           16 :     if (foeDistToJunction != INVALID_DOUBLE_VALUE) {
    2784           16 :         s->filterFoeDistToJunction = foeDistToJunction;
    2785              :     }
    2786           16 : }
    2787              : 
    2788              : 
    2789              : void
    2790            6 : Vehicle::addSubscriptionFilterVClass(const std::vector<std::string>& vClasses) {
    2791            6 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_VCLASS);
    2792            6 :     if (s != nullptr) {
    2793            6 :         s->filterVClasses = parseVehicleClasses(vClasses);
    2794              :     }
    2795            6 : }
    2796              : 
    2797              : 
    2798              : void
    2799            6 : Vehicle::addSubscriptionFilterVType(const std::vector<std::string>& vTypes) {
    2800            6 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_VTYPE);
    2801            6 :     if (s != nullptr) {
    2802              :         s->filterVTypes.insert(vTypes.begin(), vTypes.end());
    2803              :     }
    2804            6 : }
    2805              : 
    2806              : 
    2807              : void
    2808           16 : Vehicle::addSubscriptionFilterFieldOfVision(double openingAngle) {
    2809           16 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_FIELD_OF_VISION);
    2810           16 :     if (s != nullptr) {
    2811           16 :         s->filterFieldOfVisionOpeningAngle = openingAngle;
    2812              :     }
    2813           16 : }
    2814              : 
    2815              : 
    2816              : void
    2817           15 : Vehicle::addSubscriptionFilterLateralDistance(double lateralDist, double downstreamDist, double upstreamDist) {
    2818           15 :     Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_LATERAL_DIST);
    2819           14 :     if (s != nullptr) {
    2820           14 :         s->filterLateralDist = lateralDist;
    2821              :     }
    2822           14 :     if (downstreamDist != INVALID_DOUBLE_VALUE) {
    2823           14 :         addSubscriptionFilterDownstreamDistance(downstreamDist);
    2824              :     }
    2825           14 :     if (upstreamDist != INVALID_DOUBLE_VALUE) {
    2826           14 :         addSubscriptionFilterUpstreamDistance(upstreamDist);
    2827              :     }
    2828           14 : }
    2829              : 
    2830              : 
    2831              : void
    2832        17164 : Vehicle::storeShape(const std::string& id, PositionVector& shape) {
    2833        17164 :     shape.push_back(Helper::getVehicle(id)->getPosition());
    2834        17164 : }
    2835              : 
    2836              : 
    2837              : std::shared_ptr<VariableWrapper>
    2838          271 : Vehicle::makeWrapper() {
    2839          271 :     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
    2840              : }
    2841              : 
    2842              : 
    2843              : bool
    2844      9901884 : Vehicle::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
    2845      9901884 :     switch (variable) {
    2846       126503 :         case TRACI_ID_LIST:
    2847       126503 :             return wrapper->wrapStringList(objID, variable, getIDList());
    2848           93 :         case ID_COUNT:
    2849           93 :             return wrapper->wrapInt(objID, variable, getIDCount());
    2850      1007183 :         case VAR_POSITION:
    2851      1007183 :             return wrapper->wrapPosition(objID, variable, getPosition(objID));
    2852         1284 :         case VAR_POSITION3D:
    2853         1284 :             return wrapper->wrapPosition(objID, variable, getPosition(objID, true));
    2854          267 :         case VAR_ANGLE:
    2855          267 :             return wrapper->wrapDouble(objID, variable, getAngle(objID));
    2856       169652 :         case VAR_SPEED:
    2857       169652 :             return wrapper->wrapDouble(objID, variable, getSpeed(objID));
    2858           54 :         case VAR_SPEED_LAT:
    2859           54 :             return wrapper->wrapDouble(objID, variable, getLateralSpeed(objID));
    2860      4213558 :         case VAR_ROAD_ID:
    2861      8427116 :             return wrapper->wrapString(objID, variable, getRoadID(objID));
    2862         2083 :         case VAR_SPEED_WITHOUT_TRACI:
    2863         2083 :             return wrapper->wrapDouble(objID, variable, getSpeedWithoutTraCI(objID));
    2864           14 :         case VAR_SLOPE:
    2865           14 :             return wrapper->wrapDouble(objID, variable, getSlope(objID));
    2866        34200 :         case VAR_LANE_ID:
    2867        68391 :             return wrapper->wrapString(objID, variable, getLaneID(objID));
    2868        30155 :         case VAR_LANE_INDEX:
    2869        30155 :             return wrapper->wrapInt(objID, variable, getLaneIndex(objID));
    2870           74 :         case VAR_SEGMENT_ID:
    2871          145 :             return wrapper->wrapString(objID, variable, getSegmentID(objID));
    2872           71 :         case VAR_SEGMENT_INDEX:
    2873           71 :             return wrapper->wrapInt(objID, variable, getSegmentIndex(objID));
    2874          218 :         case VAR_TYPE:
    2875          431 :             return wrapper->wrapString(objID, variable, getTypeID(objID));
    2876           83 :         case VAR_ROUTE_ID:
    2877          161 :             return wrapper->wrapString(objID, variable, getRouteID(objID));
    2878           53 :         case VAR_DEPARTURE:
    2879           53 :             return wrapper->wrapDouble(objID, variable, getDeparture(objID));
    2880           53 :         case VAR_DEPART_DELAY:
    2881           53 :             return wrapper->wrapDouble(objID, variable, getDepartDelay(objID));
    2882         2017 :         case VAR_ROUTE_INDEX:
    2883         2017 :             return wrapper->wrapInt(objID, variable, getRouteIndex(objID));
    2884          603 :         case VAR_COLOR:
    2885          603 :             return wrapper->wrapColor(objID, variable, getColor(objID));
    2886      4193023 :         case VAR_LANEPOSITION:
    2887      4193023 :             return wrapper->wrapDouble(objID, variable, getLanePosition(objID));
    2888         1975 :         case VAR_LANEPOSITION_LAT:
    2889         1975 :             return wrapper->wrapDouble(objID, variable, getLateralLanePosition(objID));
    2890          255 :         case VAR_CO2EMISSION:
    2891          255 :             return wrapper->wrapDouble(objID, variable, getCO2Emission(objID));
    2892           55 :         case VAR_COEMISSION:
    2893           55 :             return wrapper->wrapDouble(objID, variable, getCOEmission(objID));
    2894           55 :         case VAR_HCEMISSION:
    2895           55 :             return wrapper->wrapDouble(objID, variable, getHCEmission(objID));
    2896           55 :         case VAR_PMXEMISSION:
    2897           55 :             return wrapper->wrapDouble(objID, variable, getPMxEmission(objID));
    2898           55 :         case VAR_NOXEMISSION:
    2899           55 :             return wrapper->wrapDouble(objID, variable, getNOxEmission(objID));
    2900          265 :         case VAR_FUELCONSUMPTION:
    2901          265 :             return wrapper->wrapDouble(objID, variable, getFuelConsumption(objID));
    2902           55 :         case VAR_NOISEEMISSION:
    2903           55 :             return wrapper->wrapDouble(objID, variable, getNoiseEmission(objID));
    2904          103 :         case VAR_ELECTRICITYCONSUMPTION:
    2905          103 :             return wrapper->wrapDouble(objID, variable, getElectricityConsumption(objID));
    2906          278 :         case VAR_PERSON_NUMBER:
    2907          278 :             return wrapper->wrapInt(objID, variable, getPersonNumber(objID));
    2908          291 :         case VAR_PERSON_CAPACITY:
    2909          291 :             return wrapper->wrapInt(objID, variable, getPersonCapacity(objID));
    2910           53 :         case VAR_BOARDING_DURATION:
    2911           53 :             return wrapper->wrapDouble(objID, variable, getBoardingDuration(objID));
    2912          114 :         case LAST_STEP_PERSON_ID_LIST:
    2913          114 :             return wrapper->wrapStringList(objID, variable, getPersonIDList(objID));
    2914          147 :         case VAR_WAITING_TIME:
    2915          147 :             return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
    2916           75 :         case VAR_ACCUMULATED_WAITING_TIME:
    2917           75 :             return wrapper->wrapDouble(objID, variable, getAccumulatedWaitingTime(objID));
    2918              :         case VAR_EDGE_TRAVELTIME: {
    2919           73 :             StoHelp::readCompound(*paramData);
    2920           73 :             const double time = StoHelp::readTypedDouble(*paramData);
    2921          146 :             return wrapper->wrapDouble(objID, variable, getAdaptedTraveltime(objID, time, StoHelp::readTypedString(*paramData)));
    2922              :         }
    2923              :         case VAR_EDGE_EFFORT: {
    2924           71 :             StoHelp::readCompound(*paramData);
    2925           71 :             const double time = StoHelp::readTypedDouble(*paramData);
    2926          142 :             return wrapper->wrapDouble(objID, variable, getEffort(objID, time, StoHelp::readTypedString(*paramData)));
    2927              :         }
    2928           54 :         case VAR_ROUTE_VALID:
    2929           54 :             return wrapper->wrapInt(objID, variable, isRouteValid(objID));
    2930         2187 :         case VAR_EDGES:
    2931         2187 :             return wrapper->wrapStringList(objID, variable, getRoute(objID));
    2932           56 :         case VAR_SIGNALS:
    2933           56 :             return wrapper->wrapInt(objID, variable, getSignals(objID));
    2934           58 :         case VAR_BEST_LANES:
    2935           58 :             return wrapper->wrapBestLanesDataVector(objID, variable, getBestLanes(objID));
    2936           35 :         case VAR_NEXT_LINKS:
    2937           35 :             return wrapper->wrapConnectionVector(objID, variable, getNextLinks(objID));
    2938         1151 :         case VAR_STOPSTATE:
    2939         1151 :             return wrapper->wrapInt(objID, variable, getStopState(objID));
    2940          384 :         case VAR_DISTANCE:
    2941          384 :             return wrapper->wrapDouble(objID, variable, getDistance(objID));
    2942           53 :         case VAR_REFERENCE_DISTANCE:
    2943           53 :             return wrapper->wrapDouble(objID, variable, getReferenceDistance(objID));
    2944           53 :         case VAR_ALLOWED_SPEED:
    2945           53 :             return wrapper->wrapDouble(objID, variable, getAllowedSpeed(objID));
    2946          118 :         case VAR_SPEED_FACTOR:
    2947          118 :             return wrapper->wrapDouble(objID, variable, getSpeedFactor(objID));
    2948           46 :         case VAR_SPEEDSETMODE:
    2949           46 :             return wrapper->wrapInt(objID, variable, getSpeedMode(objID));
    2950          148 :         case VAR_LANECHANGE_MODE:
    2951          148 :             return wrapper->wrapInt(objID, variable, getLaneChangeMode(objID));
    2952          151 :         case VAR_ROUTING_MODE:
    2953          151 :             return wrapper->wrapInt(objID, variable, getRoutingMode(objID));
    2954           54 :         case VAR_LINE:
    2955          108 :             return wrapper->wrapString(objID, variable, getLine(objID));
    2956           54 :         case VAR_VIA:
    2957           54 :             return wrapper->wrapStringList(objID, variable, getVia(objID));
    2958         2686 :         case VAR_ACCELERATION:
    2959         2686 :             return wrapper->wrapDouble(objID, variable, getAcceleration(objID));
    2960           53 :         case VAR_LASTACTIONTIME:
    2961           53 :             return wrapper->wrapDouble(objID, variable, getLastActionTime(objID));
    2962         1616 :         case VAR_STOP_DELAY:
    2963         1616 :             return wrapper->wrapDouble(objID, variable, getStopDelay(objID));
    2964           68 :         case VAR_IMPATIENCE:
    2965           68 :             return wrapper->wrapDouble(objID, variable, getImpatience(objID));
    2966         1615 :         case VAR_STOP_ARRIVALDELAY:
    2967         1615 :             return wrapper->wrapDouble(objID, variable, getStopArrivalDelay(objID));
    2968           53 :         case VAR_TIMELOSS:
    2969           53 :             return wrapper->wrapDouble(objID, variable, getTimeLoss(objID));
    2970           53 :         case VAR_MINGAP_LAT:
    2971           53 :             return wrapper->wrapDouble(objID, variable, getMinGapLat(objID));
    2972        31298 :         case VAR_LEADER:
    2973        62596 :             return wrapper->wrapStringDoublePair(objID, variable, getLeader(objID, StoHelp::readTypedDouble(*paramData)));
    2974          184 :         case VAR_FOLLOWER:
    2975          365 :             return wrapper->wrapStringDoublePair(objID, variable, getFollower(objID, StoHelp::readTypedDouble(*paramData)));
    2976          129 :         case VAR_LOADED_LIST:
    2977          129 :             return wrapper->wrapStringList(objID, variable, getLoadedIDList());
    2978          104 :         case VAR_TELEPORTING_LIST:
    2979          104 :             return wrapper->wrapStringList(objID, variable, getTeleportingIDList());
    2980              :         case VAR_FOLLOW_SPEED: {
    2981          363 :             StoHelp::readCompound(*paramData);
    2982          363 :             const double speed = StoHelp::readTypedDouble(*paramData);
    2983          363 :             const double gap = StoHelp::readTypedDouble(*paramData);
    2984          363 :             const double leaderSpeed = StoHelp::readTypedDouble(*paramData);
    2985          363 :             const double leaderMaxDecel = StoHelp::readTypedDouble(*paramData);
    2986          726 :             return wrapper->wrapDouble(objID, variable, getFollowSpeed(objID, speed, gap, leaderSpeed, leaderMaxDecel, StoHelp::readTypedString(*paramData)));
    2987              :         }
    2988              :         case VAR_SECURE_GAP: {
    2989           13 :             StoHelp::readCompound(*paramData);
    2990           13 :             const double speed = StoHelp::readTypedDouble(*paramData);
    2991           13 :             const double leaderSpeed = StoHelp::readTypedDouble(*paramData);
    2992           13 :             const double leaderMaxDecel = StoHelp::readTypedDouble(*paramData);
    2993           26 :             return wrapper->wrapDouble(objID, variable, getSecureGap(objID, speed, leaderSpeed, leaderMaxDecel, StoHelp::readTypedString(*paramData)));
    2994              :         }
    2995              :         case VAR_STOP_SPEED: {
    2996           13 :             StoHelp::readCompound(*paramData);
    2997           13 :             const double speed = StoHelp::readTypedDouble(*paramData);
    2998           26 :             return wrapper->wrapDouble(objID, variable, getStopSpeed(objID, speed, StoHelp::readTypedDouble(*paramData)));
    2999              :         }
    3000           98 :         case VAR_FOES:
    3001          196 :             return wrapper->wrapJunctionFoeVector(objID, variable, getJunctionFoes(objID, StoHelp::readTypedDouble(*paramData)));
    3002         2576 :         case VAR_NEIGHBORS:
    3003         5152 :             return wrapper->wrapStringDoublePairList(objID, variable, getNeighbors(objID, StoHelp::readTypedByte(*paramData)));
    3004         9385 :         case CMD_CHANGELANE:
    3005        18770 :             return wrapper->wrapIntPair(objID, variable, getLaneChangeState(objID, StoHelp::readTypedInt(*paramData)));
    3006              :         case VAR_STOP_PARAMETER: {
    3007          259 :             const int count = StoHelp::readCompound(*paramData);
    3008          259 :             const int nextStopIndex = StoHelp::readTypedInt(*paramData);
    3009          259 :             const std::string param = StoHelp::readTypedString(*paramData);
    3010          512 :             const bool customParam = count == 3 && StoHelp::readTypedByte(*paramData) != 0;
    3011          518 :             return wrapper->wrapString(objID, variable, getStopParameter(objID, nextStopIndex, param, customParam));
    3012              :         }
    3013          817 :         case VAR_NEXT_TLS:
    3014          817 :             return wrapper->wrapNextTLSDataVector(objID, variable, getNextTLS(objID));
    3015           41 :         case VAR_NEXT_STOPS:
    3016           41 :             return wrapper->wrapNextStopDataVector(objID, variable, getNextStops(objID));
    3017         2398 :         case VAR_NEXT_STOPS2:
    3018         4793 :             return wrapper->wrapNextStopDataVector(objID, variable, getStops(objID, StoHelp::readTypedInt(*paramData)));
    3019              :         case DISTANCE_REQUEST: {
    3020         3628 :             TraCIRoadPosition roadPos;
    3021              :             Position pos;
    3022         1814 :             if (Helper::readDistanceRequest(*paramData, roadPos, pos) == libsumo::POSITION_ROADMAP) {
    3023         1757 :                 return wrapper->wrapDouble(objID, variable, getDrivingDistance(objID, roadPos.edgeID, roadPos.pos, roadPos.laneIndex));
    3024              :             }
    3025           55 :             return wrapper->wrapDouble(objID, variable, getDrivingDistance2D(objID, pos.x(), pos.y()));
    3026              :         }
    3027         6093 :         case VAR_TAXI_FLEET:
    3028        12186 :             return wrapper->wrapStringList(objID, variable, getTaxiFleet(StoHelp::readTypedInt(*paramData)));
    3029        47912 :         case VAR_PARAMETER:
    3030        95802 :             return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
    3031           48 :         case VAR_PARAMETER_WITH_KEY:
    3032           96 :             return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
    3033         2377 :         default:
    3034         4754 :             return VehicleType::handleVariableWithID(objID, getTypeID(objID), variable, wrapper, paramData);
    3035              :     }
    3036              : }
    3037              : 
    3038              : 
    3039              : }
    3040              : 
    3041              : 
    3042              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1