LCOV - code coverage report
Current view: top level - src/libsumo - Vehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.0 % 1663 1514
Test Date: 2025-11-13 15:38:19 Functions: 99.5 % 187 186

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

Generated by: LCOV version 2.0-1