LCOV - code coverage report
Current view: top level - src/libsumo - Person.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 73.1 % 618 452
Test Date: 2024-11-21 15:56:26 Functions: 62.6 % 99 62

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

Generated by: LCOV version 2.0-1