LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSStageWalking.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 231 253 91.3 %
Date: 2024-05-07 15:28:01 Functions: 20 21 95.2 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-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    MSStageWalking.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @author  Laura Bieker
      19             : /// @date    Mon, 9 Jul 2001
      20             : ///
      21             : // A stage performing walking on a sequence of edges.
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <string>
      26             : #include <vector>
      27             : #include <utils/iodevices/OutputDevice.h>
      28             : #include <utils/options/OptionsCont.h>
      29             : #include <utils/common/ToString.h>
      30             : #include <utils/common/StringUtils.h>
      31             : #include <utils/geom/GeomHelper.h>
      32             : #include <utils/router/IntermodalNetwork.h>
      33             : #include <microsim/MSNet.h>
      34             : #include <microsim/MSEdge.h>
      35             : #include <microsim/MSLane.h>
      36             : #include <microsim/transportables/MSTransportableControl.h>
      37             : #include <microsim/MSInsertionControl.h>
      38             : #include <microsim/MSEventControl.h>
      39             : #include <microsim/MSVehicle.h>
      40             : #include <microsim/MSVehicleControl.h>
      41             : #include <microsim/MSStoppingPlace.h>
      42             : #include <microsim/MSRouteHandler.h>
      43             : #include <microsim/devices/MSDevice_Tripinfo.h>
      44             : #include <microsim/devices/MSDevice_Taxi.h>
      45             : #include <microsim/trigger/MSTriggeredRerouter.h>
      46             : #include "MSPModel_Striping.h"
      47             : #include "MSStageTrip.h"
      48             : #include "MSPerson.h"
      49             : #include "MSStageWalking.h"
      50             : 
      51             : 
      52             : // ===========================================================================
      53             : // static member definition
      54             : // ===========================================================================
      55             : bool MSStageWalking::myWarnedInvalidTripinfo = false;
      56             : 
      57             : 
      58             : // ===========================================================================
      59             : // method definitions
      60             : // ===========================================================================
      61      293142 : MSStageWalking::MSStageWalking(const std::string& personID,
      62             :                                const ConstMSEdgeVector& route,
      63             :                                MSStoppingPlace* toStop,
      64             :                                SUMOTime walkingTime, double speed,
      65             :                                double departPos, double arrivalPos, double departPosLat, int departLane,
      66      293142 :                                const std::string& routeID) :
      67             :     MSStageMoving(MSStageType::WALKING, route, routeID, toStop, speed, departPos, arrivalPos, departPosLat, departLane),
      68      293142 :     myWalkingTime(walkingTime),
      69      293142 :     myExitTimes(nullptr),
      70      293142 :     myInternalDistance(0) {
      71      293142 :     myDepartPos = SUMOVehicleParameter::interpretEdgePos(departPos, route.front()->getLength(), SUMO_ATTR_DEPARTPOS,
      72      586284 :                   "person '" + personID + "' walking from edge '" + route.front()->getID() + "'");
      73      293142 :     myArrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, route.back()->getLength(), SUMO_ATTR_ARRIVALPOS,
      74      586284 :                    "person '" + personID + "' walking to edge '" + route.back()->getID() + "'");
      75      293142 :     if (walkingTime > 0) {
      76          96 :         mySpeed = computeAverageSpeed();
      77             :     }
      78      293142 : }
      79             : 
      80             : 
      81      586206 : MSStageWalking::~MSStageWalking() {
      82      293229 :     delete myExitTimes;
      83      586206 : }
      84             : 
      85             : 
      86             : MSStage*
      87       22311 : MSStageWalking::clone() const {
      88       22311 :     std::vector<const MSEdge*> route = myRoute;
      89       22311 :     double departPos = myDepartPos;
      90       22311 :     double arrivalPos = myArrivalPos;
      91       22311 :     int departLane = myDepartLane;
      92       22311 :     if (myRouteID != "" && MSRoute::distDictionary(myRouteID) != nullptr) {
      93         576 :         route = MSRoute::dictionary(myRouteID, MSRouteHandler::getParsingRNG())->getEdges();
      94         288 :         if (departPos > route[0]->getLength()) {
      95           0 :             WRITE_WARNINGF(TL("Adjusting departPos for cloned walk with routeDistribution '%'"), myRouteID);
      96           0 :             departPos = route[0]->getLength();
      97             :         }
      98         288 :         if (arrivalPos > route.back()->getLength()) {
      99           0 :             WRITE_WARNINGF(TL("Adjusting arrivalPos for cloned walk with routeDistribution '%'"), myRouteID);
     100           0 :             arrivalPos = route.back()->getLength();
     101             :         }
     102         288 :         if (departLane >= route[0]->getNumLanes()) {
     103           0 :             WRITE_WARNINGF(TL("Adjusting departLane for cloned walk with routeDistribution '%'"), myRouteID);
     104           0 :             departLane = route[0]->getNumLanes() - 1;
     105             :         }
     106             :     }
     107       22311 :     MSStage* clon = new MSStageWalking("dummyID", route, myDestinationStop, myWalkingTime, mySpeed, departPos, arrivalPos, myDepartPosLat, departLane, myRouteID);
     108       22311 :     clon->setParameters(*this);
     109       22311 :     return clon;
     110             : }
     111             : 
     112             : 
     113             : void
     114      292632 : MSStageWalking::proceed(MSNet* net, MSTransportable* person, SUMOTime now, MSStage* previous) {
     115      292632 :     myDeparted = now;
     116      292632 :     myRouteStep = myRoute.begin();
     117      292632 :     myLastEdgeEntryTime = now;
     118      292632 :     if (myWalkingTime == 0) {
     119           0 :         if (!person->proceed(net, now)) {
     120           0 :             MSNet::getInstance()->getPersonControl().erase(person);
     121             :         }
     122           0 :         return;
     123             :     }
     124      292632 :     if (previous->getEdgePos(now) >= 0 && previous->getEdge() == *myRouteStep) {
     125             :         // we need to adapt to the arrival position of the vehicle unless we have an explicit access
     126      290475 :         myDepartPos = previous->getEdgePos(now);
     127      290475 :         const OptionsCont& oc = OptionsCont::getOptions();
     128      580950 :         const std::string model = oc.getString("pedestrian.model");
     129      290475 :         if (model != "jupedsim") {
     130      290475 :             if (previous->getStageType() == MSStageType::ACCESS) {
     131        2356 :                 const Position& lastPos = previous->getPosition(now);
     132             :                 // making a wild guess on where we actually want to depart laterally
     133        2356 :                 const double possibleDepartPosLat = lastPos.distanceTo(previous->getEdgePosition(previous->getEdge(), myDepartPos, 0.));
     134        2356 :                 const Position& newPos = previous->getEdgePosition(previous->getEdge(), myDepartPos, -possibleDepartPosLat); // Minus sign is here for legacy reasons.
     135        2356 :                 if (lastPos.almostSame(newPos)) {
     136         522 :                     myDepartPosLat = possibleDepartPosLat;
     137        3668 :                 } else if (lastPos.almostSame(previous->getEdgePosition(previous->getEdge(), myDepartPos, possibleDepartPosLat))) {
     138             :                     // maybe the other side of the street
     139         514 :                     myDepartPosLat = -possibleDepartPosLat;
     140             :                 }
     141             :             }
     142             :         } else {
     143           0 :             myDepartPosLat = previous->getEdgePosLat(now);
     144             :         }
     145      290475 :         if (myWalkingTime > 0) {
     146          70 :             mySpeed = computeAverageSpeed();
     147             :         }
     148             :     }
     149      292632 :     MSTransportableControl& pControl = net->getPersonControl();
     150      292632 :     myPState = pControl.getMovementModel()->add(person, this, now);
     151      292628 :     if (myPState == nullptr) {
     152           8 :         pControl.erase(person);
     153           8 :         return;
     154             :     }
     155      292620 :     if (previous->getStageType() != MSStageType::WALKING || previous->getEdge() != getEdge()) {
     156             :         // we only need new move reminders if we are walking a different edge (else it is probably a rerouting)
     157      291089 :         activateEntryReminders(person, true);
     158             :     }
     159      585240 :     if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
     160         126 :         myExitTimes = new std::vector<SUMOTime>();
     161             :     }
     162      292620 :     (*myRouteStep)->addTransportable(person);
     163             : }
     164             : 
     165             : 
     166             : void
     167        1579 : MSStageWalking::abort(MSTransportable*) {
     168        1579 :     MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
     169        1579 : }
     170             : 
     171             : 
     172             : void
     173          23 : MSStageWalking::setSpeed(double speed) {
     174          23 :     mySpeed = speed;
     175          23 : }
     176             : 
     177             : 
     178             : double
     179         166 : MSStageWalking::computeAverageSpeed() const {
     180         166 :     return walkDistance() / STEPS2TIME(myWalkingTime + 1); // avoid systematic rounding errors
     181             : }
     182             : 
     183             : 
     184             : bool
     185     1110602 : MSPerson::isJammed() const {
     186     1110602 :     MSStageWalking* stage = dynamic_cast<MSStageWalking*>(getCurrentStage());
     187     1110602 :     if (stage != nullptr) {
     188     1110602 :         return stage->getPState()->isJammed();
     189             :     }
     190             :     return false;
     191             : }
     192             : 
     193             : 
     194             : double
     195      239848 : MSStageWalking::walkDistance(bool partial) const {
     196             :     double length = 0;
     197      239848 :     auto endIt = partial && myArrived < 0 ? myRouteStep + 1 : myRoute.end();
     198      660815 :     for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt; ++i) {
     199      420967 :         length += (*i)->getLength();
     200             :     }
     201      239848 :     if (myRoute.size() > 1 && MSNet::getInstance()->getPersonControl().getMovementModel()->usingInternalLanes()) {
     202       91794 :         if (myInternalDistance > 0) {
     203       79715 :             length += myInternalDistance;
     204             :         } else {
     205             :             // use lower bound for distance to pass the intersection
     206       48154 :             for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt - 1; ++i) {
     207       36075 :                 const MSEdge* fromEdge = *i;
     208       36075 :                 const MSEdge* toEdge = *(i + 1);
     209       36075 :                 const MSLane* from = getSidewalk<MSEdge, MSLane>(fromEdge);
     210       36075 :                 const MSLane* to = getSidewalk<MSEdge, MSLane>(toEdge);
     211             :                 Position fromPos;
     212             :                 Position toPos;
     213       36075 :                 if (from != nullptr && to != nullptr) {
     214       36075 :                     if (fromEdge->getToJunction() == toEdge->getFromJunction()) {
     215       36025 :                         fromPos = from->getShape().back();
     216       36025 :                         toPos = to->getShape().front();
     217          50 :                     } else if (fromEdge->getToJunction() == toEdge->getToJunction()) {
     218          25 :                         fromPos = from->getShape().back();
     219          25 :                         toPos = to->getShape().back();
     220          25 :                     } else if (fromEdge->getFromJunction() == toEdge->getFromJunction()) {
     221          10 :                         fromPos = from->getShape().front();
     222          10 :                         toPos = to->getShape().front();
     223          15 :                     } else if (fromEdge->getFromJunction() == toEdge->getToJunction()) {
     224          15 :                         fromPos = from->getShape().front();
     225          15 :                         toPos = to->getShape().back();
     226             :                     }
     227             :                     //std::cout << " from=" << from->getID() << " to=" << to->getID() << " junctionLength=" << fromPos.distanceTo2D(toPos) << "\n";
     228       36075 :                     length += fromPos.distanceTo2D(toPos);
     229             :                 }
     230             :             }
     231             :         }
     232             :     }
     233             :     // determine walking direction for depart and arrival
     234      239848 :     int dummy = 0;
     235      239848 :     const int departFwdArrivalDir = MSPModel::canTraverse(MSPModel::FORWARD, myRoute, dummy);
     236      239848 :     const int departBwdArrivalDir = MSPModel::canTraverse(MSPModel::BACKWARD, myRoute, dummy);
     237      239848 :     const bool mayStartForward = departFwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
     238      239848 :     const bool mayStartBackward = departBwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
     239      239848 :     const double arrivalPos = partial && myArrived < 0 ? getEdgePos(SIMSTEP) : myArrivalPos;
     240      239848 :     const double lengthFwd = (length - myDepartPos - (
     241             :                                   departFwdArrivalDir == MSPModel::BACKWARD
     242      239848 :                                   ? arrivalPos
     243      239848 :                                   : myRoute.back()->getLength() - arrivalPos));
     244      239848 :     const double lengthBwd = (length - (myRoute.front()->getLength() - myDepartPos) - (
     245             :                                   departBwdArrivalDir == MSPModel::BACKWARD
     246      239848 :                                   ? arrivalPos
     247      239848 :                                   : myRoute.back()->getLength() - arrivalPos));
     248             :     //std::cout << " length=" << length << " lengthFwd=" << lengthFwd << " lengthBwd=" << lengthBwd << " mayStartForward=" << mayStartForward << " mayStartBackward=" << mayStartBackward << "\n";
     249             : 
     250      239848 :     if (myRoute.size() == 1) {
     251      129252 :         if (myDepartPos > myArrivalPos) {
     252             :             length = lengthBwd;
     253             :         } else {
     254             :             length = lengthFwd;
     255             :         }
     256             :     } else {
     257      110596 :         if (mayStartForward && mayStartBackward) {
     258       14935 :             length = lengthFwd < lengthBwd ? lengthFwd : lengthBwd;
     259       95661 :         } else if (mayStartForward) {
     260             :             length = lengthFwd;
     261       14816 :         } else if (mayStartBackward) {
     262             :             length = lengthBwd;
     263             :         } else {
     264             :             length = lengthFwd;
     265             :         }
     266             :     }
     267             :     //std::cout << SIMTIME << " route=" << toString(myRoute)
     268             :     //    << " depPos=" << myDepartPos << " arPos=" << myArrivalPos
     269             :     //    << " dFwdADir=" << departFwdArrivalDir
     270             :     //    << " dBwdADir=" << departBwdArrivalDir
     271             :     //    << " lengthFwd=" << lengthFwd
     272             :     //    << " lengthBwd=" << lengthBwd
     273             :     //    << "\n";
     274             : 
     275      239848 :     return MAX2(POSITION_EPS, length);
     276             : }
     277             : 
     278             : 
     279             : SUMOTime
     280       95854 : MSStageWalking::getTimeLoss(const MSTransportable* transportable) const {
     281       95854 :     SUMOTime timeLoss = myArrived == -1 ? 0 : getDuration() - TIME2STEPS(walkDistance(true) / getMaxSpeed(transportable));
     282       95854 :     if (timeLoss < 0 && timeLoss > TIME2STEPS(-0.1)) {
     283             :         // avoid negative timeLoss due to rounding errors
     284             :         timeLoss = 0;
     285             :     }
     286       95854 :     return timeLoss;
     287             : }
     288             : 
     289             : 
     290             : void
     291       47927 : MSStageWalking::tripInfoOutput(OutputDevice& os, const MSTransportable* const person) const {
     292       47927 :     if (!myWarnedInvalidTripinfo && MSNet::getInstance()->getPersonControl().getMovementModel()->usingShortcuts()) {
     293           0 :         WRITE_WARNING(TL("The pedestrian model uses infrastructure which is not in the network, timeLoss and routeLength may be invalid."));
     294           0 :         myWarnedInvalidTripinfo = true;
     295             :     }
     296       47927 :     const double distance = walkDistance(true);
     297       47927 :     const double maxSpeed = getMaxSpeed(person);
     298       47927 :     const SUMOTime duration = myArrived - myDeparted;
     299       47927 :     const SUMOTime timeLoss = getTimeLoss(person);
     300       47927 :     MSDevice_Tripinfo::addPedestrianData(distance, duration, timeLoss);
     301       47927 :     os.openTag("walk");
     302       95854 :     os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
     303       47927 :     os.writeAttr("departPos", myDepartPos);
     304       95854 :     os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
     305       95854 :     os.writeAttr("arrivalPos", myArrived >= 0 ? toString(myArrivalPos) : "-1");
     306      143767 :     os.writeAttr("duration", myDeparted < 0 ? "-1" :
     307       47913 :                  time2string(myArrived >= 0 ? duration : MSNet::getInstance()->getCurrentTimeStep() - myDeparted));
     308       95854 :     os.writeAttr("routeLength", myArrived >= 0 ? toString(distance) : "-1");
     309       95854 :     os.writeAttr("timeLoss", time2string(timeLoss));
     310       47927 :     os.writeAttr("maxSpeed", maxSpeed);
     311       47927 :     os.closeTag();
     312       47927 : }
     313             : 
     314             : 
     315             : void
     316        2113 : MSStageWalking::routeOutput(const bool /* isPerson */, OutputDevice& os, const bool withRouteLength, const MSStage* const /* previous */) const {
     317        2113 :     os.openTag("walk").writeAttr(SUMO_ATTR_EDGES, myRoute);
     318        2113 :     std::string comment = "";
     319        2113 :     if (myDestinationStop != nullptr) {
     320         311 :         os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
     321         622 :         if (myDestinationStop->getMyName() != "") {
     322         124 :             comment =  " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
     323             :         }
     324        1802 :     } else if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
     325         182 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
     326             :     }
     327        2113 :     if (myWalkingTime > 0) {
     328           0 :         os.writeAttr(SUMO_ATTR_DURATION, time2string(myWalkingTime));
     329        2113 :     } else if (mySpeed > 0) {
     330          24 :         os.writeAttr(SUMO_ATTR_SPEED, mySpeed);
     331             :     }
     332        2113 :     if (withRouteLength) {
     333          36 :         if (myDeparted >= 0) {
     334          72 :             os.writeAttr("routeLength", walkDistance(true));
     335             :         } else {
     336           0 :             os.writeAttr("routeLength", "-1");
     337             :         }
     338             :     }
     339        2113 :     if (myExitTimes != nullptr) {
     340             :         std::vector<std::string> exits;
     341         444 :         for (SUMOTime t : *myExitTimes) {
     342         636 :             exits.push_back(time2string(t));
     343             :         }
     344         252 :         std::vector<std::string> missing(MAX2(0, (int)myRoute.size() - (int)myExitTimes->size()), "-1");
     345         126 :         exits.insert(exits.end(), missing.begin(), missing.end());
     346         126 :         os.writeAttr("exitTimes", exits);
     347         126 :         os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
     348         126 :         os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
     349         126 :     }
     350        4226 :     if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
     351         210 :         os.writeAttr(SUMO_ATTR_COST, getCosts());
     352             :     }
     353        2113 :     os.closeTag(comment);
     354        2113 : }
     355             : 
     356             : 
     357             : bool
     358      983336 : MSStageWalking::moveToNextEdge(MSTransportable* person, SUMOTime currentTime, int prevDir, MSEdge* nextInternal) {
     359      983336 :     ((MSEdge*)getEdge())->removeTransportable(person);
     360      983336 :     const MSLane* lane = getSidewalk<MSEdge, MSLane>(getEdge());
     361             :     const bool arrived = myRouteStep == myRoute.end() - 1;
     362      983336 :     if (lane != nullptr) {
     363      983214 :         const double tl = person->getVehicleType().getLength();
     364             :         const double lastPos = (arrived
     365      983214 :                                 ? (prevDir == MSPModel::FORWARD
     366      316852 :                                    ? getArrivalPos() + tl
     367       27790 :                                    : getArrivalPos() - tl)
     368      694152 :                                 : person->getPositionOnLane());
     369      983214 :         activateLeaveReminders(person, lane, lastPos, currentTime, arrived);
     370             :     }
     371      983336 :     if (myExitTimes != nullptr && nextInternal == nullptr) {
     372         318 :         myExitTimes->push_back(currentTime);
     373             :     }
     374             :     myMoveReminders.clear();
     375      983336 :     myLastEdgeEntryTime = currentTime;
     376             :     //std::cout << SIMTIME << " moveToNextEdge person=" << person->getID() << "\n";
     377      983336 :     if (myCurrentInternalEdge != nullptr) {
     378      261816 :         myInternalDistance += (myPState->getPathLength() == 0 ? myCurrentInternalEdge->getLength() : myPState->getPathLength());
     379             :     }
     380      983336 :     if (arrived) {
     381      289088 :         MSPerson* p = dynamic_cast<MSPerson*>(person);
     382      289088 :         if (p->hasInfluencer() && p->getInfluencer().isRemoteControlled()) {
     383           0 :             myCurrentInternalEdge = nextInternal;
     384           0 :             ((MSEdge*) getEdge())->addTransportable(person);
     385           0 :             return false;
     386             :         }
     387      289088 :         if (myDestinationStop != nullptr) {
     388       36555 :             myDestinationStop->addTransportable(person);
     389             :         }
     390      289088 :         if (!person->proceed(MSNet::getInstance(), currentTime)) {
     391      282734 :             MSNet::getInstance()->getPersonControl().erase(person);
     392             :         }
     393             :         //std::cout << " end walk. myRouteStep=" << (*myRouteStep)->getID() << "\n";
     394      289088 :         return true;
     395             :     } else {
     396      694248 :         if (nextInternal == nullptr) {
     397             :             ++myRouteStep;
     398             :         }
     399      694248 :         myCurrentInternalEdge = nextInternal;
     400      694248 :         ((MSEdge*) getEdge())->addTransportable(person);
     401      694248 :         return false;
     402             :     }
     403             : }
     404             : 
     405             : 
     406             : void
     407      983214 : MSStageWalking::activateLeaveReminders(MSTransportable* person, const MSLane* lane, double lastPos, SUMOTime t, bool arrived) {
     408      983214 :     MSMoveReminder::Notification notification = arrived ? MSMoveReminder::NOTIFICATION_ARRIVED : MSMoveReminder::NOTIFICATION_JUNCTION;
     409     1058611 :     for (MSMoveReminder* const rem : myMoveReminders) {
     410       75397 :         rem->updateDetector(*person, 0.0, lane->getLength(), myLastEdgeEntryTime, t, t, true);
     411       75397 :         rem->notifyLeave(*person, lastPos, notification);
     412             :     }
     413      983214 : }
     414             : 
     415             : 
     416             : void
     417      985660 : MSStageWalking::activateEntryReminders(MSTransportable* person, const bool isDepart) {
     418      985660 :     const MSLane* const nextLane = getSidewalk<MSEdge, MSLane>(getEdge());
     419      985660 :     if (nextLane != nullptr) {
     420     1065702 :         for (MSMoveReminder* const rem : nextLane->getMoveReminders()) {
     421      153560 :             if (rem->notifyEnter(*person, isDepart ? MSMoveReminder::NOTIFICATION_DEPARTED : MSMoveReminder::NOTIFICATION_JUNCTION, nextLane)) {
     422       76522 :                 myMoveReminders.push_back(rem);
     423             :             }
     424             :         }
     425             :     }
     426     1971320 :     if (hasParameter("rerouter")) {
     427             :         double minDist = std::numeric_limits<double>::max();
     428             :         MSTriggeredRerouter* nearest = nullptr;
     429         190 :         for (MSMoveReminder* const rem : myMoveReminders) {
     430         120 :             MSTriggeredRerouter* rerouter = dynamic_cast<MSTriggeredRerouter*>(rem);
     431         120 :             if (rerouter != nullptr) {
     432          70 :                 const double dist2 = rerouter->getPosition().distanceSquaredTo2D(person->getPosition());
     433          70 :                 if (dist2 < minDist) {
     434             :                     nearest = rerouter;
     435             :                     minDist = dist2;
     436             :                 }
     437             :             }
     438             :         }
     439          70 :         if (nearest != nullptr) {
     440          70 :             nearest->triggerRouting(*person, MSMoveReminder::NOTIFICATION_JUNCTION);
     441             :         }
     442             :         // TODO maybe removal of the reminders? Or can we rely on movetonextedge to clean everything up?
     443             :     }
     444      985660 : }
     445             : 
     446             : 
     447             : int
     448      449430 : MSStageWalking::getRoutePosition() const {
     449      449430 :     return (int)(myRouteStep - myRoute.begin());
     450             : }
     451             : 
     452             : 
     453             : double
     454    52195909 : MSStageWalking::getMaxSpeed(const MSTransportable* const person) const {
     455    52195909 :     return mySpeed >= 0 ? mySpeed : person->getMaxSpeed();
     456             : }
     457             : 
     458             : std::string
     459           0 : MSStageWalking::getStageSummary(const bool /* isPerson */) const {
     460             :     const std::string dest = (getDestinationStop() == nullptr ?
     461           0 :                               " edge '" + getDestination()->getID() + "'" :
     462           0 :                               " stop '" + getDestinationStop()->getID() + "'" + (
     463           0 :                                   getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
     464           0 :     return "walking to " + dest;
     465             : }
     466             : 
     467             : 
     468             : void
     469          27 : MSStageWalking::saveState(std::ostringstream& out) {
     470          54 :     out << " " << myDeparted << " " << (myRouteStep - myRoute.begin()) << " " << myLastEdgeEntryTime;
     471          27 :     myPState->saveState(out);
     472          27 : }
     473             : 
     474             : 
     475             : void
     476          33 : MSStageWalking::loadState(MSTransportable* transportable, std::istringstream& state) {
     477             :     int stepIdx;
     478          33 :     state >> myDeparted >> stepIdx >> myLastEdgeEntryTime;
     479          33 :     myRouteStep = myRoute.begin() + stepIdx;
     480          33 :     myPState = MSNet::getInstance()->getPersonControl().getMovementModel()->loadState(transportable, this, state);
     481          33 :     if (myPState->getLane() && !myPState->getLane()->isNormal()) {
     482           2 :         myCurrentInternalEdge = &myPState->getLane()->getEdge();
     483           2 :         myCurrentInternalEdge->addTransportable(transportable);
     484             :     } else {
     485          31 :         (*myRouteStep)->addTransportable(transportable);
     486             :     }
     487          33 : }
     488             : 
     489             : 
     490             : /****************************************************************************/

Generated by: LCOV version 1.14