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

Generated by: LCOV version 2.0-1