LCOV - code coverage report
Current view: top level - src/libsumo - Vehicle.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 1389 1549 89.7 %
Date: 2024-04-27 15:34:54 Functions: 181 183 98.9 %

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

Generated by: LCOV version 1.14