LCOV - code coverage report
Current view: top level - src/libsumo - Person.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 74.7 % 683 510
Test Date: 2025-11-13 15:38:19 Functions: 65.3 % 101 66

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2017-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    Person.cpp
      15              : /// @author  Leonhard Luecken
      16              : /// @date    15.09.2017
      17              : ///
      18              : // C++ TraCI client API implementation
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <microsim/transportables/MSTransportableControl.h>
      23              : #include <microsim/MSVehicleControl.h>
      24              : #include <microsim/MSEdge.h>
      25              : #include <microsim/MSLane.h>
      26              : #include <microsim/MSNet.h>
      27              : #include <microsim/MSStoppingPlace.h>
      28              : #include <microsim/transportables/MSPModel.h>
      29              : #include <microsim/transportables/MSPerson.h>
      30              : #include <microsim/transportables/MSStageDriving.h>
      31              : #include <microsim/transportables/MSStageWaiting.h>
      32              : #include <microsim/transportables/MSStageWalking.h>
      33              : #include <microsim/transportables/MSStageTrip.h>
      34              : #include <microsim/devices/MSDevice_Taxi.h>
      35              : #include <microsim/devices/MSDispatch_TraCI.h>
      36              : #include <libsumo/TraCIConstants.h>
      37              : #include <utils/geom/GeomHelper.h>
      38              : #include <utils/common/StringTokenizer.h>
      39              : #include <utils/common/SUMOTime.h>
      40              : #include <utils/emissions/PollutantsInterface.h>
      41              : #include <utils/router/PedestrianRouter.h>
      42              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      43              : #include "Helper.h"
      44              : #include "StorageHelper.h"
      45              : #include "VehicleType.h"
      46              : #include "Person.h"
      47              : 
      48              : #define FAR_AWAY 1000.0
      49              : 
      50              : //#define DEBUG_MOVEXY
      51              : //#define DEBUG_MOVEXY_ANGLE
      52              : 
      53              : namespace libsumo {
      54              : // ===========================================================================
      55              : // static member initializations
      56              : // ===========================================================================
      57              : SubscriptionResults Person::mySubscriptionResults;
      58              : ContextSubscriptionResults Person::myContextSubscriptionResults;
      59              : 
      60              : 
      61              : // ===========================================================================
      62              : // static member definitions
      63              : // ===========================================================================
      64              : std::vector<std::string>
      65        59208 : Person::getIDList() {
      66        59208 :     MSTransportableControl& c = MSNet::getInstance()->getPersonControl();
      67              :     std::vector<std::string> ids;
      68       158474 :     for (MSTransportableControl::constVehIt i = c.loadedBegin(); i != c.loadedEnd(); ++i) {
      69        99268 :         if (i->second->getCurrentStageType() != MSStageType::WAITING_FOR_DEPART) {
      70        99251 :             ids.push_back(i->first);
      71              :         }
      72              :     }
      73        59206 :     return ids;
      74            0 : }
      75              : 
      76              : 
      77              : int
      78           30 : Person::getIDCount() {
      79           30 :     return MSNet::getInstance()->getPersonControl().size();
      80              : }
      81              : 
      82              : 
      83              : TraCIPosition
      84       127146 : Person::getPosition(const std::string& personID, const bool includeZ) {
      85       127146 :     return Helper::makeTraCIPosition(getPerson(personID)->getPosition(), includeZ);
      86              : }
      87              : 
      88              : 
      89              : TraCIPosition
      90            4 : Person::getPosition3D(const std::string& personID) {
      91            4 :     return Helper::makeTraCIPosition(getPerson(personID)->getPosition(), true);
      92              : }
      93              : 
      94              : 
      95              : double
      96          121 : Person::getAngle(const std::string& personID) {
      97          121 :     return GeomHelper::naviDegree(getPerson(personID)->getAngle());
      98              : }
      99              : 
     100              : 
     101              : double
     102           19 : Person::getSlope(const std::string& personID) {
     103           19 :     MSPerson* person = getPerson(personID);
     104           19 :     const double ep = person->getEdgePos();
     105           19 :     const MSLane* lane = getSidewalk<MSEdge, MSLane>(person->getEdge());
     106           19 :     if (lane == nullptr) {
     107            0 :         lane = person->getEdge()->getLanes()[0];
     108              :     }
     109              :     const double gp = lane->interpolateLanePosToGeometryPos(ep);
     110           19 :     return lane->getShape().slopeDegreeAtOffset(gp);
     111              : }
     112              : 
     113              : 
     114              : double
     115           43 : Person::getSpeed(const std::string& personID) {
     116           43 :     return getPerson(personID)->getSpeed();
     117              : }
     118              : 
     119              : 
     120              : std::string
     121         1242 : Person::getRoadID(const std::string& personID) {
     122         1242 :     return getPerson(personID)->getEdge()->getID();
     123              : }
     124              : 
     125              : 
     126              : std::string
     127          261 : Person::getLaneID(const std::string& personID) {
     128          522 :     return Named::getIDSecure(getPerson(personID)->getLane(), "");
     129              : }
     130              : 
     131              : 
     132              : double
     133          121 : Person::getLanePosition(const std::string& personID) {
     134          121 :     return getPerson(personID)->getEdgePos();
     135              : }
     136              : 
     137              : 
     138              : double
     139           28 : Person::getWalkingDistance(const std::string& personID, const std::string& edgeID, double pos, int laneIndex) {
     140           28 :     MSPerson* p = getPerson(personID);
     141           28 :     if (p->getCurrentStageType() == MSStageType::WALKING) {
     142           24 :         const MSStageWalking* walk = dynamic_cast<const MSStageWalking*>(p->getCurrentStage());
     143           24 :         ConstMSEdgeVector edges = walk->getEdges();
     144           24 :         edges.erase(edges.begin(), edges.begin() + walk->getRoutePosition());
     145           24 :         const MSLane* lane = Helper::getLaneChecking(edgeID, laneIndex, pos);
     146           24 :         auto it = std::find(edges.begin(), edges.end(), &lane->getEdge());
     147           24 :         if (it == edges.end()) {
     148              :             // Vehicle would return INVALID_DOUBLE_VALUE;
     149            0 :             throw TraCIException(TLF("Edge '%' does not occur within the remaining walk of person '%'.", edgeID, personID));
     150              : 
     151              :         }
     152              :         edges.erase(it + 1, edges.end());
     153           24 :         double distance = 0;
     154           24 :         MSPedestrianRouter& router = MSNet::getInstance()->getPedestrianRouter(0);
     155           24 :         router.recomputeWalkCosts(edges, p->getMaxSpeed(), p->getEdgePos(), pos, SIMSTEP, p->getVTypeParameter(), distance);
     156           24 :         if (distance == std::numeric_limits<double>::max()) {
     157              :             return INVALID_DOUBLE_VALUE;
     158              :         }
     159           24 :         return distance;
     160           24 :     } else {
     161              :         // Vehicle would return INVALID_DOUBLE_VALUE;
     162           12 :         throw TraCIException(TLF("Person '%' is not walking", personID));
     163              :     }
     164              : }
     165              : 
     166              : 
     167              : double
     168           12 : Person::getWalkingDistance2D(const std::string& personID, double x, double y) {
     169           12 :     MSPerson* p = getPerson(personID);
     170           12 :     std::pair<MSLane*, double> roadPos = Helper::convertCartesianToRoadMap(Position(x, y), p->getVehicleType().getVehicleClass());
     171           12 :     return getWalkingDistance(personID, roadPos.first->getEdge().getID(), roadPos.second, roadPos.first->getIndex());
     172              : }
     173              : 
     174              : 
     175              : 
     176              : std::vector<TraCIReservation>
     177         4849 : Person::getTaxiReservations(int onlyNew) {
     178              :     std::vector<TraCIReservation> result;
     179              :     MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
     180         4849 :     if (dispatcher != nullptr) {
     181         8463 :         for (Reservation* res : dispatcher->getReservations()) {
     182         3622 :             if (filterReservation(onlyNew, res, result)) {
     183         2900 :                 if (res->state == Reservation::NEW) {
     184          358 :                     res->state = Reservation::RETRIEVED;
     185              :                 }
     186              :             }
     187         4841 :         }
     188         4841 :         const bool includeRunning = onlyNew == 0 || (onlyNew & (Reservation::ASSIGNED | Reservation::ONBOARD)) != 0;
     189              :         if (includeRunning) {
     190         9551 :             for (const Reservation* res : dispatcher->getRunningReservations()) {
     191         5337 :                 filterReservation(onlyNew, res, result);
     192         4214 :             }
     193              :         }
     194              :     }
     195         4849 :     std::sort(result.begin(), result.end(), reservation_by_id_sorter());
     196         4849 :     return result;
     197            0 : }
     198              : 
     199              : int
     200         8698 : Person::reservation_by_id_sorter::operator()(const TraCIReservation& r1, const TraCIReservation& r2) const {
     201         8698 :     return r1.id < r2.id;
     202              : }
     203              : 
     204              : 
     205              : std::string
     206            5 : Person::splitTaxiReservation(std::string reservationID, const std::vector<std::string>& personIDs) {
     207              :     MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
     208            5 :     if (dispatcher != nullptr) {
     209            5 :         MSDispatch_TraCI* traciDispatcher = dynamic_cast<MSDispatch_TraCI*>(dispatcher);
     210            5 :         if (traciDispatcher != nullptr) {
     211           15 :             return traciDispatcher->splitReservation(reservationID, personIDs);
     212              :         }
     213              :     }
     214            0 :     throw TraCIException("device.taxi.dispatch-algorithm 'traci' has not been loaded");
     215              : }
     216              : 
     217              : bool
     218         8959 : Person::filterReservation(int onlyNew, const Reservation* res, std::vector<libsumo::TraCIReservation>& reservations) {
     219         8959 :     if (onlyNew != 0 && (onlyNew & res->state) == 0) {
     220              :         return false;
     221              :     }
     222              :     std::vector<std::string> personIDs;
     223        16225 :     for (const MSTransportable* p : res->persons) {
     224         8125 :         personIDs.push_back(p->getID());
     225              :     }
     226         8100 :     std::sort(personIDs.begin(), personIDs.end());
     227         8100 :     reservations.push_back(TraCIReservation(res->id,
     228              :                                             personIDs,
     229         8100 :                                             res->group,
     230         8100 :                                             res->from->getID(),
     231         8100 :                                             res->to->getID(),
     232         8100 :                                             res->fromPos,
     233         8100 :                                             res->toPos,
     234         8100 :                                             STEPS2TIME(res->pickupTime),
     235         8100 :                                             STEPS2TIME(res->reservationTime),
     236         8100 :                                             res->state
     237              :                                            ));
     238              :     return true;
     239         8100 : }
     240              : 
     241              : 
     242              : TraCIColor
     243           21 : Person::getColor(const std::string& personID) {
     244           21 :     const RGBColor& col = getPerson(personID)->getParameter().color;
     245              :     TraCIColor tcol;
     246           21 :     tcol.r = col.red();
     247           21 :     tcol.g = col.green();
     248           21 :     tcol.b = col.blue();
     249           21 :     tcol.a = col.alpha();
     250           21 :     return tcol;
     251              : }
     252              : 
     253              : 
     254              : std::string
     255          235 : Person::getTypeID(const std::string& personID) {
     256          235 :     return getPerson(personID)->getVehicleType().getID();
     257              : }
     258              : 
     259              : 
     260              : double
     261          612 : Person::getWaitingTime(const std::string& personID) {
     262          612 :     return getPerson(personID)->getWaitingSeconds();
     263              : }
     264              : 
     265              : 
     266              : std::string
     267           84 : Person::getNextEdge(const std::string& personID) {
     268           84 :     return getPerson(personID)->getNextEdge();
     269              : }
     270              : 
     271              : 
     272              : std::vector<std::string>
     273         1151 : Person::getEdges(const std::string& personID, int nextStageIndex) {
     274         1151 :     MSTransportable* p = getPerson(personID);
     275         1151 :     if (nextStageIndex >= p->getNumRemainingStages()) {
     276            0 :         throw TraCIException("The stage index must be lower than the number of remaining stages.");
     277              :     }
     278         1151 :     if (nextStageIndex < (p->getNumRemainingStages() - p->getNumStages())) {
     279            0 :         throw TraCIException("The negative stage index must refer to a valid previous stage.");
     280              :     }
     281              :     std::vector<std::string> edgeIDs;
     282         3047 :     for (auto& e : p->getNextStage(nextStageIndex)->getEdges()) {
     283         1896 :         if (e != nullptr) {
     284         1896 :             edgeIDs.push_back(e->getID());
     285              :         }
     286         1151 :     }
     287         1151 :     return edgeIDs;
     288            0 : }
     289              : 
     290              : 
     291              : TraCIStage
     292          797 : Person::getStage(const std::string& personID, int nextStageIndex) {
     293          797 :     MSTransportable* p = getPerson(personID);
     294         1586 :     TraCIStage result;
     295          793 :     if (nextStageIndex >= p->getNumRemainingStages()) {
     296           10 :         throw TraCIException("The stage index must be lower than the number of remaining stages.");
     297              :     }
     298          788 :     if (nextStageIndex < (p->getNumRemainingStages() - p->getNumStages())) {
     299          106 :         throw TraCIException("The negative stage index " + toString(nextStageIndex) + " must refer to a valid previous stage.");
     300              :     }
     301              :     //stageType, arrivalPos, edges, destStop, vType, and description can be retrieved directly from the base Stage class.
     302              :     MSStage* stage = p->getNextStage(nextStageIndex);
     303          735 :     result.type = (int)stage->getStageType();
     304          735 :     result.arrivalPos = stage->getArrivalPos();
     305         2105 :     for (auto e : stage->getEdges()) {
     306         1370 :         if (e != nullptr) {
     307         1360 :             result.edges.push_back(e->getID());
     308              :         }
     309          735 :     }
     310              :     MSStoppingPlace* destinationStop = stage->getDestinationStop();
     311          735 :     if (destinationStop != nullptr) {
     312          470 :         result.destStop = destinationStop->getID();
     313              :     }
     314          735 :     result.description = stage->getStageDescription(p->isPerson());
     315          735 :     result.length = stage->getDistance();
     316          735 :     if (result.length == -1.) {
     317           63 :         result.length = INVALID_DOUBLE_VALUE;
     318              :     }
     319          735 :     result.departPos = INVALID_DOUBLE_VALUE;
     320          735 :     result.cost = INVALID_DOUBLE_VALUE;
     321          735 :     result.depart = stage->getDeparted() >= 0 ? STEPS2TIME(stage->getDeparted()) : INVALID_DOUBLE_VALUE;
     322          735 :     result.travelTime = INVALID_DOUBLE_VALUE;
     323          735 :     if (stage->getArrived() >= 0) {
     324          141 :         result.travelTime = STEPS2TIME(stage->getArrived() - stage->getDeparted());
     325          594 :     } else if (stage->getDeparted() >= 0) {
     326          457 :         result.travelTime = STEPS2TIME(SIMSTEP - stage->getDeparted());
     327              :     }
     328              : 
     329              :     // Some stage type dependant attributes
     330          735 :     switch (stage->getStageType()) {
     331          525 :         case MSStageType::DRIVING: {
     332              :             MSStageDriving* const drivingStage = static_cast<MSStageDriving*>(stage);
     333         1050 :             result.vType = drivingStage->getVehicleType();
     334          525 :             result.intended = drivingStage->getIntendedVehicleID();
     335          525 :             if (result.depart < 0 && drivingStage->getIntendedDepart() >= 0) {
     336            0 :                 result.depart = STEPS2TIME(drivingStage->getIntendedDepart());
     337              :             }
     338              :             const std::set<std::string> lines = drivingStage->getLines();
     339         1050 :             for (auto line = lines.begin(); line != lines.end(); line++) {
     340          525 :                 if (line != lines.begin()) {
     341            0 :                     result.line += " ";
     342              :                 }
     343          525 :                 result.line += *line;
     344              :             }
     345              :             break;
     346              :         }
     347           83 :         case MSStageType::WALKING: {
     348              :             auto* walkingStage = (MSStageWalking*) stage;
     349           83 :             result.departPos = walkingStage->getDepartPos();
     350           83 :             break;
     351              :         }
     352           21 :         case MSStageType::WAITING: {
     353              :             auto* waitingStage = (MSStageWaiting*) stage;
     354           21 :             if (waitingStage->getPlannedDuration() > 0) {
     355           10 :                 result.travelTime = STEPS2TIME(waitingStage->getPlannedDuration());
     356              :             }
     357              :             break;
     358              :         }
     359              :         default:
     360              :             break;
     361              :     }
     362          735 :     return result;
     363           58 : }
     364              : 
     365              : 
     366              : int
     367          162 : Person::getRemainingStages(const std::string& personID) {
     368          162 :     return getPerson(personID)->getNumRemainingStages();
     369              : }
     370              : 
     371              : 
     372              : std::string
     373           19 : Person::getVehicle(const std::string& personID) {
     374           19 :     const SUMOVehicle* veh = getPerson(personID)->getVehicle();
     375           19 :     if (veh == nullptr) {
     376           19 :         return "";
     377              :     } else {
     378              :         return veh->getID();
     379              :     }
     380              : }
     381              : 
     382              : 
     383              : std::string
     384          475 : Person::getParameter(const std::string& personID, const std::string& param) {
     385          949 :     return getPerson(personID)->getParameter().getParameter(param, "");
     386              : }
     387              : 
     388              : 
     389          102 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Person)
     390              : 
     391              : 
     392              : std::string
     393            0 : Person::getEmissionClass(const std::string& personID) {
     394            0 :     return PollutantsInterface::getName(getPerson(personID)->getVehicleType().getEmissionClass());
     395              : }
     396              : 
     397              : 
     398              : std::string
     399            0 : Person::getShapeClass(const std::string& personID) {
     400            0 :     return getVehicleShapeName(getPerson(personID)->getVehicleType().getGuiShape());
     401              : }
     402              : 
     403              : 
     404              : double
     405            4 : Person::getLength(const std::string& personID) {
     406            4 :     return getPerson(personID)->getVehicleType().getLength();
     407              : }
     408              : 
     409              : 
     410              : double
     411           18 : Person::getSpeedFactor(const std::string& personID) {
     412           18 :     return getPerson(personID)->getChosenSpeedFactor();
     413              : }
     414              : 
     415              : 
     416              : double
     417            0 : Person::getAccel(const std::string& personID) {
     418            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getMaxAccel();
     419              : }
     420              : 
     421              : 
     422              : double
     423            0 : Person::getDecel(const std::string& personID) {
     424            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getMaxDecel();
     425              : }
     426              : 
     427              : 
     428            0 : double Person::getEmergencyDecel(const std::string& personID) {
     429            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getEmergencyDecel();
     430              : }
     431              : 
     432              : 
     433            0 : double Person::getApparentDecel(const std::string& personID) {
     434            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getApparentDecel();
     435              : }
     436              : 
     437              : 
     438            0 : double Person::getActionStepLength(const std::string& personID) {
     439            0 :     return getPerson(personID)->getVehicleType().getActionStepLengthSecs();
     440              : }
     441              : 
     442              : 
     443              : double
     444            0 : Person::getTau(const std::string& personID) {
     445            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getHeadwayTime();
     446              : }
     447              : 
     448              : 
     449              : double
     450            0 : Person::getImperfection(const std::string& personID) {
     451            0 :     return getPerson(personID)->getVehicleType().getCarFollowModel().getImperfection();
     452              : }
     453              : 
     454              : 
     455              : double
     456            0 : Person::getSpeedDeviation(const std::string& personID) {
     457            0 :     return getPerson(personID)->getVehicleType().getSpeedFactor().getParameter(1);
     458              : }
     459              : 
     460              : 
     461              : std::string
     462            0 : Person::getVehicleClass(const std::string& personID) {
     463            0 :     return toString(getPerson(personID)->getVehicleType().getVehicleClass());
     464              : }
     465              : 
     466              : 
     467              : double
     468            4 : Person::getMinGap(const std::string& personID) {
     469            4 :     return getPerson(personID)->getVehicleType().getMinGap();
     470              : }
     471              : 
     472              : 
     473              : double
     474            0 : Person::getMinGapLat(const std::string& personID) {
     475            0 :     return getPerson(personID)->getVehicleType().getMinGapLat();
     476              : }
     477              : 
     478              : 
     479              : double
     480           18 : Person::getMaxSpeed(const std::string& personID) {
     481           18 :     return getPerson(personID)->getMaxSpeed();
     482              : }
     483              : 
     484              : 
     485              : double
     486            0 : Person::getMaxSpeedLat(const std::string& personID) {
     487            0 :     return getPerson(personID)->getVehicleType().getMaxSpeedLat();
     488              : }
     489              : 
     490              : 
     491              : std::string
     492            0 : Person::getLateralAlignment(const std::string& personID) {
     493            0 :     return toString(getPerson(personID)->getVehicleType().getPreferredLateralAlignment());
     494              : }
     495              : 
     496              : 
     497              : double
     498            4 : Person::getWidth(const std::string& personID) {
     499            4 :     return getPerson(personID)->getVehicleType().getWidth();
     500              : }
     501              : 
     502              : 
     503              : double
     504            0 : Person::getHeight(const std::string& personID) {
     505            0 :     return getPerson(personID)->getVehicleType().getHeight();
     506              : }
     507              : 
     508              : 
     509              : double
     510            0 : Person::getMass(const std::string& personID) {
     511            0 :     return getPerson(personID)->getVehicleType().getMass();
     512              : }
     513              : 
     514              : 
     515              : int
     516            0 : Person::getPersonCapacity(const std::string& personID) {
     517            0 :     return getPerson(personID)->getVehicleType().getPersonCapacity();
     518              : }
     519              : 
     520              : 
     521              : double
     522            4 : Person::getBoardingDuration(const std::string& personID) {
     523            4 :     return STEPS2TIME(getPerson(personID)->getVehicleType().getBoardingDuration(true));
     524              : }
     525              : 
     526              : 
     527              : double
     528            8 : Person::getImpatience(const std::string& personID) {
     529            8 :     return getPerson(personID)->getImpatience();
     530              : }
     531              : 
     532              : 
     533              : void
     534           14 : Person::setSpeed(const std::string& personID, double speed) {
     535           14 :     getPerson(personID)->setSpeed(speed);
     536           14 : }
     537              : 
     538              : 
     539              : void
     540           16 : Person::setType(const std::string& personID, const std::string& typeID) {
     541           16 :     MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
     542           16 :     if (vehicleType == nullptr) {
     543            0 :         throw TraCIException("The vehicle type '" + typeID + "' is not known.");
     544              :     }
     545           16 :     getPerson(personID)->replaceVehicleType(vehicleType);
     546           16 : }
     547              : 
     548              : 
     549              : void
     550          211 : Person::add(const std::string& personID, const std::string& edgeID, double pos, double departInSecs, const std::string typeID) {
     551              :     MSTransportable* p;
     552              :     try {
     553          211 :         p = getPerson(personID);
     554          211 :     } catch (TraCIException&) {
     555              :         p = nullptr;
     556          211 :     }
     557              : 
     558            0 :     if (p != nullptr) {
     559            0 :         throw TraCIException("The person " + personID + " to add already exists.");
     560              :     }
     561              : 
     562          211 :     SUMOTime depart = TIME2STEPS(departInSecs);
     563          211 :     SUMOVehicleParameter vehicleParams;
     564              :     vehicleParams.id = personID;
     565              : 
     566          211 :     MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
     567          211 :     if (!vehicleType) {
     568            0 :         throw TraCIException("Invalid type '" + typeID + "' for person '" + personID + "'");
     569              :     }
     570              : 
     571          211 :     const MSEdge* edge = MSEdge::dictionary(edgeID);
     572          211 :     if (!edge) {
     573            0 :         throw TraCIException("Invalid edge '" + edgeID + "' for person: '" + personID + "'");
     574              :     }
     575              : 
     576          211 :     if (departInSecs < 0.) {
     577          165 :         const int proc = (int) - departInSecs;
     578          165 :         if (proc >= static_cast<int>(DepartDefinition::DEF_MAX)) {
     579            0 :             throw TraCIException("Invalid departure time." + toString(depart) + " " + toString(proc));
     580              :         }
     581          165 :         vehicleParams.departProcedure = (DepartDefinition)proc;
     582          165 :         vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
     583           46 :     } else if (depart < MSNet::getInstance()->getCurrentTimeStep()) {
     584           36 :         vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
     585          108 :         WRITE_WARNINGF(TL("Departure time=% for person '%' is in the past; using current time=% instead."),
     586              :                        toString(departInSecs), personID, time2string(vehicleParams.depart));
     587              :     } else {
     588           10 :         vehicleParams.depart = depart;
     589              :     }
     590              : 
     591          211 :     vehicleParams.departPosProcedure = DepartPosDefinition::GIVEN;
     592          211 :     if (fabs(pos) > edge->getLength()) {
     593            0 :         throw TraCIException("Invalid departure position.");
     594              :     }
     595          211 :     if (pos < 0) {
     596           19 :         pos += edge->getLength();
     597              :     }
     598          211 :     vehicleParams.departPos = pos;
     599              : 
     600          211 :     SUMOVehicleParameter* params = new SUMOVehicleParameter(vehicleParams);
     601          211 :     MSTransportable::MSTransportablePlan* plan = new MSTransportable::MSTransportablePlan();
     602          211 :     plan->push_back(new MSStageWaiting(edge, nullptr, 0, depart, pos, "awaiting departure", true));
     603              : 
     604              :     try {
     605          211 :         MSTransportable* person = MSNet::getInstance()->getPersonControl().buildPerson(params, vehicleType, plan, nullptr);
     606          211 :         MSNet::getInstance()->getPersonControl().add(person);
     607            0 :     } catch (ProcessError& e) {
     608            0 :         delete params;
     609            0 :         delete plan;
     610            0 :         throw TraCIException(e.what());
     611            0 :     }
     612          211 : }
     613              : 
     614              : MSStage*
     615           44 : Person::convertTraCIStage(const TraCIStage& stage, const std::string personID) {
     616              :     MSStoppingPlace* bs = nullptr;
     617           44 :     if (!stage.destStop.empty()) {
     618           18 :         bs = MSNet::getInstance()->getStoppingPlace(stage.destStop);
     619           18 :         if (bs == nullptr) {
     620            0 :             throw TraCIException("Invalid stopping place id '" + stage.destStop + "' for person: '" + personID + "'");
     621              :         }
     622              :     }
     623           44 :     switch (stage.type) {
     624           10 :         case STAGE_DRIVING: {
     625           10 :             if (stage.edges.empty()) {
     626            0 :                 throw TraCIException("The stage should have at least one edge");
     627              :             }
     628              :             std::string toId = stage.edges.back();
     629           10 :             MSEdge* to = MSEdge::dictionary(toId);
     630           10 :             if (!to) {
     631            0 :                 throw TraCIException("Invalid edge '" + toId + "' for person: '" + personID + "'");
     632              :             }
     633              :             //std::string fromId = stage.edges.front();
     634              :             //MSEdge* from = MSEdge::dictionary(fromId);
     635              :             //if (!from) {
     636              :             //    throw TraCIException("Invalid edge '" + fromId + "' for person: '" + personID + "'");
     637              :             //}
     638           10 :             if (stage.line.empty()) {
     639            0 :                 throw TraCIException("Empty lines parameter for person: '" + personID + "'");
     640              :             }
     641           10 :             double arrivalPos = stage.arrivalPos;
     642           10 :             if (arrivalPos == INVALID_DOUBLE_VALUE) {
     643            5 :                 if (bs != nullptr) {
     644            5 :                     arrivalPos = bs->getEndLanePosition();
     645              :                 } else {
     646              :                     arrivalPos = to->getLength();
     647              :                 }
     648              :             }
     649           30 :             return new MSStageDriving(nullptr, to, bs, arrivalPos, 0.0, StringTokenizer(stage.line).getVector());
     650              :         }
     651              : 
     652           26 :         case STAGE_WALKING: {
     653           26 :             MSTransportable* p = getPerson(personID);
     654              :             ConstMSEdgeVector edges;
     655              :             try {
     656           52 :                 MSEdge::parseEdgesList(stage.edges, edges, "<unknown>");
     657            0 :             } catch (ProcessError& e) {
     658            0 :                 throw TraCIException(e.what());
     659            0 :             }
     660           26 :             if (edges.empty()) {
     661            0 :                 throw TraCIException("Empty edge list for walking stage of person '" + personID + "'.");
     662              :             }
     663           26 :             double arrivalPos = stage.arrivalPos;
     664           26 :             if (fabs(arrivalPos) > edges.back()->getLength()) {
     665            0 :                 throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
     666              :             }
     667           26 :             if (arrivalPos < 0) {
     668            1 :                 arrivalPos += edges.back()->getLength();
     669              :             }
     670           26 :             return new MSStageWalking(p->getID(), edges, bs, -1, -1, p->getArrivalPos(), arrivalPos, MSPModel::UNSPECIFIED_POS_LAT);
     671           26 :         }
     672              : 
     673            0 :         case STAGE_WAITING: {
     674            0 :             MSTransportable* p = getPerson(personID);
     675            0 :             if (stage.travelTime < 0) {
     676            0 :                 throw TraCIException("Duration for person: '" + personID + "' must not be negative");
     677              :             }
     678            0 :             return new MSStageWaiting(p->getArrivalEdge(), nullptr, TIME2STEPS(stage.travelTime), 0, p->getArrivalPos(), stage.description, false);
     679              :         }
     680            8 :         case STAGE_TRIP: {
     681            8 :             MSTransportable* p = getPerson(personID);
     682              :             ConstMSEdgeVector edges;
     683              :             try {
     684           16 :                 MSEdge::parseEdgesList(stage.edges, edges, "<unknown>");
     685            0 :             } catch (ProcessError& e) {
     686            0 :                 throw TraCIException(e.what());
     687            0 :             }
     688            8 :             if ((edges.size() == 0 && bs == nullptr) || edges.size() > 1) {
     689            0 :                 throw TraCIException("A trip should be defined with a destination edge or a destination stop for person '" + personID + "'.");
     690              :             }
     691              :             const MSEdge* to = nullptr;
     692            8 :             if (bs != nullptr) {
     693            8 :                 to = &bs->getLane().getEdge();
     694            8 :                 if (edges.size() > 0 && to != edges.back()) {
     695            0 :                     throw TraCIException("Mismatching destination edge and destination stop edge for person '" + personID + "'.");
     696              :                 }
     697              :             } else {
     698            0 :                 to = edges.back();
     699              :             }
     700            8 :             SVCPermissions modeSet = 0;
     701            8 :             MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
     702           24 :             for (std::string vtypeid : StringTokenizer(stage.vType).getVector()) {
     703            8 :                 const MSVehicleType* const vType = vehControl.getVType(vtypeid);
     704            8 :                 if (vType == nullptr) {
     705            0 :                     throw TraCIException("The vehicle type '" + vtypeid + "' in a trip for person '" + personID + "' is not known.");
     706              :                 }
     707           12 :                 modeSet |= (vType->getVehicleClass() == SVC_BICYCLE) ? SVC_BICYCLE : SVC_PASSENGER;
     708            8 :             }
     709            8 :             if (stage.line.empty()) {
     710            0 :                 modeSet = p->getParameter().modes;
     711              :             } else {
     712              :                 std::string errorMsg;
     713           16 :                 if (!SUMOVehicleParameter::parsePersonModes(stage.line, "person", personID, modeSet, errorMsg)) {
     714            0 :                     throw TraCIException(errorMsg);
     715              :                 }
     716              :             }
     717            8 :             bool hasArrivalPos = stage.arrivalPos != INVALID_DOUBLE_VALUE;
     718              :             double arrivalPos = stage.arrivalPos;
     719            8 :             if (hasArrivalPos) {
     720            8 :                 if (fabs(arrivalPos) > to->getLength()) {
     721            0 :                     throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
     722              :                 }
     723            8 :                 if (arrivalPos < 0) {
     724            0 :                     arrivalPos += to->getLength();
     725              :                 }
     726              :             }
     727              :             const MSStage* cur = p->getCurrentStage();
     728           16 :             double walkfactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
     729              :             std::string group = stage.intended; //OptionsCont::getOptions().getString("persontrip.default.group");
     730              :             const SUMOTime duration = -1;
     731              :             const double speed = -1;
     732              :             return new MSStageTrip(cur->getDestination(), cur->getDestinationStop(), to, bs,
     733            8 :                                    duration, modeSet, stage.vType, speed, walkfactor, group,
     734            8 :                                    MSPModel::UNSPECIFIED_POS_LAT, hasArrivalPos, arrivalPos);
     735            8 :         }
     736              :         default:
     737              :             return nullptr;
     738              :     }
     739              : }
     740              : 
     741              : 
     742              : void
     743           34 : Person::appendStage(const std::string& personID, const TraCIStage& stage) {
     744           34 :     MSTransportable* p = getPerson(personID);
     745           34 :     MSStage* personStage = convertTraCIStage(stage, personID);
     746           34 :     p->appendStage(personStage);
     747           34 : }
     748              : 
     749              : 
     750              : void
     751           10 : Person::replaceStage(const std::string& personID, const int stageIndex, const TraCIStage& stage) {
     752           10 :     MSTransportable* p = getPerson(personID);
     753           10 :     if (stageIndex >= p->getNumRemainingStages()) {
     754            0 :         throw TraCIException("Specified stage index:  is not valid for person " + personID);
     755              :     }
     756           10 :     MSStage* personStage = convertTraCIStage(stage, personID);
     757              :     // removing the current stage triggers abort+proceed so the replacement
     758              :     // stage must be ready beforehand
     759           10 :     p->appendStage(personStage, stageIndex + 1);
     760           10 :     p->removeStage(stageIndex);
     761           10 : }
     762              : 
     763              : 
     764              : void
     765           36 : Person::appendDrivingStage(const std::string& personID, const std::string& toEdge, const std::string& lines, const std::string& stopID) {
     766           36 :     MSTransportable* p = getPerson(personID);
     767           36 :     const MSEdge* edge = MSEdge::dictionary(toEdge);
     768           36 :     if (!edge) {
     769            0 :         throw TraCIException("Invalid edge '" + toEdge + "' for person: '" + personID + "'");
     770              :     }
     771           36 :     if (lines.size() == 0) {
     772            0 :         throw TraCIException("Empty lines parameter for person: '" + personID + "'");
     773              :     }
     774              :     MSStoppingPlace* bs = nullptr;
     775           36 :     if (stopID != "") {
     776           20 :         bs = MSNet::getInstance()->getStoppingPlace(stopID);
     777           20 :         if (bs == nullptr) {
     778            0 :             throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
     779              :         }
     780              :     }
     781          108 :     p->appendStage(new MSStageDriving(nullptr, edge, bs, edge->getLength() - NUMERICAL_EPS, 0.0, StringTokenizer(lines).getVector()));
     782           36 : }
     783              : 
     784              : 
     785              : void
     786           26 : Person::appendWaitingStage(const std::string& personID, double duration, const std::string& description, const std::string& stopID) {
     787           26 :     MSTransportable* p = getPerson(personID);
     788           26 :     if (duration < 0) {
     789            0 :         throw TraCIException("Duration for person: '" + personID + "' must not be negative");
     790              :     }
     791              :     MSStoppingPlace* bs = nullptr;
     792           26 :     if (stopID != "") {
     793           10 :         bs = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
     794           10 :         if (bs == nullptr) {
     795            0 :             throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
     796              :         }
     797              :     }
     798           52 :     p->appendStage(new MSStageWaiting(p->getArrivalEdge(), nullptr, TIME2STEPS(duration), 0, p->getArrivalPos(), description, false));
     799           26 : }
     800              : 
     801              : 
     802              : void
     803          189 : Person::appendWalkingStage(const std::string& personID, const std::vector<std::string>& edgeIDs, double arrivalPos, double duration, double speed, const std::string& stopID) {
     804          189 :     MSTransportable* p = getPerson(personID);
     805              :     ConstMSEdgeVector edges;
     806              :     try {
     807          378 :         MSEdge::parseEdgesList(edgeIDs, edges, "<unknown>");
     808            0 :     } catch (ProcessError& e) {
     809            0 :         throw TraCIException(e.what());
     810            0 :     }
     811          189 :     if (edges.empty()) {
     812            0 :         throw TraCIException("Empty edge list for walking stage of person '" + personID + "'.");
     813              :     }
     814          189 :     if (fabs(arrivalPos) > edges.back()->getLength()) {
     815            0 :         throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
     816              :     }
     817          189 :     if (arrivalPos < 0) {
     818           31 :         arrivalPos += edges.back()->getLength();
     819              :     }
     820              :     MSStoppingPlace* bs = nullptr;
     821          189 :     if (stopID != "") {
     822            0 :         bs = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
     823            0 :         if (bs == nullptr) {
     824            0 :             throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
     825              :         }
     826              :     }
     827          378 :     p->appendStage(new MSStageWalking(p->getID(), edges, bs, TIME2STEPS(duration), speed, p->getArrivalPos(), arrivalPos, MSPModel::UNSPECIFIED_POS_LAT));
     828          189 : }
     829              : 
     830              : 
     831              : void
     832          139 : Person::removeStage(const std::string& personID, int nextStageIndex) {
     833          139 :     MSTransportable* p = getPerson(personID);
     834          138 :     if (nextStageIndex >= p->getNumRemainingStages()) {
     835            0 :         throw TraCIException("The stage index must be lower than the number of remaining stages.");
     836              :     }
     837          138 :     if (nextStageIndex < 0) {
     838            0 :         throw TraCIException("The stage index may not be negative.");
     839              :     }
     840          138 :     p->removeStage(nextStageIndex);
     841          138 : }
     842              : 
     843              : 
     844              : void
     845          986 : Person::rerouteTraveltime(const std::string& personID) {
     846          986 :     MSPerson* p = getPerson(personID);
     847          986 :     if (p->getNumRemainingStages() == 0) {
     848            0 :         throw TraCIException("Person '" + personID + "' has no remaining stages.");
     849              :     }
     850          986 :     const MSEdge* from = p->getEdge();
     851          986 :     double  departPos = p->getEdgePos();
     852              :     // reroute to the start of the next-non-walking stage
     853              :     int firstIndex;
     854          986 :     if (p->getCurrentStageType() == MSStageType::WALKING) {
     855              :         firstIndex = 0;
     856            5 :     } else if (p->getCurrentStageType() == MSStageType::WAITING) {
     857            5 :         if (p->getNumRemainingStages() < 2 || p->getStageType(1) != MSStageType::WALKING) {
     858            0 :             throw TraCIException("Person '" + personID + "' cannot reroute after the current stop.");
     859              :         }
     860              :         firstIndex = 1;
     861              :     } else {
     862            0 :         throw TraCIException("Person '" + personID + "' cannot reroute in stage type '" + toString((int)p->getCurrentStageType()) + "'.");
     863              :     }
     864          986 :     int nextIndex = firstIndex + 1;
     865          991 :     for (; nextIndex < p->getNumRemainingStages(); nextIndex++) {
     866           20 :         if (p->getStageType(nextIndex) != MSStageType::WALKING) {
     867              :             break;
     868              :         }
     869              :     }
     870          986 :     MSStage* destStage = p->getNextStage(nextIndex - 1);
     871          986 :     const MSEdge* to = destStage->getEdges().back();
     872          986 :     double arrivalPos = destStage->getArrivalPos();
     873          986 :     double speed = p->getMaxSpeed();
     874              :     ConstMSEdgeVector newEdges;
     875         1972 :     MSNet::getInstance()->getPedestrianRouter(0).compute(from, to, departPos, arrivalPos, speed, 0, nullptr, p->getVTypeParameter(), newEdges);
     876          986 :     if (newEdges.empty()) {
     877            0 :         throw TraCIException("Could not find new route for person '" + personID + "'.");
     878              :     }
     879          986 :     ConstMSEdgeVector oldEdges = p->getNextStage(firstIndex)->getEdges();
     880              :     assert(!oldEdges.empty());
     881          986 :     if (oldEdges.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
     882              :         oldEdges.erase(oldEdges.begin());
     883              :     }
     884              :     //std::cout << " remainingStages=" << p->getNumRemainingStages() << " oldEdges=" << toString(oldEdges) << " newEdges=" << toString(newEdges) << " firstIndex=" << firstIndex << " nextIndex=" << nextIndex << "\n";
     885          986 :     if (newEdges == oldEdges && (firstIndex + 1 == nextIndex)) {
     886              :         return;
     887              :     }
     888           37 :     if (newEdges.front() != from) {
     889              :         // @note: maybe this should be done automatically by the router
     890            4 :         newEdges.insert(newEdges.begin(), from);
     891              :     }
     892           37 :     p->replaceWalk(newEdges, departPos, firstIndex, nextIndex);
     893          986 : }
     894              : 
     895              : 
     896              : void
     897           18 : Person::moveTo(const std::string& personID, const std::string& laneID, double pos, double posLat) {
     898           18 :     MSPerson* p = getPerson(personID);
     899           18 :     MSLane* l = MSLane::dictionary(laneID);
     900           18 :     if (l == nullptr) {
     901            0 :         throw TraCIException("Unknown lane '" + laneID + "'.");
     902              :     }
     903           18 :     if (posLat == INVALID_DOUBLE_VALUE) {
     904           18 :         posLat = 0;
     905            0 :     } else if (fabs(posLat) >= (0.5 * (l->getWidth() + p->getVehicleType().getWidth()) + MSPModel::SIDEWALK_OFFSET)) {
     906              :         // see MSPModel_Striping::moveToXY
     907            0 :         throw TraCIException("Invalid lateral position " + toString(posLat) + " on lane '" + laneID + "'.");
     908              :     }
     909           18 :     switch (p->getStageType(0)) {
     910              :         case MSStageType::WALKING: {
     911           18 :             MSStageWalking* s = dynamic_cast<MSStageWalking*>(p->getCurrentStage());
     912              :             assert(s != 0);
     913           18 :             s->getPState()->moveTo(p, l, pos, posLat, SIMSTEP);
     914              :             break;
     915              :         }
     916            0 :         default:
     917            0 :             throw TraCIException("Command moveTo is not supported for person '" + personID + "' while " + p->getCurrentStageDescription() + ".");
     918              :     }
     919           18 : }
     920              : 
     921              : 
     922              : void
     923        14121 : Person::moveToXY(const std::string& personID, const std::string& edgeID, const double x, const double y, double angle, const int keepRoute, double matchThreshold) {
     924        14121 :     MSPerson* p = getPerson(personID);
     925        14121 :     const bool doKeepRoute = (keepRoute & 1) != 0;
     926        14121 :     const bool mayLeaveNetwork = (keepRoute & 2) != 0;
     927        14121 :     const bool ignorePermissions = (keepRoute & 4) != 0;
     928        14121 :     SUMOVehicleClass vClass = ignorePermissions ? SVC_IGNORING : p->getVClass();
     929              :     Position pos(x, y);
     930              : #ifdef DEBUG_MOVEXY
     931              :     const double origAngle = angle;
     932              : #endif
     933              :     // angle must be in [0,360] because it will be compared against those returned by naviDegree()
     934              :     // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
     935        14121 :     if (angle != INVALID_DOUBLE_VALUE) {
     936        11682 :         while (angle >= 360.) {
     937            0 :             angle -= 360.;
     938              :         }
     939        11682 :         while (angle < 0.) {
     940            0 :             angle += 360.;
     941              :         }
     942              :     }
     943              : #ifdef DEBUG_MOVEXY
     944              :     std::cout << std::endl << "begin person " << p->getID() << " lanePos:" << p->getEdgePos() << " edge:" << Named::getIDSecure(p->getEdge()) << "\n";
     945              :     std::cout << " want pos:" << pos << " edgeID:" << edgeID <<  " origAngle:" << origAngle << " angle:" << angle << " keepRoute:" << keepRoute << std::endl;
     946              : #endif
     947              : 
     948              :     ConstMSEdgeVector edges;
     949        14121 :     MSLane* lane = nullptr;
     950              :     double lanePos;
     951              :     double lanePosLat = 0;
     952        14121 :     double bestDistance = std::numeric_limits<double>::max();
     953        14121 :     int routeOffset = 0;
     954              :     bool found = false;
     955        14121 :     double maxRouteDistance = matchThreshold;
     956              : 
     957              :     ConstMSEdgeVector ev;
     958        14121 :     ev.push_back(p->getEdge());
     959              :     int routeIndex = 0;
     960        14121 :     MSLane* currentLane = const_cast<MSLane*>(getSidewalk<MSEdge, MSLane>(p->getEdge()));
     961        14121 :     switch (p->getStageType(0)) {
     962              :         case MSStageType::WALKING: {
     963        14104 :             MSStageWalking* s = dynamic_cast<MSStageWalking*>(p->getCurrentStage());
     964              :             assert(s != 0);
     965        14104 :             ev = s->getEdges();
     966        14104 :             routeIndex = (int)(s->getRouteStep() - s->getRoute().begin());
     967              :         }
     968        14104 :         break;
     969              :         default:
     970              :             break;
     971              :     }
     972        14121 :     if (doKeepRoute) {
     973              :         // case a): vehicle is on its earlier route
     974              :         //  we additionally assume it is moving forward (SUMO-limit);
     975              :         //  note that the route ("edges") is not changed in this case
     976        12010 :         found = Helper::moveToXYMap_matchingRoutePosition(pos, edgeID,
     977              :                 ev, routeIndex, vClass, true,
     978              :                 bestDistance, &lane, lanePos, routeOffset);
     979        12010 :         if (bestDistance > maxRouteDistance) {
     980              :             found = false;
     981         3137 :             lane = nullptr;
     982              :         }
     983              :     } else {
     984         2111 :         double speed = pos.distanceTo2D(p->getPosition()); // !!!veh->getSpeed();
     985         4222 :         found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, edgeID, angle,
     986         2111 :                                     speed, ev, routeIndex, currentLane, p->getEdgePos(), currentLane != nullptr,
     987         2111 :                                     vClass, GeomHelper::naviDegree(p->getAngle()), true,
     988              :                                     bestDistance, &lane, lanePos, routeOffset, edges);
     989         2111 :         if (edges.size() != 0 && ev.size() > 1) {
     990              :             // try to rebuild the route
     991           24 :             const MSEdge* origEdge = p->getEdge();
     992              :             assert(lane != nullptr);
     993              :             const MSJunction* originalTarget = nullptr;
     994           24 :             if (origEdge->isNormal()) {
     995           24 :                 if (routeIndex == 0) {
     996           24 :                     if (origEdge->getToJunction() == ev[1]->getToJunction() || origEdge->getToJunction() == ev[1]->getFromJunction()) {
     997              :                         originalTarget = origEdge->getToJunction();
     998              :                     } else {
     999              :                         originalTarget = origEdge->getFromJunction();
    1000              :                     }
    1001              :                 } else {
    1002            0 :                     if (origEdge->getToJunction() == ev[routeIndex - 1]->getToJunction() || origEdge->getToJunction() == ev[routeIndex - 1]->getFromJunction()) {
    1003              :                         originalTarget = origEdge->getFromJunction();
    1004              :                     } else {
    1005              :                         originalTarget = origEdge->getToJunction();
    1006              :                     }
    1007              :                 }
    1008              :             } else {
    1009              :                 originalTarget = origEdge->getToJunction();
    1010              :                 assert(originalTarget == origEdge->getFromJunction());
    1011              :             }
    1012           24 :             const MSEdge* newEdge = edges[0];
    1013           24 :             if (edges[0]->getFromJunction() == originalTarget || edges[0]->getToJunction() == originalTarget) {
    1014           19 :                 edges = ev;
    1015           19 :                 edges[routeIndex] = newEdge;
    1016              :             }
    1017              :         }
    1018              :     }
    1019        14121 :     if (found || mayLeaveNetwork) {
    1020              :         // compute lateral offset
    1021        14116 :         if (found) {
    1022        10984 :             const double perpDist = lane->getShape().distance2D(pos, false);
    1023        10984 :             if (perpDist != GeomHelper::INVALID_OFFSET) {
    1024              :                 lanePosLat = perpDist;
    1025        10984 :                 if (!mayLeaveNetwork) {
    1026         1633 :                     lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + p->getVehicleType().getWidth()));
    1027              :                 }
    1028              :                 // figure out whether the offset is to the left or to the right
    1029        10984 :                 PositionVector tmp = lane->getShape();
    1030              :                 try {
    1031        10984 :                     tmp.move2side(-lanePosLat); // moved to left
    1032            0 :                 } catch (ProcessError&) {
    1033            0 :                     WRITE_WARNINGF(TL("Could not determine position on lane '%' at lateral position %."), lane->getID(), toString(-lanePosLat));
    1034            0 :                 }
    1035              :                 //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
    1036        10984 :                 if (tmp.distance2D(pos) > perpDist) {
    1037              :                     lanePosLat = -lanePosLat;
    1038              :                 }
    1039        10984 :             }
    1040              :         }
    1041        14116 :         if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
    1042              :             // mapped position may differ from pos
    1043         1633 :             pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
    1044              :         }
    1045              :         assert((found && lane != nullptr) || (!found && lane == nullptr));
    1046        14116 :         switch (p->getStageType(0)) {
    1047        14099 :             case MSStageType::WALKING: {
    1048        14099 :                 if (angle == INVALID_DOUBLE_VALUE) {
    1049              :                     // walking angle cannot be deduced from road angle so we always use the last pos
    1050         2417 :                     angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
    1051              :                 }
    1052              :                 break;
    1053              :             }
    1054           17 :             case MSStageType::WAITING_FOR_DEPART:
    1055              :             case MSStageType::WAITING: {
    1056           17 :                 if (p->getNumRemainingStages() <= 1 || p->getStageType(1) != MSStageType::WALKING) {
    1057              :                     // insert walking stage after the current stage
    1058            4 :                     ConstMSEdgeVector route({p->getEdge()});
    1059            4 :                     const double departPos = p->getCurrentStage()->getArrivalPos();
    1060            4 :                     p->appendStage(new MSStageWalking(p->getID(), route, nullptr, -1, -1, departPos, departPos, MSPModel::UNSPECIFIED_POS_LAT), 1);
    1061            4 :                 }
    1062              :                 // abort waiting stage and proceed to walking stage
    1063           17 :                 p->removeStage(0);
    1064              :                 assert(p->getStageType(0) == MSStageType::WALKING);
    1065           17 :                 if (angle == INVALID_DOUBLE_VALUE) {
    1066           17 :                     if (lane != nullptr && !lane->getEdge().isWalkingArea()) {
    1067           17 :                         angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
    1068              :                     } else {
    1069              :                         // compute angle outside road network or on walkingarea from old and new position
    1070            0 :                         angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
    1071              :                     }
    1072              :                 }
    1073              :                 break;
    1074              :             }
    1075            0 :             default:
    1076            0 :                 throw TraCIException("Command moveToXY is not supported for person '" + personID + "' while " + p->getCurrentStageDescription() + ".");
    1077              :         }
    1078        14116 :         Helper::setRemoteControlled(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
    1079              :     } else {
    1080            5 :         if (lane == nullptr) {
    1081           15 :             throw TraCIException("Could not map person '" + personID + "' no road found within " + toString(maxRouteDistance) + "m.");
    1082              :         } else {
    1083            0 :             throw TraCIException("Could not map person '" + personID + "' distance to road is " + toString(bestDistance) + ".");
    1084              :         }
    1085              :     }
    1086        14126 : }
    1087              : 
    1088              : 
    1089              : /** untested setter functions which alter the person's vtype ***/
    1090              : 
    1091              : void
    1092          109 : Person::setParameter(const std::string& personID, const std::string& key, const std::string& value) {
    1093          109 :     MSTransportable* p = getPerson(personID);
    1094          218 :     if (StringUtils::startsWith(key, "device.")) {
    1095            0 :         throw TraCIException("Person '" + personID + "' does not support device parameters\n");
    1096          218 :     } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
    1097            0 :         throw TraCIException("Person '" + personID + "' does not support laneChangeModel parameters\n");
    1098          218 :     } else if (StringUtils::startsWith(key, "carFollowModel.")) {
    1099            0 :         throw TraCIException("Person '" + personID + "' does not support carFollowModel parameters\n");
    1100          218 :     } else if (StringUtils::startsWith(key, "junctionModel.")) {
    1101              :         try {
    1102              :             // use the whole key (including junctionModel prefix)
    1103           10 :             p->setJunctionModelParameter(key, value);
    1104            5 :         } catch (InvalidArgument& e) {
    1105              :             // error message includes id since it is also used for xml input
    1106           10 :             throw TraCIException(e.what());
    1107            5 :         }
    1108           99 :     } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
    1109            0 :         throw TraCIException("Person '" + personID + "' does not support chanigng device status\n");
    1110              :     } else {
    1111           99 :         ((SUMOVehicleParameter&)p->getParameter()).setParameter(key, value);
    1112              :     }
    1113          104 : }
    1114              : 
    1115              : 
    1116              : void
    1117            2 : Person::setLength(const std::string& personID, double length) {
    1118            2 :     getPerson(personID)->getSingularType().setLength(length);
    1119            2 : }
    1120              : 
    1121              : 
    1122              : void
    1123            0 : Person::setMaxSpeed(const std::string& personID, double speed) {
    1124            0 :     getPerson(personID)->getSingularType().setMaxSpeed(speed);
    1125            0 : }
    1126              : 
    1127              : 
    1128              : void
    1129            0 : Person::setVehicleClass(const std::string& personID, const std::string& clazz) {
    1130            0 :     getPerson(personID)->getSingularType().setVClass(getVehicleClassID(clazz));
    1131            0 : }
    1132              : 
    1133              : 
    1134              : void
    1135            0 : Person::setShapeClass(const std::string& personID, const std::string& clazz) {
    1136            0 :     getPerson(personID)->getSingularType().setShape(getVehicleShapeID(clazz));
    1137            0 : }
    1138              : 
    1139              : 
    1140              : void
    1141            0 : Person::setEmissionClass(const std::string& personID, const std::string& clazz) {
    1142            0 :     getPerson(personID)->getSingularType().setEmissionClass(PollutantsInterface::getClassByName(clazz));
    1143            0 : }
    1144              : 
    1145              : 
    1146              : void
    1147            2 : Person::setWidth(const std::string& personID, double width) {
    1148            2 :     getPerson(personID)->getSingularType().setWidth(width);
    1149            2 : }
    1150              : 
    1151              : 
    1152              : void
    1153            2 : Person::setHeight(const std::string& personID, double height) {
    1154            2 :     getPerson(personID)->getSingularType().setHeight(height);
    1155            2 : }
    1156              : 
    1157              : 
    1158              : void
    1159            0 : Person::setMass(const std::string& personID, double mass) {
    1160            0 :     getPerson(personID)->getSingularType().setMass(mass);
    1161            0 : }
    1162              : 
    1163              : 
    1164              : void
    1165            2 : Person::setMinGap(const std::string& personID, double minGap) {
    1166            2 :     getPerson(personID)->getSingularType().setMinGap(minGap);
    1167            2 : }
    1168              : 
    1169              : 
    1170              : void
    1171            0 : Person::setAccel(const std::string& personID, double accel) {
    1172            0 :     getPerson(personID)->getSingularType().setAccel(accel);
    1173            0 : }
    1174              : 
    1175              : 
    1176              : void
    1177            0 : Person::setDecel(const std::string& personID, double decel) {
    1178            0 :     getPerson(personID)->getSingularType().setDecel(decel);
    1179            0 : }
    1180              : 
    1181              : 
    1182              : void
    1183            0 : Person::setEmergencyDecel(const std::string& personID, double decel) {
    1184            0 :     getPerson(personID)->getSingularType().setEmergencyDecel(decel);
    1185            0 : }
    1186              : 
    1187              : 
    1188              : void
    1189            0 : Person::setApparentDecel(const std::string& personID, double decel) {
    1190            0 :     getPerson(personID)->getSingularType().setApparentDecel(decel);
    1191            0 : }
    1192              : 
    1193              : 
    1194              : void
    1195            0 : Person::setImperfection(const std::string& personID, double imperfection) {
    1196            0 :     getPerson(personID)->getSingularType().setImperfection(imperfection);
    1197            0 : }
    1198              : 
    1199              : 
    1200              : void
    1201            0 : Person::setBoardingDuration(const std::string& personID, double boardingDuration)  {
    1202            0 :     Helper::getPerson(personID)->getSingularType().setBoardingDuration(TIME2STEPS(boardingDuration));
    1203            0 : }
    1204              : 
    1205              : 
    1206              : void
    1207            0 : Person::setImpatience(const std::string& personID, double impatience)  {
    1208            0 :     Helper::getVehicle(personID)->getSingularType().setImpatience(impatience);
    1209            0 : }
    1210              : 
    1211              : 
    1212              : 
    1213              : void
    1214            0 : Person::setTau(const std::string& personID, double tau) {
    1215            0 :     getPerson(personID)->getSingularType().setTau(tau);
    1216            0 : }
    1217              : 
    1218              : 
    1219              : void
    1220            0 : Person::setMinGapLat(const std::string& personID, double minGapLat) {
    1221            0 :     getPerson(personID)->getSingularType().setMinGapLat(minGapLat);
    1222            0 : }
    1223              : 
    1224              : 
    1225              : void
    1226            0 : Person::setMaxSpeedLat(const std::string& personID, double speed) {
    1227            0 :     getPerson(personID)->getSingularType().setMaxSpeedLat(speed);
    1228            0 : }
    1229              : 
    1230              : 
    1231              : void
    1232            0 : Person::setLateralAlignment(const std::string& personID, const std::string& latAlignment) {
    1233              :     double lao;
    1234              :     LatAlignmentDefinition lad;
    1235            0 :     if (SUMOVTypeParameter::parseLatAlignment(latAlignment, lao, lad)) {
    1236            0 :         getPerson(personID)->getSingularType().setPreferredLateralAlignment(lad, lao);
    1237              :     } else {
    1238            0 :         throw TraCIException("Unknown value '" + latAlignment + "' when setting latAlignment for person '" + personID + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
    1239              :     }
    1240            0 : }
    1241              : 
    1242              : 
    1243              : void
    1244           30 : Person::setSpeedFactor(const std::string& personID, double factor) {
    1245           30 :     getPerson(personID)->setChosenSpeedFactor(factor);
    1246           30 : }
    1247              : 
    1248              : 
    1249              : void
    1250            0 : Person::setActionStepLength(const std::string& personID, double actionStepLength, bool resetActionOffset) {
    1251            0 :     getPerson(personID)->getSingularType().setActionStepLength(SUMOVehicleParserHelper::processActionStepLength(actionStepLength), resetActionOffset);
    1252            0 : }
    1253              : 
    1254              : void
    1255           23 : Person::remove(const std::string& personID, char /*reason*/) {
    1256           23 :     MSPerson* person = getPerson(personID);
    1257              :     // remove all stages after the current and then abort the current stage
    1258              :     // (without adding a zero-length waiting stage)
    1259           32 :     while (person->getNumRemainingStages() > 1) {
    1260            9 :         person->removeStage(1);
    1261              :     }
    1262           23 :     person->removeStage(0, false);
    1263           23 : }
    1264              : 
    1265              : void
    1266            6 : Person::setColor(const std::string& personID, const TraCIColor& c) {
    1267            6 :     const SUMOVehicleParameter& p = getPerson(personID)->getParameter();
    1268            6 :     p.color.set((unsigned char)c.r, (unsigned char)c.g, (unsigned char)c.b, (unsigned char)c.a);
    1269            6 :     p.parametersSet |= VEHPARS_COLOR_SET;
    1270            6 : }
    1271              : 
    1272              : 
    1273         8387 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Person, PERSON)
    1274              : 
    1275              : 
    1276              : MSPerson*
    1277       164983 : Person::getPerson(const std::string& personID) {
    1278       164983 :     return Helper::getPerson(personID);
    1279              : }
    1280              : 
    1281              : 
    1282              : void
    1283        16360 : Person::storeShape(const std::string& id, PositionVector& shape) {
    1284        16360 :     shape.push_back(getPerson(id)->getPosition());
    1285        16360 : }
    1286              : 
    1287              : 
    1288              : std::shared_ptr<VariableWrapper>
    1289          270 : Person::makeWrapper() {
    1290          270 :     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
    1291              : }
    1292              : 
    1293              : 
    1294              : bool
    1295       115117 : Person::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
    1296       115117 :     switch (variable) {
    1297        30424 :         case TRACI_ID_LIST:
    1298        30424 :             return wrapper->wrapStringList(objID, variable, getIDList());
    1299           22 :         case ID_COUNT:
    1300           22 :             return wrapper->wrapInt(objID, variable, getIDCount());
    1301        77632 :         case VAR_POSITION:
    1302        77632 :             return wrapper->wrapPosition(objID, variable, getPosition(objID));
    1303           17 :         case VAR_POSITION3D:
    1304           17 :             return wrapper->wrapPosition(objID, variable, getPosition(objID, true));
    1305           77 :         case VAR_ANGLE:
    1306           77 :             return wrapper->wrapDouble(objID, variable, getAngle(objID));
    1307           15 :         case VAR_SLOPE:
    1308           15 :             return wrapper->wrapDouble(objID, variable, getSlope(objID));
    1309           31 :         case VAR_SPEED:
    1310           31 :             return wrapper->wrapDouble(objID, variable, getSpeed(objID));
    1311          752 :         case VAR_ROAD_ID:
    1312         1504 :             return wrapper->wrapString(objID, variable, getRoadID(objID));
    1313          192 :         case VAR_LANE_ID:
    1314          384 :             return wrapper->wrapString(objID, variable, getLaneID(objID));
    1315           80 :         case VAR_LANEPOSITION:
    1316           80 :             return wrapper->wrapDouble(objID, variable, getLanePosition(objID));
    1317           17 :         case VAR_COLOR:
    1318           17 :             return wrapper->wrapColor(objID, variable, getColor(objID));
    1319          608 :         case VAR_WAITING_TIME:
    1320          608 :             return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
    1321            8 :         case VAR_IMPATIENCE:
    1322            8 :             return wrapper->wrapDouble(objID, variable, getImpatience(objID));
    1323           26 :         case VAR_TYPE:
    1324           52 :             return wrapper->wrapString(objID, variable, getTypeID(objID));
    1325           14 :         case VAR_SPEED_FACTOR:
    1326           14 :             return wrapper->wrapDouble(objID, variable, getSpeedFactor(objID));
    1327           82 :         case VAR_NEXT_EDGE:
    1328          164 :             return wrapper->wrapString(objID, variable, getNextEdge(objID));
    1329          695 :         case VAR_EDGES:
    1330         1390 :             return wrapper->wrapStringList(objID, variable, getEdges(objID, StoHelp::readTypedInt(*paramData)));
    1331          464 :         case VAR_STAGE:
    1332          884 :             return wrapper->wrapStage(objID, variable, getStage(objID, StoHelp::readTypedInt(*paramData)));
    1333          124 :         case VAR_STAGES_REMAINING:
    1334          124 :             return wrapper->wrapInt(objID, variable, getRemainingStages(objID));
    1335           15 :         case VAR_VEHICLE:
    1336           30 :             return wrapper->wrapString(objID, variable, getVehicle(objID));
    1337           14 :         case VAR_MAXSPEED:
    1338              :             // integrate desiredMaxSpeed and individual speedFactor
    1339           14 :             return wrapper->wrapDouble(objID, variable, getMaxSpeed(objID));
    1340              :         case DISTANCE_REQUEST: {
    1341           50 :             TraCIRoadPosition roadPos;
    1342              :             Position pos;
    1343           25 :             if (Helper::readDistanceRequest(*paramData, roadPos, pos) == libsumo::POSITION_ROADMAP) {
    1344           14 :                 return wrapper->wrapDouble(objID, variable, getWalkingDistance(objID, roadPos.edgeID, roadPos.pos, roadPos.laneIndex));
    1345              :             }
    1346           11 :             return wrapper->wrapDouble(objID, variable, getWalkingDistance2D(objID, pos.x(), pos.y()));
    1347              :         }
    1348          399 :         case VAR_PARAMETER:
    1349          798 :             return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
    1350           47 :         case VAR_PARAMETER_WITH_KEY:
    1351           94 :             return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
    1352         3134 :         case VAR_TAXI_RESERVATIONS:
    1353         6268 :             return wrapper->wrapReservationVector(objID, variable, getTaxiReservations(StoHelp::readTypedInt(*paramData)));
    1354            4 :         case SPLIT_TAXI_RESERVATIONS:
    1355           13 :             return wrapper->wrapString(objID, variable, splitTaxiReservation(objID, StoHelp::readTypedStringList(*paramData)));
    1356          199 :         default:
    1357          398 :             return libsumo::VehicleType::handleVariable(getTypeID(objID), variable, wrapper, paramData);
    1358              :     }
    1359              : }
    1360              : 
    1361              : 
    1362              : }
    1363              : 
    1364              : 
    1365              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1