LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSTransportable.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.1 % 338 308
Test Date: 2026-05-24 16:29:35 Functions: 81.8 % 44 36

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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    MSTransportable.cpp
      15              : /// @author  Melanie Weber
      16              : /// @author  Andreas Kendziorra
      17              : /// @author  Michael Behrisch
      18              : /// @date    Thu, 12 Jun 2014
      19              : ///
      20              : // The common superclass for modelling transportable objects like persons and containers
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <utils/common/StringTokenizer.h>
      25              : #include <utils/geom/GeomHelper.h>
      26              : #include <utils/vehicle/SUMOVehicleParameter.h>
      27              : #include <utils/router/PedestrianRouter.h>
      28              : #include <utils/router/IntermodalRouter.h>
      29              : #include <libsumo/TraCIConstants.h>
      30              : #include <microsim/MSEdge.h>
      31              : #include <microsim/MSLane.h>
      32              : #include <microsim/MSNet.h>
      33              : #include <microsim/MSEventControl.h>
      34              : #include <microsim/MSStoppingPlace.h>
      35              : #include <microsim/MSVehicleControl.h>
      36              : #include <microsim/devices/MSTransportableDevice.h>
      37              : #include <microsim/transportables/MSTransportableControl.h>
      38              : #include <microsim/transportables/MSPerson.h>
      39              : #include <microsim/transportables/MSStageDriving.h>
      40              : #include <microsim/transportables/MSStageTrip.h>
      41              : #include <microsim/transportables/MSStageWaiting.h>
      42              : #include <microsim/transportables/MSTransportable.h>
      43              : 
      44              : SUMOTrafficObject::NumericalID MSTransportable::myCurrentNumericalIndex = 0;
      45              : 
      46              : //#define DEBUG_PARKING
      47              : 
      48              : // ===========================================================================
      49              : // method definitions
      50              : // ===========================================================================
      51       469535 : MSTransportable::MSTransportable(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportablePlan* plan, const bool isPerson) :
      52              :     SUMOTrafficObject(pars->id),
      53       469535 :     myParameter(pars), myVType(vtype), myPlan(plan),
      54       469535 :     myAmPerson(isPerson),
      55       469535 :     myNumericalID(myCurrentNumericalIndex++),
      56       469535 :     myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())) {
      57       469535 :     myStep = myPlan->begin();
      58              :     // init devices
      59       469535 :     MSDevice::buildTransportableDevices(*this, myDevices);
      60      1462530 :     for (MSStage* const stage : * myPlan) {
      61       992995 :         stage->init(this);
      62              :     }
      63       469535 : }
      64              : 
      65              : 
      66       666418 : MSTransportable::~MSTransportable() {
      67       469479 :     if (myStep != myPlan->end() && getCurrentStageType() == MSStageType::DRIVING) {
      68        65097 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(*myStep);
      69        65097 :         if (stage->getVehicle() != nullptr) {
      70          157 :             stage->getVehicle()->removeTransportable(this);
      71        64940 :         } else if (stage->getOriginStop() != nullptr)  {
      72        19004 :             stage->getOriginStop()->removeTransportable(this);
      73              :         }
      74              :     }
      75       469479 :     if (myPlan != nullptr) {
      76      1640818 :         for (MSTransportablePlan::const_iterator i = myPlan->begin(); i != myPlan->end(); ++i) {
      77      1171339 :             delete *i;
      78              :         }
      79       469479 :         delete myPlan;
      80       469479 :         myPlan = nullptr;
      81              :     }
      82       472396 :     for (MSTransportableDevice* dev : myDevices) {
      83         2917 :         delete dev;
      84              :     }
      85       469479 :     delete myParameter;
      86       469479 :     if (myVType->isVehicleSpecific()) {
      87          179 :         MSNet::getInstance()->getVehicleControl().removeVType(myVType);
      88              :     }
      89       666418 : }
      90              : 
      91              : SumoRNG*
      92           45 : MSTransportable::getRNG() const {
      93           45 :     return getEdge()->getLanes()[0]->getRNG();
      94              : }
      95              : 
      96              : int
      97         2358 : MSTransportable::getRNGIndex() const {
      98         2358 :     return getEdge()->getLanes()[0]->getRNGIndex();
      99              : }
     100              : 
     101              : bool
     102      1054390 : MSTransportable::proceed(MSNet* net, SUMOTime time, const bool vehicleArrived) {
     103      1054390 :     MSStage* const prior = *myStep;
     104      1054390 :     const std::string& error = prior->setArrived(net, this, time, vehicleArrived);
     105              :     // must be done before increasing myStep to avoid invalid state for rendering
     106      1054390 :     prior->getEdge()->removeTransportable(this);
     107              :     myStep++;
     108      1054390 :     if (error != "") {
     109           52 :         throw ProcessError(error);
     110              :     }
     111              :     /* We need to check whether an access stage is needed (or maybe even two).
     112              :        The general scheme is: If the prior stage ended at a stop and the next stage
     113              :        starts at an edge which is not the one the stop is at, but the stop has an access to it
     114              :        we need an access stage. The same is true if prior ends at an edge, the next stage
     115              :        is allowed to start at any stop the edge has access to.
     116              :        If we start at a stop or end at a stop no access is needed.
     117              :     */
     118              :     bool accessToStop = false;
     119      1054338 :     if (prior->getStageType() == MSStageType::WALKING || prior->getStageType() == MSStageType::DRIVING) {
     120       234272 :         accessToStop = checkAccess(prior);
     121       820066 :     } else if (prior->getStageType() == MSStageType::WAITING_FOR_DEPART) {
     122       450968 :         for (MSTransportableDevice* const dev : myDevices) {
     123         2467 :             dev->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED, nullptr);
     124              :         }
     125              :     }
     126      1054338 :     if (!accessToStop && (myStep == myPlan->end()
     127       677516 :                           || ((*myStep)->getStageType() != MSStageType::DRIVING
     128       598338 :                               && (*myStep)->getStageType() != MSStageType::TRIP))) {
     129       806703 :         MSStoppingPlace* priorStop = prior->getStageType() == MSStageType::TRIP ? prior->getOriginStop() : prior->getDestinationStop();
     130              :         // a trip might resolve to DRIVING so we would have to stay at the stop
     131              :         // if a trip resolves to something else, this step will do stop removal
     132       806703 :         if (priorStop != nullptr) {
     133       173895 :             priorStop->removeTransportable(this);
     134              :         }
     135              :     }
     136      1054338 :     if (myStep != myPlan->end()) {
     137       679606 :         if ((*myStep)->getStageType() == MSStageType::WALKING && (prior->getStageType() != MSStageType::ACCESS || prior->getDestination() != (*myStep)->getFromEdge())) {
     138       228510 :             checkAccess(prior, false);
     139       902247 :         } else if ((*myStep)->getStageType() == MSStageType::WAITING && prior->getStageType() == MSStageType::WAITING && prior->getDestination() != (*myStep)->getFromEdge()) {
     140           22 :             checkAccess(prior, false);
     141              :         }
     142       679606 :         (*myStep)->proceed(net, this, time, prior);
     143              :         return true;
     144              :     } else {
     145       374732 :         MSNet::getInstance()->getPersonControl().addArrived();
     146       374732 :         return false;
     147              :     }
     148              : }
     149              : 
     150              : 
     151              : void
     152            0 : MSTransportable::setID(const std::string& /*newID*/) {
     153            0 :     throw ProcessError(TL("Changing a transportable ID is not permitted"));
     154              : }
     155              : 
     156              : SUMOTime
     157            0 : MSTransportable::getDesiredDepart() const {
     158            0 :     return myParameter->depart;
     159              : }
     160              : 
     161              : void
     162       464293 : MSTransportable::setDeparted(SUMOTime now) {
     163       464293 :     (*myStep)->setDeparted(now);
     164       464293 : }
     165              : 
     166              : SUMOTime
     167          122 : MSTransportable::getDeparture() const {
     168          122 :     for (const MSStage* const stage : *myPlan) {
     169          122 :         if (stage->getDeparted() >= 0) {
     170          122 :             return stage->getDeparted();
     171              :         }
     172              :     }
     173              :     return -1;
     174              : }
     175              : 
     176              : const MSEdge*
     177            0 : MSTransportable::getCurrentEdge() const {
     178            0 :     const MSLane* lane = getLane();
     179            0 :     return lane == nullptr ? getEdge() : &lane->getEdge();
     180              : }
     181              : 
     182              : double
     183      9826362 : MSTransportable::getEdgePos() const {
     184      9826362 :     return (*myStep)->getEdgePos(MSNet::getInstance()->getCurrentTimeStep());
     185              : }
     186              : 
     187              : double
     188         4256 : MSTransportable::getBackPositionOnLane(const MSLane* /*lane*/) const {
     189         4256 :     return getEdgePos() - getVehicleType().getLength();
     190              : }
     191              : 
     192              : int
     193       370800 : MSTransportable::getDirection() const {
     194       370800 :     return (*myStep)->getDirection();
     195              : }
     196              : 
     197              : Position
     198     12501123 : MSTransportable::getPosition() const {
     199     12501123 :     return (*myStep)->getPosition(MSNet::getInstance()->getCurrentTimeStep());
     200              : }
     201              : 
     202              : double
     203      6839120 : MSTransportable::getAngle() const {
     204      6839120 :     return (*myStep)->getAngle(MSNet::getInstance()->getCurrentTimeStep());
     205              : }
     206              : 
     207              : double
     208          612 : MSTransportable::getWaitingSeconds() const {
     209          612 :     return STEPS2TIME((*myStep)->getWaitingTime());
     210              : }
     211              : 
     212              : double
     213      4575458 : MSTransportable::getSpeed() const {
     214      4575458 :     return (*myStep)->getSpeed();
     215              : }
     216              : 
     217              : 
     218              : void
     219        57561 : MSTransportable::tripInfoOutput(OutputDevice& os) const {
     220        57561 :     SUMOTime departure = myPlan->front()->getDeparted();
     221       115974 :     os.openTag(isPerson() ? "personinfo" : "containerinfo");
     222        57561 :     os.writeAttr(SUMO_ATTR_ID, getID());
     223        57561 :     os.writeAttr(SUMO_ATTR_DEPART, departure >= 0 ? time2string(departure) : "-1");
     224        57561 :     os.writeAttr(SUMO_ATTR_TYPE, getVehicleType().getID());
     225        57561 :     if (isPerson()) {
     226        56709 :         os.writeAttr(SUMO_ATTR_SPEEDFACTOR, getChosenSpeedFactor());
     227              :     }
     228              :     SUMOTime duration = 0;
     229              :     SUMOTime waitingTime = 0;
     230              :     SUMOTime timeLoss = 0;
     231              :     SUMOTime travelTime = 0;
     232              :     bool durationOK = true;
     233              :     bool waitingTimeOK = true;
     234              :     bool timeLossOK = true;
     235              :     bool travelTimeOK = true;
     236       192739 :     for (MSStage* const i : *myPlan) {
     237       135178 :         SUMOTime t = i->getDuration();
     238       135178 :         if (t != SUMOTime_MAX) {
     239       134470 :             duration += t;
     240              :         } else {
     241              :             durationOK = false;
     242              :         }
     243       135178 :         t = i->getTotalWaitingTime();
     244       135178 :         if (t != SUMOTime_MAX) {
     245       135142 :             waitingTime += t;
     246              :         } else {
     247              :             waitingTimeOK = false;
     248              :         }
     249       135178 :         t = i->getTimeLoss(this);
     250       135178 :         if (t != SUMOTime_MAX) {
     251       134839 :             timeLoss += t;
     252              :         } else {
     253              :             timeLossOK = false;
     254              :         }
     255       135178 :         t = i->getTravelTime();
     256       135178 :         if (t != SUMOTime_MAX) {
     257       134472 :             travelTime += t;
     258              :         } else {
     259              :             travelTimeOK = false;
     260              :         }
     261              :     }
     262        57561 :     os.writeAttr(SUMO_ATTR_DURATION, durationOK ? time2string(duration) : "-1");
     263        57561 :     os.writeAttr(SUMO_ATTR_WAITINGTIME, waitingTimeOK ? time2string(waitingTime) : "-1");
     264        57561 :     os.writeAttr(SUMO_ATTR_TIMELOSS, timeLossOK ? time2string(timeLoss) : "-1");
     265        57561 :     os.writeAttr(SUMO_ATTR_TRAVELTIME, travelTimeOK ? time2string(travelTime) : "-1");
     266       192739 :     for (MSStage* const i : *myPlan) {
     267       135178 :         i->tripInfoOutput(os, this);
     268              :     }
     269        57561 :     os.closeTag();
     270        57561 : }
     271              : 
     272              : 
     273              : void
     274         3702 : MSTransportable::routeOutput(OutputDevice& os, const bool withRouteLength) const {
     275              :     const std::string typeID = (
     276         7328 :                                    (isPerson() && getVehicleType().getID() == DEFAULT_PEDTYPE_ID)
     277         7328 :                                    || (isContainer() && getVehicleType().getID() == DEFAULT_CONTAINERTYPE_ID)) ? "" : getVehicleType().getID();
     278         3778 :     myParameter->write(os, OptionsCont::getOptions(), isPerson() ? SUMO_TAG_PERSON : SUMO_TAG_CONTAINER, typeID);
     279         3702 :     if (hasArrived()) {
     280         7116 :         os.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
     281              :     }
     282              :     const MSStage* previous = nullptr;
     283         3702 :     const bool withTiming = OptionsCont::getOptions().getBool("vehroute-output.exit-times");
     284        14282 :     for (const MSStage* const stage : *myPlan) {
     285        10580 :         stage->routeOutput(myAmPerson, os, withRouteLength, previous, withTiming);
     286              :         previous = stage;
     287              :     }
     288         3702 :     myParameter->writeParams(os);
     289         3702 :     os.closeTag();
     290         3702 :     os.lf();
     291         3702 : }
     292              : 
     293              : 
     294              : void
     295           32 : MSTransportable::setAbortWaiting(const SUMOTime timeout) {
     296           32 :     if (timeout < 0 && myAbortCommand != nullptr) {
     297              :         myAbortCommand->deschedule();
     298           16 :         myAbortCommand = nullptr;
     299           16 :         return;
     300              :     }
     301           16 :     myAbortCommand = new WrappingCommand<MSTransportable>(this, &MSTransportable::abortStage);
     302           16 :     MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myAbortCommand, SIMSTEP + timeout);
     303              : }
     304              : 
     305              : 
     306              : SUMOTime
     307           16 : MSTransportable::abortStage(SUMOTime step) {
     308           48 :     WRITE_WARNINGF(TL("Teleporting % '%'; waited too long, from edge '%', time=%."),
     309              :                    isPerson() ? "person" : "container", getID(), (*myStep)->getEdge()->getID(), time2string(step));
     310           16 :     MSTransportableControl& tc = isPerson() ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl();
     311              :     tc.registerTeleportAbortWait();
     312           16 :     (*myStep)->abort(this);
     313           16 :     if (!proceed(MSNet::getInstance(), step)) {
     314            8 :         tc.erase(this);
     315              :     }
     316           16 :     return 0;
     317              : }
     318              : 
     319              : 
     320              : void
     321       174270 : MSTransportable::appendStage(MSStage* stage, int next) {
     322              :     // myStep is invalidated upon modifying myPlan
     323       174270 :     const int stepIndex = (int)(myStep - myPlan->begin());
     324       174270 :     if (next < 0) {
     325          394 :         myPlan->push_back(stage);
     326              :     } else {
     327       173876 :         if (stepIndex + next > (int)myPlan->size()) {
     328            0 :             throw ProcessError("invalid index '" + toString(next) + "' for inserting new stage into plan of '" + getID() + "'");
     329              :         }
     330       173876 :         myPlan->insert(myPlan->begin() + stepIndex + next, stage);
     331              :     }
     332       174270 :     myStep = myPlan->begin() + stepIndex;
     333       174270 : }
     334              : 
     335              : 
     336              : void
     337         1911 : MSTransportable::removeStage(int next, bool stayInSim) {
     338              :     assert(myStep + next < myPlan->end());
     339              :     assert(next >= 0);
     340         1911 :     if (next > 0) {
     341              :         // myStep is invalidated upon modifying myPlan
     342           82 :         int stepIndex = (int)(myStep - myPlan->begin());
     343           82 :         delete *(myStep + next);
     344           82 :         myPlan->erase(myStep + next);
     345           82 :         myStep = myPlan->begin() + stepIndex;
     346              :     } else {
     347         1829 :         if (myStep + 1 == myPlan->end() && stayInSim) {
     348              :             // stay in the simulation until the start of simStep to allow appending new stages (at the correct position)
     349          166 :             appendStage(new MSStageWaiting(getEdge(), nullptr, 0, 0, getEdgePos(), "last stage removed", false));
     350         1746 :         } else if (myStep + 1 != myPlan->end()) {
     351         3118 :             (*(myStep + 1))->setOrigin(getEdge(), getEdge() == getFromEdge() ? (*myStep)->getOriginStop() : nullptr, getEdgePos());
     352              :         }
     353         1829 :         (*myStep)->abort(this);
     354         1829 :         if (!proceed(MSNet::getInstance(), SIMSTEP)) {
     355          187 :             MSNet::getInstance()->getPersonControl().erase(this);
     356         1642 :         } else if (myPlan->front()->getDeparted() < 0) {
     357           42 :             myPlan->front()->setDeparted(SIMSTEP);
     358              :         }
     359              :     }
     360         1911 : }
     361              : 
     362              : 
     363              : void
     364           13 : MSTransportable::setSpeed(double speed) {
     365           35 :     for (MSTransportablePlan::const_iterator i = myStep; i != myPlan->end(); ++i) {
     366           22 :         (*i)->setSpeed(speed);
     367              :     }
     368           13 :     getSingularType().setMaxSpeed(speed);
     369           13 : }
     370              : 
     371              : 
     372              : bool
     373            0 : MSTransportable::replaceRoute(ConstMSRoutePtr newRoute, const std::string& /* info */, bool /* onInit */, int /* offset */, bool /* addRouteStops */, bool /* removeStops */, std::string* /* msgReturn */) {
     374            0 :     if (isPerson()) {
     375            0 :         static_cast<MSPerson*>(this)->replaceWalk(newRoute->getEdges(), getPositionOnLane(), 0, 1);
     376            0 :         return true;
     377              :     }
     378              :     return false;
     379              : }
     380              : 
     381              : 
     382              : bool
     383          100 : MSTransportable::reroute(SUMOTime t, const std::string& /* info */, MSTransportableRouter& router, const bool /* onInit */, const bool /* withTaz */, const bool /* silent */, const MSEdge* /* sink */) {
     384              :     MSStageTrip* trip = getCurrentStage()->getTrip();
     385          100 :     if (trip == nullptr) {
     386              :         // TODO this should be possible after factoring out MSStageTrip::reroute
     387              :         return false;
     388              :     }
     389          100 :     if (getCurrentStage()->getVehicle() != nullptr) {
     390              :         // TODO rerouting during a ride still needs to be implemented
     391              :         return false;
     392              :     }
     393              :     // find the final stage of the trip
     394              :     int tripEndOffset = -1;
     395           80 :     for (int i = getNumRemainingStages() - 1; i >= 0; i--) {
     396           80 :         if (getNextStage(i)->getTrip() == trip) {
     397              :             tripEndOffset = i;
     398              :             break;
     399              :         }
     400              :     }
     401              :     std::vector<MSStage*> stages;
     402           80 :     MSStageWaiting start(getEdge(), getCurrentStage()->getOriginStop(), -1, t, getEdgePos(), "start", true);
     403           80 :     if (trip->reroute(t, router, this, &start, getEdge(), getRerouteDestination(), stages) == "") {
     404              :         // check whether the new plan actually differs
     405          150 :         while (tripEndOffset >= 0 && !stages.empty() && stages.back()->equals(*getNextStage(tripEndOffset))) {
     406           70 :             delete stages.back();
     407              :             stages.pop_back();
     408           70 :             tripEndOffset--;
     409              :         }
     410              :         bool abortCurrent = true;
     411              :         // check whether the future route of the current stage is identical to the route
     412           80 :         if (!stages.empty() && stages.front()->isWalk() && getCurrentStage()->isWalk()) {
     413              :             // TODO this check should be done for rides as well
     414              :             MSStageMoving* s = static_cast<MSStageMoving*>(getCurrentStage());
     415           48 :             int routeIndex = (int)(s->getRouteStep() - s->getRoute().begin());
     416           48 :             ConstMSEdgeVector oldEdges = s->getEdges();
     417              :             oldEdges.erase(oldEdges.begin(), oldEdges.begin() + routeIndex);
     418           48 :             ConstMSEdgeVector newEdges = stages.front()->getEdges();
     419           48 :             if (newEdges == oldEdges) {
     420           48 :                 delete stages.front();
     421              :                 stages.erase(stages.begin());
     422              :                 abortCurrent = false;
     423              :             }
     424           48 :         }
     425           80 :         if (stages.empty()) {
     426              :             return false;
     427              :         }
     428              :         // remove future stages of the trip
     429           12 :         for (int i = tripEndOffset; i >= 1; i--) {
     430            6 :             removeStage(i);
     431              :         }
     432              :         // insert new stages of the rerouting
     433              :         int idx = 1;
     434           12 :         for (MSStage* stage : stages) {
     435            6 :             appendStage(stage, idx++);
     436              :         }
     437            6 :         if (abortCurrent) {
     438            0 :             removeStage(0);
     439              :         }
     440            6 :         return true;
     441              :     }
     442              :     return false;
     443           80 : }
     444              : 
     445              : 
     446              : void
     447          195 : MSTransportable::replaceVehicleType(const MSVehicleType* type) {
     448          195 :     const SUMOVehicleClass oldVClass = myVType->getVehicleClass();
     449          195 :     if (myVType->isVehicleSpecific()) {
     450            1 :         MSNet::getInstance()->getVehicleControl().removeVType(myVType);
     451              :     }
     452          195 :     if (isPerson()
     453          195 :             && type->getVehicleClass() != oldVClass
     454           10 :             && type->getVehicleClass() != SVC_PEDESTRIAN
     455          200 :             && !type->getParameter().wasSet(VTYPEPARS_VEHICLECLASS_SET)) {
     456           15 :         WRITE_WARNINGF(TL("Person '%' receives type '%' which implicitly uses unsuitable vClass '%'."), getID(), type->getID(), toString(type->getVehicleClass()));
     457              :     }
     458          195 :     myVType = type;
     459          195 : }
     460              : 
     461              : 
     462              : MSVehicleType&
     463          201 : MSTransportable::getSingularType() {
     464          201 :     if (myVType->isVehicleSpecific()) {
     465              :         return *const_cast<MSVehicleType*>(myVType);
     466              :     }
     467          360 :     MSVehicleType* type = myVType->buildSingularType(myVType->getID() + "@" + getID());
     468          180 :     replaceVehicleType(type);
     469          180 :     return *type;
     470              : }
     471              : 
     472              : 
     473              : PositionVector
     474      1157890 : MSTransportable::getBoundingBox() const {
     475      1157890 :     PositionVector centerLine;
     476      1157890 :     const Position p = getPosition();
     477      1157890 :     const double angle = getAngle();
     478      1157890 :     const double length = getVehicleType().getLength();
     479      1157890 :     const Position back = p + Position(-cos(angle) * length, -sin(angle) * length);
     480      1157890 :     centerLine.push_back(p);
     481      1157890 :     centerLine.push_back(back);
     482      1157890 :     centerLine.move2side(0.5 * getVehicleType().getWidth());
     483              :     PositionVector result = centerLine;
     484      1157890 :     centerLine.move2side(-getVehicleType().getWidth());
     485      1157890 :     result.append(centerLine.reverse(), POSITION_EPS);
     486              :     //std::cout << " transp=" << getID() << " p=" << p << " angle=" << GeomHelper::naviDegree(angle) << " back=" << back << " result=" << result << "\n";
     487      1157890 :     return result;
     488      1157890 : }
     489              : 
     490              : 
     491              : std::string
     492            0 : MSTransportable::getStageSummary(int stageIndex) const {
     493              :     assert(stageIndex < (int)myPlan->size());
     494              :     assert(stageIndex >= 0);
     495            0 :     return (*myPlan)[stageIndex]->getStageSummary(myAmPerson);
     496              : }
     497              : 
     498              : 
     499              : const std::set<SUMOTrafficObject::NumericalID>
     500            0 : MSTransportable::getUpcomingEdgeIDs() const {
     501              :     std::set<SUMOTrafficObject::NumericalID> result;
     502            0 :     for (auto step = myStep; step != myPlan->end(); ++step) {
     503            0 :         for (const MSEdge* const e : (*step)->getEdges()) {
     504            0 :             result.insert(e->getNumericalID());
     505            0 :         }
     506              :     }
     507            0 :     return result;
     508              : }
     509              : 
     510              : 
     511              : bool
     512      4667775 : MSTransportable::hasArrived() const {
     513      4667775 :     return myStep == myPlan->end();
     514              : }
     515              : 
     516              : bool
     517       465491 : MSTransportable::hasDeparted() const {
     518       465491 :     return myPlan->size() > 0 && (myPlan->front()->getDeparted() >= 0 || myStep > myPlan->begin());
     519              : }
     520              : 
     521              : 
     522              : void
     523           44 : MSTransportable::rerouteParkingArea(MSStoppingPlace* orig, MSStoppingPlace* replacement) {
     524              :     // check whether the transportable was riding to the orignal stop
     525              :     // @note: parkingArea can currently not be set as myDestinationStop so we
     526              :     // check for stops on the edge instead
     527              : #ifdef DEBUG_PARKING
     528              :     std::cout << SIMTIME << " person=" << getID() << " rerouteParkingArea orig=" << orig->getID() << " replacement=" << replacement->getID() << "\n";
     529              : #endif
     530              :     assert(getCurrentStageType() == MSStageType::DRIVING);
     531           44 :     if (!myAmPerson) {
     532            0 :         WRITE_WARNING(TL("parkingAreaReroute not supported for containers"));
     533            0 :         return;
     534              :     }
     535           44 :     if (getDestination() == &orig->getLane().getEdge()) {
     536           44 :         MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(*myStep);
     537              :         assert(stage != 0);
     538              :         assert(stage->getVehicle() != 0);
     539              :         // adapt plan
     540           44 :         stage->setDestination(&replacement->getLane().getEdge(), replacement);
     541           44 :         stage->setArrivalPos((replacement->getBeginLanePosition() + replacement->getEndLanePosition()) / 2);
     542              : #ifdef DEBUG_PARKING
     543              :         std::cout << " set ride destination\n";
     544              : #endif
     545           44 :         if (myStep + 1 == myPlan->end()) {
     546              :             return;
     547              :         }
     548              :         // if the next step is a walk, adapt the route
     549           44 :         MSStage* nextStage = *(myStep + 1);
     550           44 :         if (nextStage->getStageType() == MSStageType::TRIP) {
     551           34 :             dynamic_cast<MSStageTrip*>(nextStage)->setOrigin(stage->getDestination(), stage->getDestinationStop(), stage->getArrivalPos());
     552              : #ifdef DEBUG_PARKING
     553              :             std::cout << " set subsequent trip origin\n";
     554              : #endif
     555           10 :         } else if (nextStage->getStageType() == MSStageType::WALKING) {
     556              : #ifdef DEBUG_PARKING
     557              :             std::cout << " replace subsequent walk with a trip\n";
     558              : #endif
     559              :             MSStageTrip* newStage = new MSStageTrip(stage->getDestination(), nullptr, nextStage->getDestination(),
     560            5 :                                                     nextStage->getDestinationStop(), -1, 0, "", -1, 1, getID(), 0, true, nextStage->getArrivalPos());
     561            5 :             removeStage(1);
     562            5 :             appendStage(newStage, 1);
     563            5 :         } else if (nextStage->getStageType() == MSStageType::WAITING) {
     564              : #ifdef DEBUG_PARKING
     565              :             std::cout << " add subsequent walk to reach stop\n";
     566              :             std::cout << "   arrivalPos=" << nextStage->getArrivalPos() << "\n";
     567              : #endif
     568              :             MSStageTrip* newStage = new MSStageTrip(stage->getDestination(), nullptr, nextStage->getDestination(),
     569            5 :                                                     nextStage->getDestinationStop(), -1, 0, "", -1, 1, getID(), 0, true, nextStage->getArrivalPos());
     570            5 :             appendStage(newStage, 1);
     571              :         }
     572              :         // if the plan contains another ride with the same vehicle from the same
     573              :         // parking area, adapt the preceeding walk to end at the replacement
     574           89 :         for (auto it = myStep + 2; it != myPlan->end(); it++) {
     575           55 :             MSStage* const futureStage = *it;
     576           55 :             MSStage* const prevStage = *(it - 1);
     577           55 :             if (futureStage->getStageType() == MSStageType::DRIVING) {
     578              :                 MSStageDriving* const ds = static_cast<MSStageDriving*>(futureStage);
     579              :                 // ride origin is set implicitly from the walk destination
     580           10 :                 ds->setOrigin(nullptr, nullptr, -1);
     581              :                 if (ds->getLines() == stage->getLines()
     582           10 :                         && prevStage->getDestination() == &orig->getLane().getEdge()) {
     583           10 :                     if (prevStage->getStageType() == MSStageType::TRIP) {
     584            5 :                         dynamic_cast<MSStageTrip*>(prevStage)->setDestination(stage->getDestination(), replacement);
     585              : #ifdef DEBUG_PARKING
     586              :                         std::cout << " replace later trip before ride (" << (it - myPlan->begin()) << ")\n";
     587              : #endif
     588            5 :                     } else if (prevStage->getStageType() == MSStageType::WALKING) {
     589              : #ifdef DEBUG_PARKING
     590              :                         std::cout << " replace later walk before ride (" << (it - myPlan->begin()) << ")\n";
     591              : #endif
     592            5 :                         MSStageTrip* newStage = new MSStageTrip(prevStage->getFromEdge(), nullptr, stage->getDestination(),
     593           10 :                                                                 replacement, -1, 0, "", -1, 1, getID(), 0, true, stage->getArrivalPos());
     594            5 :                         int prevStageRelIndex = (int)(it - 1 - myStep);
     595            5 :                         removeStage(prevStageRelIndex);
     596            5 :                         appendStage(newStage, prevStageRelIndex);
     597              :                     }
     598              :                     break;
     599              :                 }
     600              :             }
     601              :         }
     602              :     }
     603              : }
     604              : 
     605              : 
     606              : MSDevice*
     607      2398454 : MSTransportable::getDevice(const std::type_info& type) const {
     608      2610938 :     for (MSTransportableDevice* const dev : myDevices) {
     609      2486799 :         if (typeid(*dev) == type) {
     610              :             return dev;
     611              :         }
     612              :     }
     613              :     return nullptr;
     614              : }
     615              : 
     616              : 
     617              : void
     618           10 : MSTransportable::setJunctionModelParameter(const std::string& key, const std::string& value) {
     619           15 :     if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
     620            5 :         getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
     621            5 :         const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
     622              :         // checked in MSLink::ignoreFoe
     623              :     } else {
     624           15 :         throw InvalidArgument(getObjectType() + " '" + getID() + "' does not support junctionModel parameter '" + key + "'");
     625              :     }
     626            5 : }
     627              : 
     628              : 
     629              : double
     630            0 : MSTransportable::getSlope() const {
     631            0 :     const MSEdge* edge = getEdge();
     632            0 :     const double ep = getEdgePos();
     633            0 :     const double gp = edge->getLanes()[0]->interpolateLanePosToGeometryPos(ep);
     634            0 :     return edge->getLanes()[0]->getShape().slopeDegreeAtOffset(gp);
     635              : }
     636              : 
     637              : 
     638              : SUMOTime
     639         9220 : MSTransportable::getWaitingTime(const bool /* accumulated */) const {
     640         9220 :     return (*myStep)->getWaitingTime();
     641              : }
     642              : 
     643              : 
     644              : double
     645    106603268 : MSTransportable::getMaxSpeed() const {
     646    106603268 :     return MIN2(getVehicleType().getMaxSpeed(), getVehicleType().getDesiredMaxSpeed() * getChosenSpeedFactor());
     647              : }
     648              : 
     649              : 
     650              : SUMOVehicleClass
     651      2408910 : MSTransportable::getVClass() const {
     652      2408910 :     return getVehicleType().getVehicleClass();
     653              : }
     654              : 
     655              : 
     656              : int
     657            0 : MSTransportable::getRoutingMode() const {
     658              :     /// @todo: allow configuring routing mode
     659            0 :     return libsumo::ROUTING_MODE_DEFAULT;
     660              : }
     661              : 
     662              : void
     663          215 : MSTransportable::saveState(OutputDevice& out) {
     664              :     // this saves lots of departParameters which are only needed for transportables that did not yet depart
     665              :     // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
     666          215 :     const SUMOTime desiredDepart = myParameter->depart;
     667          215 :     if (myPlan->front()->getDeparted() >= 0) {
     668              :         // this is only relevant in the context of delayed departure (max-num-persons)
     669          130 :         const_cast<SUMOVehicleParameter*>(myParameter)->depart = myPlan->front()->getDeparted();
     670              :     }
     671          215 :     myParameter->write(out, OptionsCont::getOptions(), myAmPerson ? SUMO_TAG_PERSON : SUMO_TAG_CONTAINER, getVehicleType().getID());
     672          215 :     const_cast<SUMOVehicleParameter*>(myParameter)->depart = desiredDepart;
     673          215 :     if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
     674          215 :         out.setPrecision(MAX2(gPrecisionRandom, gPrecision));
     675          215 :         out.writeAttr(SUMO_ATTR_SPEEDFACTOR, getChosenSpeedFactor());
     676          215 :         out.setPrecision(gPrecision);
     677              :     }
     678          215 :     int stepIdx = (int)(myStep - myPlan->begin());
     679          385 :     for (auto it = myPlan->begin(); it != myStep; ++it) {
     680          170 :         const MSStageType st = (*it)->getStageType();
     681          170 :         if (st == MSStageType::TRIP || st == MSStageType::ACCESS) {
     682           30 :             stepIdx--;
     683              :         }
     684              :     }
     685          215 :     const bool isAccess = (*myStep)->getStageType() == MSStageType::ACCESS;
     686          215 :     std::ostringstream state;
     687          645 :     state << myParameter->parametersSet << " " << (isAccess ? toString(stepIdx - 0.5, 1) : toString(stepIdx));
     688          215 :     (*myStep)->saveState(state, this);
     689          215 :     out.writeAttr(SUMO_ATTR_STATE, state.str());
     690              :     const MSStage* previous = nullptr;
     691          691 :     for (const MSStage* const stage : *myPlan) {
     692          476 :         const bool routeLength = stage->getDeparted() >= 0 && stage->getStageType() == MSStageType::DRIVING;
     693          476 :         const bool withTiming = stage->getDeparted() >= 0;
     694          476 :         stage->routeOutput(myAmPerson, out, routeLength, previous, withTiming, true);
     695              :         previous = stage;
     696              :     }
     697          215 :     out.closeTag();
     698          215 : }
     699              : 
     700              : 
     701              : void
     702          219 : MSTransportable::loadState(const std::string& state) {
     703          219 :     std::istringstream iss(state);
     704              :     double step;
     705          219 :     iss >> myParameter->parametersSet >> step;
     706          219 :     myPlan->front()->setDeparted(myParameter->depart);
     707          219 :     if (step != floor(step)) {
     708              :         // we are in an access stage
     709            2 :         int priorIndex = (int)(step - 0.5);
     710            2 :         MSStage* prior = *(myPlan->begin() + priorIndex);
     711            2 :         myStep = myPlan->begin() + priorIndex + 1;
     712              :         bool waitAtStop = prior->getDestinationStop() != nullptr
     713            2 :             && &prior->getDestinationStop()->getLane().getEdge() != prior->getDestination();
     714            2 :         checkAccess(prior, waitAtStop);
     715              :         //std::cout << " step=" << step << " i=" << getCurrentStageIndex() << " stage=" << getStageSummary(true) << "\n";
     716              :     } else {
     717          217 :         myStep = myPlan->begin() + (int)step;
     718              :     }
     719          219 :     (*myStep)->loadState(this, iss);
     720          229 :     for (int i = 1; i < step; i++) {
     721           10 :         if ((*myPlan)[i]->getStageType() == MSStageType::DRIVING) {
     722            4 :             dynamic_cast<MSStageDriving*>((*myPlan)[i])->setWaitingSince((*myPlan)[i - 1]->getArrived());
     723              :         }
     724              :     }
     725          219 : }
     726              : 
     727              : 
     728              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1