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

Generated by: LCOV version 2.0-1