LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSPerson.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 158 143
Test Date: 2026-07-26 16:30:20 Functions: 87.1 % 31 27

            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    MSPerson.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              : // The class for modelling person-movements
      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_Taxi.h>
      44              : #include <microsim/trigger/MSTriggeredRerouter.h>
      45              : #include "MSPModel_Striping.h"
      46              : #include "MSStageTrip.h"
      47              : #include "MSStageWalking.h"
      48              : #include "MSPerson.h"
      49              : 
      50              : 
      51              : // ===========================================================================
      52              : // method definitions
      53              : // ===========================================================================
      54              : /* -------------------------------------------------------------------------
      55              : * MSPerson::MSPersonStage_Access - methods
      56              : * ----------------------------------------------------------------------- */
      57         4236 : MSPerson::MSPersonStage_Access::MSPersonStage_Access(const MSEdge* destination, MSStoppingPlace* toStop,
      58              :         const double arrivalPos, const double arrivalPosLat, const double dist, const bool isExit,
      59         4236 :         const Position& startPos, const Position& endPos) :
      60              :     MSStage(MSStageType::ACCESS, destination, toStop, arrivalPos, arrivalPosLat),
      61         8472 :     myDist(dist), myAmExit(isExit) {
      62         4236 :     myPath.push_back(startPos);
      63         4236 :     myPath.push_back(endPos);
      64         4236 : }
      65              : 
      66              : 
      67         8472 : MSPerson::MSPersonStage_Access::~MSPersonStage_Access() {}
      68              : 
      69              : MSStage*
      70            0 : MSPerson::MSPersonStage_Access::clone() const {
      71            0 :     return new MSPersonStage_Access(myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat, myDist, myAmExit, myPath.front(), myPath.back());
      72              : }
      73              : 
      74              : void
      75         4234 : MSPerson::MSPersonStage_Access::proceed(MSNet* net, MSTransportable* person, SUMOTime now, MSStage* previous) {
      76         4234 :     myDeparted = now;
      77         4234 :     if (myDist >= 0) {
      78         4220 :         myEstimatedArrival = now + TIME2STEPS(myDist / person->getMaxSpeed());
      79              :     } else {
      80           14 :         myEstimatedArrival = now + previous->getJumpDuration();
      81              :     }
      82              :     // TODO myEstimatedArrival is not a multiple of DELTA_T here. This might give a problem because the destination position will not be reached precisely
      83         4234 :     MSEdge* edge = myDestinationStop != nullptr ? &myDestinationStop->getLane().getEdge() : const_cast<MSEdge*>(myDestination);
      84         4234 :     net->getBeginOfTimestepEvents()->addEvent(new ProceedCmd(person, edge), myEstimatedArrival);
      85         4234 :     net->getPersonControl().startedAccess();
      86         4234 :     edge->addTransportable(person);
      87         4234 : }
      88              : 
      89              : 
      90              : std::string
      91        19022 : MSPerson::MSPersonStage_Access::getStageDescription(const bool /* isPerson */) const {
      92        19022 :     return "access";
      93              : }
      94              : 
      95              : 
      96              : std::string
      97            0 : MSPerson::MSPersonStage_Access::getStageSummary(const bool /* isPerson */) const {
      98            0 :     if (myDestination == nullptr) {
      99            0 :         return ("jump to edge '") + getDestination()->getID() + "'";
     100              :     } else {
     101            0 :         return (myAmExit ? "access from stop '" : "access to stop '") + getDestinationStop()->getID() + "'";
     102              :     }
     103              : }
     104              : 
     105              : 
     106              : Position
     107        19891 : MSPerson::MSPersonStage_Access::getPosition(SUMOTime now) const {
     108        19891 :     return myPath.positionAtOffset(myPath.length() * (double)(now - myDeparted) / (double)(myEstimatedArrival - myDeparted));
     109              : }
     110              : 
     111              : 
     112              : double
     113        19891 : MSPerson::MSPersonStage_Access::getAngle(SUMOTime /* now */) const {
     114        19891 :     return myPath.angleAt2D(0);
     115              : }
     116              : 
     117              : 
     118              : double
     119        38044 : MSPerson::MSPersonStage_Access::getSpeed() const {
     120        38044 :     return myDist / STEPS2TIME(MAX2((SUMOTime)1, myEstimatedArrival - myDeparted));
     121              : }
     122              : 
     123              : void
     124         2950 : MSPerson::MSPersonStage_Access::tripInfoOutput(OutputDevice& os, const MSTransportable* const) const {
     125         5900 :     os.openTag("access");
     126         2950 :     if (getDestinationStop() != nullptr) {
     127         2942 :         os.writeAttr("stop", getDestinationStop()->getID());
     128              :     }
     129         2950 :     os.writeAttr("depart", time2string(myDeparted));
     130         2950 :     os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
     131         2950 :     os.writeAttr("duration", myArrived > 0 ? time2string(getDuration()) : "-1");
     132         2950 :     os.writeAttr("routeLength", myDist);
     133         2950 :     os.closeTag();
     134         2950 : }
     135              : 
     136              : 
     137              : SUMOTime
     138         4204 : MSPerson::MSPersonStage_Access::ProceedCmd::execute(SUMOTime currentTime) {
     139         4204 :     MSNet::getInstance()->getPersonControl().endedAccess();
     140         4204 :     myStopEdge->removeTransportable(myPerson);
     141         4204 :     if (!myPerson->proceed(MSNet::getInstance(), currentTime)) {
     142           54 :         MSNet::getInstance()->getPersonControl().erase(myPerson);
     143              :     }
     144         4204 :     return 0;
     145              : }
     146              : 
     147              : 
     148              : void
     149            2 : MSPerson::MSPersonStage_Access::saveState(std::ostringstream& out, MSTransportable* /*transportable*/) {
     150            4 :     out << " " << myDeparted << " " << myEstimatedArrival;
     151            2 : }
     152              : 
     153              : 
     154              : void
     155            2 : MSPerson::MSPersonStage_Access::loadState(MSTransportable* person, std::istringstream& state) {
     156            2 :     state >> myDeparted;
     157            2 :     state >> myEstimatedArrival;
     158            2 :     MSNet* net = MSNet::getInstance();
     159            2 :     MSEdge* edge = myDestinationStop != nullptr ? &myDestinationStop->getLane().getEdge() : const_cast<MSEdge*>(myDestination);
     160            2 :     net->getBeginOfTimestepEvents()->addEvent(new ProceedCmd(person, edge), myEstimatedArrival);
     161            2 :     net->getPersonControl().startedAccess();
     162            2 :     edge->addTransportable(person);
     163            2 : }
     164              : 
     165              : /* -------------------------------------------------------------------------
     166              :  * MSPerson - methods
     167              :  * ----------------------------------------------------------------------- */
     168       331420 : MSPerson::MSPerson(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportable::MSTransportablePlan* plan, const double speedFactor) :
     169              :     MSTransportable(pars, vtype, plan, true),
     170       331420 :     myInfluencer(nullptr),
     171       662840 :     myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
     172       331660 :     myTimegapCrossing(getFloatParam("pedestrian.timegap-crossing"))
     173       331420 : { }
     174              : 
     175              : 
     176       633115 : MSPerson::~MSPerson() {
     177       331372 :     delete myInfluencer;
     178       633115 : }
     179              : 
     180              : 
     181              : bool
     182       521681 : MSPerson::checkAccess(const MSStage* const prior, const bool waitAtStop) {
     183              :     MSStoppingPlace* prevStop = prior->getDestinationStop();
     184       521681 :     if (!waitAtStop && prior->getStageType() == MSStageType::TRIP) {
     185       164608 :         prevStop = prior->getOriginStop();
     186              :     }
     187       521681 :     if (prevStop != nullptr) {
     188       119626 :         const MSEdge* const accessEdge = waitAtStop ? prior->getDestination() : (*myStep)->getFromEdge();
     189       119626 :         const MSStoppingPlace::Access* const access = prevStop->getAccess(accessEdge);
     190       119626 :         if (access != nullptr) {
     191         4222 :             const MSLane* const lane = accessEdge->getLanes()[0];
     192         4222 :             MSStage* newStage = nullptr;
     193         4222 :             if (waitAtStop) {
     194         2072 :                 const MSEdge* const stopEdge = &prevStop->getLane().getEdge();
     195         2072 :                 const double arrivalAtBs = (prevStop->getBeginLanePosition() + prevStop->getEndLanePosition()) / 2;
     196         4144 :                 newStage = new MSPersonStage_Access(stopEdge, prevStop, arrivalAtBs, 0.0, access->length, false,
     197         2072 :                                                     lane->geometryPositionAtOffset(access->endPos),
     198         4144 :                                                     prevStop->getLane().geometryPositionAtOffset(arrivalAtBs));
     199              :             } else {
     200         3850 :                 const bool useDoors = access->exit == MSStoppingPlace::AccessExit::DOORS ||
     201         7250 :                                       (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim" && access->exit == MSStoppingPlace::AccessExit::CARRIAGE);
     202         2150 :                 if (access->exit == MSStoppingPlace::AccessExit::CARRIAGE) {
     203            0 :                     const double startPos = prior->getStageType() == MSStageType::TRIP ? prior->getEdgePos(0) : prior->getArrivalPos();
     204            0 :                     const double startPosLat = prior->getStageType() == MSStageType::TRIP ? prior->getEdgePosLat(0) : prior->getArrivalPosLat();
     205              :                     // The start and end attributes of the access stage are equal in this case, but we need to compute the arrival position relatively
     206              :                     // to the current lane and not the lane of the previous stage.
     207            0 :                     const Position start = prevStop->getLane().geometryPositionAtOffset(startPos, startPosLat);
     208            0 :                     const Position end = lane->getShape().transformToVectorCoordinates(start);
     209            0 :                     newStage = new MSPersonStage_Access(accessEdge, prevStop, end.x(), -end.y(), access->length, true, start, start);
     210              :                 } else {
     211         2150 :                     const double startPos = prior->getStageType() == MSStageType::TRIP ? prior->getEdgePos(0) : prior->getArrivalPos();
     212         2150 :                     const Position& trainExit = prevStop->getLane().geometryPositionAtOffset(startPos);
     213         2150 :                     const double arrivalPos = useDoors ? lane->getShape().nearest_offset_to_point2D(trainExit) : access->endPos;
     214              :                     Position platformEntry = lane->geometryPositionAtOffset(arrivalPos);
     215         2150 :                     if (useDoors) {
     216              :                         // find the closer side of the platform to enter
     217          900 :                         const double halfWidth = lane->getWidth() / 2. - MAX2(getVehicleType().getLength(), getVehicleType().getWidth()) / 2. - POSITION_EPS;
     218          450 :                         platformEntry = lane->geometryPositionAtOffset(arrivalPos, halfWidth);
     219          450 :                         const Position& plat2 = lane->geometryPositionAtOffset(arrivalPos, -halfWidth);
     220          450 :                         if (trainExit.distanceSquaredTo2D(plat2) < trainExit.distanceSquaredTo2D(platformEntry)) {
     221          356 :                             platformEntry = plat2;
     222              :                         }
     223              :                     }
     224         2150 :                     newStage = new MSPersonStage_Access(accessEdge, prevStop, arrivalPos, 0.0, access->length, true,
     225         2150 :                                                         trainExit, platformEntry);
     226              :                 }
     227              :             }
     228         4222 :             newStage->setTrip(prior->getTrip());
     229         4222 :             myStep = myPlan->insert(myStep, newStage);
     230              :             return true;
     231              :         }
     232              :     }
     233       517459 :     if (prior->getJumpDuration() > 0) {
     234              :         // negative distance indicates jump
     235              :         MSStage* newStage = new MSPersonStage_Access(getDestination(), nullptr, getArrivalPos(), 0.0, -1, true,
     236           28 :                 prior->getPosition(SIMSTEP), (*myStep)->getPosition(SIMSTEP));
     237           14 :         myStep = myPlan->insert(myStep, newStage);
     238              :         return true;
     239              :     }
     240              :     return false;
     241              : }
     242              : 
     243              : 
     244              : double
     245            8 : MSPerson::getImpatience() const {
     246            8 :     return MAX2(0., MIN2(1., getVehicleType().getImpatience()
     247            8 :                          + STEPS2TIME((*myStep)->getWaitingTime()) / MSPModel_Striping::MAX_WAIT_TOLERANCE));
     248              : }
     249              : 
     250              : 
     251              : bool
     252      1156006 : MSPerson::isJammed() const {
     253      1156006 :     MSStageWalking* stage = dynamic_cast<MSStageWalking*>(getCurrentStage());
     254      1156006 :     if (stage != nullptr) {
     255      1156006 :         return stage->getPState()->isJammed();
     256              :     }
     257              :     return false;
     258              : }
     259              : 
     260              : 
     261              : const std::string&
     262         2633 : MSPerson::getNextEdge() const {
     263              : //    if (getCurrentStageType() == WALKING) {
     264              : //        MSStageWalking* walkingStage =  dynamic_cast<MSStageWalking*>(*myStep);
     265              : //        assert(walkingStage != 0);
     266              : //        const MSEdge* nextEdge = walkingStage->getPedestrianState()->getNextEdge(*walkingStage);
     267              : //        if (nextEdge != 0) {
     268              : //            return nextEdge->getID();
     269              : //        }
     270              : //    }
     271              : //    return StringUtils::emptyString;
     272         2633 :     const MSEdge* nextEdge = getNextEdgePtr();
     273         2633 :     if (nextEdge != nullptr) {
     274         2623 :         return nextEdge->getID();
     275              :     }
     276              :     return StringUtils::emptyString;
     277              : }
     278              : 
     279              : 
     280              : const MSEdge*
     281       166745 : MSPerson::getNextEdgePtr() const {
     282       166745 :     if (getCurrentStageType() == MSStageType::WALKING) {
     283       166745 :         MSStageWalking* walkingStage =  dynamic_cast<MSStageWalking*>(*myStep);
     284              :         assert(walkingStage != nullptr);
     285       166745 :         return walkingStage->getPState()->getNextEdge(*walkingStage);
     286              :     }
     287              :     return nullptr;
     288              : }
     289              : 
     290              : 
     291              : 
     292              : void
     293         1507 : MSPerson::replaceWalk(const ConstMSEdgeVector& newEdges, double departPos, int firstIndex, int nextIndex) {
     294              :     assert(nextIndex > firstIndex);
     295              :     //std::cout << SIMTIME << " reroute person " << getID()
     296              :     //    << "  newEdges=" << toString(newEdges)
     297              :     //    << " firstIndex=" << firstIndex
     298              :     //    << " nextIndex=" << nextIndex
     299              :     //    << " departPos=" << getEdgePos()
     300              :     //    << " arrivalPos=" <<  getNextStage(nextIndex - 1)->getArrivalPos()
     301              :     //    << "\n";
     302         1507 :     MSStage* const toBeReplaced = getNextStage(nextIndex - 1);
     303              :     MSStageWalking* newStage = new MSStageWalking(getID(), newEdges,
     304              :             toBeReplaced->getDestinationStop(), -1,
     305              :             -1,
     306              :             departPos,
     307         1507 :             toBeReplaced->getArrivalPos(),
     308         1507 :             MSPModel::UNSPECIFIED_POS_LAT);
     309         1507 :     appendStage(newStage, nextIndex);
     310              :     // remove stages in reverse order so that proceed will only be called at the last removal
     311         3019 :     for (int i = nextIndex - 1; i >= firstIndex; i--) {
     312              :         //std::cout << " removeStage=" << i << "\n";
     313         1512 :         removeStage(i);
     314              :     }
     315         1507 : }
     316              : 
     317              : 
     318              : MSPerson::Influencer&
     319      5885816 : MSPerson::getInfluencer() {
     320      5885816 :     if (myInfluencer == nullptr) {
     321          226 :         myInfluencer = new Influencer();
     322              :     }
     323      5885816 :     return *myInfluencer;
     324              : }
     325              : 
     326              : 
     327              : const MSPerson::Influencer*
     328            0 : MSPerson::getInfluencer() const {
     329            0 :     return myInfluencer;
     330              : }
     331              : 
     332              : 
     333              : 
     334              : /* -------------------------------------------------------------------------
     335              :  * methods of MSPerson::Influencer
     336              :  * ----------------------------------------------------------------------- */
     337          226 : MSPerson::Influencer::Influencer() {}
     338              : 
     339              : 
     340          226 : MSPerson::Influencer::~Influencer() {}
     341              : 
     342              : 
     343              : void
     344      1957728 : MSPerson::Influencer::setRemoteControlled(Position xyPos, MSLane* l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector& route, SUMOTime t) {
     345      1957728 :     myRemoteXYPos = xyPos;
     346      1957728 :     myRemoteLane = l;
     347      1957728 :     myRemotePos = pos;
     348      1957728 :     myRemotePosLat = posLat;
     349      1957728 :     myRemoteAngle = angle;
     350      1957728 :     myRemoteEdgeOffset = edgeOffset;
     351      1957728 :     myRemoteRoute = route;
     352      1957728 :     myLastRemoteAccess = t;
     353      1957728 : }
     354              : 
     355              : 
     356              : bool
     357      1970361 : MSPerson::Influencer::isRemoteControlled() const {
     358      1970361 :     return myLastRemoteAccess == MSNet::getInstance()->getCurrentTimeStep();
     359              : }
     360              : 
     361              : 
     362              : bool
     363            0 : MSPerson::Influencer::isRemoteAffected(SUMOTime t) const {
     364            0 :     return myLastRemoteAccess >= t - TIME2STEPS(10);
     365              : }
     366              : 
     367              : 
     368              : void
     369      1957727 : MSPerson::Influencer::postProcessRemoteControl(MSPerson* p) {
     370              :     /*
     371              :     std::cout << SIMTIME << " moveToXY person=" << p->getID()
     372              :         << " xyPos=" << myRemoteXYPos
     373              :         << " lane=" << Named::getIDSecure(myRemoteLane)
     374              :         << " pos=" << myRemotePos
     375              :         << " posLat=" << myRemotePosLat
     376              :         << " angle=" << myRemoteAngle
     377              :         << " eOf=" << myRemoteEdgeOffset
     378              :         << " route=" << toString(myRemoteRoute)
     379              :         << " aTime=" << time2string(myLastRemoteAccess)
     380              :         << "\n";
     381              :         */
     382      1957727 :     switch (p->getStageType(0)) {
     383              :         case MSStageType::WALKING: {
     384      1957687 :             MSStageWalking* s = dynamic_cast<MSStageWalking*>(p->getCurrentStage());
     385              :             assert(s != nullptr);
     386      1957687 :             s->getPState()->moveToXY(p, myRemoteXYPos, myRemoteLane, myRemotePos, myRemotePosLat,
     387      1957687 :                                      myRemoteAngle, myRemoteEdgeOffset, myRemoteRoute,
     388              :                                      MSNet::getInstance()->getCurrentTimeStep());
     389              :         }
     390      1957687 :         break;
     391              :         default:
     392              :             break;
     393              :     }
     394      1957727 : }
     395              : 
     396              : 
     397              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1