LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSStageDriving.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 323 356 90.7 %
Date: 2024-05-07 15:28:01 Functions: 34 36 94.4 %

          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    MSStageDriving.cpp
      15             : /// @author  Melanie Weber
      16             : /// @author  Andreas Kendziorra
      17             : /// @author  Michael Behrisch
      18             : /// @date    Thu, 12 Jun 2014
      19             : ///
      20             : // A stage performing the travelling by a transport system (cars, public transport)
      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 <microsim/MSEdge.h>
      30             : #include <microsim/MSEventControl.h>
      31             : #include <microsim/MSLane.h>
      32             : #include <microsim/MSNet.h>
      33             : #include <microsim/MSStop.h>
      34             : #include <microsim/MSInsertionControl.h>
      35             : #include <microsim/MSVehicleControl.h>
      36             : #include <microsim/MSStoppingPlace.h>
      37             : #include <microsim/MSTrainHelper.h>
      38             : #include <microsim/MSVehicleType.h>
      39             : #include <microsim/devices/MSTransportableDevice.h>
      40             : #include <microsim/devices/MSDevice_Taxi.h>
      41             : #include <microsim/devices/MSDevice_Transportable.h>
      42             : #include <microsim/devices/MSDevice_Tripinfo.h>
      43             : #include <microsim/devices/MSDispatch.h>
      44             : #include <microsim/transportables/MSTransportableControl.h>
      45             : #include <microsim/transportables/MSStageDriving.h>
      46             : #include <microsim/transportables/MSPModel.h>
      47             : #include <microsim/transportables/MSPerson.h>
      48             : 
      49             : 
      50             : // ===========================================================================
      51             : // method definitions
      52             : // ===========================================================================
      53       44214 : MSStageDriving::MSStageDriving(const MSEdge* origin, const MSEdge* destination,
      54             :                                MSStoppingPlace* toStop, const double arrivalPos, const double arrivalPosLat,
      55             :                                const std::vector<std::string>& lines, const std::string& group,
      56       44214 :                                const std::string& intendedVeh, SUMOTime intendedDepart) :
      57             :     MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
      58       44214 :     myOrigin(origin),
      59       44214 :     myLines(lines.begin(), lines.end()),
      60       44214 :     myVehicle(nullptr),
      61       44214 :     myVehicleID("NULL"),
      62       44214 :     myVehicleVClass(SVC_IGNORING),
      63       44214 :     myVehicleDistance(-1.),
      64       44214 :     myTimeLoss(-1),
      65       44214 :     myWaitingPos(-1),
      66       44214 :     myWaitingSince(-1),
      67       44214 :     myWaitingEdge(nullptr),
      68       44214 :     myStopWaitPos(Position::INVALID),
      69       44214 :     myOriginStop(nullptr),
      70       44214 :     myIntendedVehicleID(intendedVeh),
      71       44214 :     myIntendedDepart(intendedDepart),
      72       44214 :     myReservationCommand(nullptr) {
      73       44214 : }
      74             : 
      75             : 
      76             : MSStage*
      77       32779 : MSStageDriving::clone() const {
      78       32779 :     MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
      79       65558 :             std::vector<std::string>(myLines.begin(), myLines.end()),
      80       32779 :             myGroup, myIntendedVehicleID, myIntendedDepart);
      81       32779 :     clon->setParameters(*this);
      82       32779 :     return clon;
      83             : }
      84             : 
      85             : 
      86      132627 : MSStageDriving::~MSStageDriving() {}
      87             : 
      88             : 
      89             : void
      90       39069 : MSStageDriving::init(MSTransportable* transportable) {
      91       78138 :     if (hasParameter("earliestPickupTime")) {
      92          78 :         SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
      93         156 :         if (hasParameter("reservationTime")) {
      94         144 :             reservationTime = string2time(getParameter("reservationTime"));
      95             :         }
      96         234 :         SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
      97          78 :         if (transportable->getNextStage(1) == this) {
      98             :             // if the ride is the first stage use the departPos (there is a unvisible stop before)
      99          60 :             myWaitingPos = transportable->getParameter().departPos;
     100             :         } else {
     101             :             // else use the middle of the edge, as also used as default for walk's arrivalPos
     102          18 :             myWaitingPos = myOrigin->getLength() / 2;
     103             :         }
     104          78 :         myReservationCommand = new BookReservation(transportable, earliestPickupTime, this);
     105          78 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myReservationCommand, reservationTime);
     106             :     }
     107             : 
     108             : 
     109       39069 : }
     110             : 
     111             : 
     112             : const MSEdge*
     113      108388 : MSStageDriving::getEdge() const {
     114      108388 :     if (myVehicle != nullptr) {
     115       92220 :         if (myVehicle->getLane() != nullptr) {
     116       80014 :             return &myVehicle->getLane()->getEdge();
     117             :         }
     118       12206 :         return myVehicle->getEdge();
     119       16168 :     } else if (myArrived >= 0) {
     120       15866 :         return myDestination;
     121             :     } else {
     122         302 :         return myWaitingEdge;
     123             :     }
     124             : }
     125             : 
     126             : 
     127             : const MSEdge*
     128        3092 : MSStageDriving::getFromEdge() const {
     129        3092 :     return myWaitingEdge;
     130             : }
     131             : 
     132             : 
     133             : double
     134      332051 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
     135      332051 :     if (isWaiting4Vehicle()) {
     136      240429 :         return myWaitingPos;
     137       91622 :     } else if (myArrived >= 0) {
     138        3074 :         return myArrivalPos;
     139             :     } else {
     140             :         // vehicle may already have passed the lane (check whether this is correct)
     141       88548 :         return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
     142             :     }
     143             : }
     144             : 
     145             : int
     146          60 : MSStageDriving::getDirection() const {
     147          60 :     if (isWaiting4Vehicle()) {
     148           0 :         return MSPModel::UNDEFINED_DIRECTION;
     149          60 :     } else if (myArrived >= 0) {
     150           0 :         return MSPModel::UNDEFINED_DIRECTION;
     151             :     } else {
     152          60 :         return MSPModel::FORWARD;
     153             :     }
     154             : }
     155             : 
     156             : const MSLane*
     157          76 : MSStageDriving::getLane() const {
     158          76 :     return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
     159             : }
     160             : 
     161             : 
     162             : Position
     163      404634 : MSStageDriving::getPosition(SUMOTime /* now */) const {
     164      404634 :     if (isWaiting4Vehicle()) {
     165             :         if (myStopWaitPos != Position::INVALID) {
     166      140687 :             return myStopWaitPos;
     167             :         }
     168      214207 :         return getEdgePosition(myWaitingEdge, myWaitingPos,
     169      428414 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     170       49740 :     } else if (myArrived >= 0) {
     171           0 :         return getEdgePosition(myDestination, myArrivalPos,
     172           0 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     173             :     } else {
     174       49740 :         return myVehicle->getPosition();
     175             :     }
     176             : }
     177             : 
     178             : 
     179             : double
     180      405799 : MSStageDriving::getAngle(SUMOTime /* now */) const {
     181      405799 :     if (isWaiting4Vehicle()) {
     182      710332 :         return getEdgeAngle(myWaitingEdge, myWaitingPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
     183       50625 :     } else if (myArrived >= 0) {
     184           0 :         return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
     185             :     } else {
     186       50625 :         MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
     187       50625 :         if (veh != nullptr) {
     188       45020 :             return veh->getAngle();
     189             :         } else {
     190             :             return 0;
     191             :         }
     192             :     }
     193             : }
     194             : 
     195             : 
     196             : double
     197        7122 : MSStageDriving::getDistance() const {
     198        7122 :     if (myVehicle != nullptr) {
     199             :         // distance was previously set to driven distance upon embarking
     200         487 :         return myVehicle->getOdometer() - myVehicleDistance;
     201             :     }
     202        6635 :     return myVehicleDistance;
     203             : }
     204             : 
     205             : 
     206             : std::string
     207        1723 : MSStageDriving::getStageDescription(const bool isPerson) const {
     208        2677 :     return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
     209             : }
     210             : 
     211             : 
     212             : std::string
     213           0 : MSStageDriving::getStageSummary(const bool isPerson) const {
     214             :     const std::string dest = (getDestinationStop() == nullptr ?
     215           0 :                               " edge '" + getDestination()->getID() + "'" :
     216           0 :                               " stop '" + getDestinationStop()->getID() + "'" + (
     217           0 :                                   getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
     218           0 :     const std::string intended = myIntendedVehicleID != "" ?
     219           0 :                                  " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
     220           0 :                                  "";
     221           0 :     const std::string modeName = isPerson ? "driving" : "transported";
     222           0 :     return isWaiting4Vehicle() ?
     223           0 :            "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
     224           0 :            modeName + " to " + dest;
     225             : }
     226             : 
     227             : 
     228             : void
     229       43876 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
     230       43876 :     myOriginStop = (previous->getStageType() == MSStageType::TRIP
     231       43876 :                     ? previous->getOriginStop()
     232             :                     : previous->getDestinationStop());
     233       43876 :     myWaitingSince = now;
     234       43876 :     const bool isPerson = transportable->isPerson();
     235       43876 :     if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
     236       43876 :             && transportable->getCurrentStageIndex() == 1) {
     237             :         // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
     238             :         const std::string vehID = *myLines.begin();
     239        1927 :         SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
     240        1927 :         if (startVeh == nullptr && net->hasFlow(vehID)) {
     241         408 :             startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
     242             :         }
     243        1927 :         if (startVeh == nullptr) {
     244           0 :             throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
     245           0 :                                (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
     246             :         }
     247        1927 :         myDeparted = now;
     248        1927 :         setVehicle(startVeh);
     249        1927 :         if (myOriginStop != nullptr) {
     250           0 :             myOriginStop->removeTransportable(transportable);
     251             :         }
     252        1927 :         myWaitingEdge = previous->getEdge();
     253        1927 :         myStopWaitPos = Position::INVALID;
     254        1927 :         myWaitingPos = previous->getEdgePos(now);
     255        1927 :         myVehicle->addTransportable(transportable);
     256             :         return;
     257             :     }
     258       41949 :     if (myOriginStop != nullptr) {
     259             :         // the arrival stop may have an access point
     260        6520 :         myWaitingEdge = &myOriginStop->getLane().getEdge();
     261        6520 :         myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     262        6520 :         myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     263             :     } else {
     264       35429 :         myWaitingEdge = previous->getEdge();
     265       35429 :         myStopWaitPos = Position::INVALID;
     266       35429 :         myWaitingPos = previous->getEdgePos(now);
     267             :     }
     268       33912 :     if (myOrigin != nullptr && myOrigin != myWaitingEdge
     269       41972 :             && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
     270             :         // transfer at junction (rather than access)
     271          15 :         myWaitingEdge = myOrigin;
     272          15 :         myWaitingPos = 0;
     273             :     }
     274       41949 :     SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
     275       41949 :     const bool triggered = availableVehicle != nullptr &&
     276        4511 :                            ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
     277         267 :                             (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
     278        2018 :     if (triggered && !availableVehicle->hasDeparted()) {
     279        1990 :         setVehicle(availableVehicle);
     280        1990 :         if (myOriginStop != nullptr) {
     281           0 :             myOriginStop->removeTransportable(transportable);
     282             :         }
     283        1990 :         myVehicle->addTransportable(transportable);
     284        1990 :         net->getInsertionControl().add(myVehicle);
     285        1990 :         net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
     286             :     } else {
     287       39959 :         registerWaiting(transportable, now);
     288             :     }
     289             : }
     290             : 
     291             : 
     292             : void
     293       39969 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
     294             :     // check if the ride can be conducted and reserve it
     295       39969 :     if (MSDevice_Taxi::isReservation(getLines())) {
     296        2964 :         const MSEdge* to = getDestination();
     297        2964 :         double toPos = getArrivalPos();
     298        2964 :         if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
     299             :             // try to find usable access edge
     300           6 :             for (const auto& access : getDestinationStop()->getAllAccessPos()) {
     301           6 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     302           6 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     303             :                     to = accessEdge;
     304           6 :                     toPos = access.endPos;
     305           6 :                     break;
     306             :                 }
     307             :             }
     308             :         }
     309        2964 :         if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
     310             :             // try to find usable access edge
     311          11 :             for (const auto& access : myOriginStop->getAllAccessPos()) {
     312          11 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     313          11 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     314          11 :                     myWaitingEdge = accessEdge;
     315          11 :                     myStopWaitPos = Position::INVALID;
     316          11 :                     myWaitingPos = access.endPos;
     317          11 :                     break;
     318             :                 }
     319             :             }
     320             :         }
     321             :         // Create reservation only if not already created by previous reservationTime
     322        2964 :         if (myReservationCommand == nullptr) {
     323        2886 :             MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
     324             :         } else {
     325             :             // update "fromPos" with current (new) value of myWaitingPos
     326          78 :             MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationCommand->myWaitingPos, to, toPos, myGroup, myWaitingPos);
     327             :         }
     328             :     }
     329       39969 :     if (transportable->isPerson()) {
     330       14204 :         MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
     331             :     } else {
     332       25765 :         MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
     333             :     }
     334       39969 :     myWaitingEdge->addTransportable(transportable);
     335       39969 : }
     336             : 
     337             : 
     338             : SUMOTime
     339       13612 : MSStageDriving::getWaitingTime() const {
     340       13612 :     const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
     341       13612 :     return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
     342             : }
     343             : 
     344             : 
     345             : SUMOTime
     346       13372 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
     347       13372 :     return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
     348             : }
     349             : 
     350             : void
     351        6806 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
     352        6806 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     353             :     const SUMOTime departed = myDeparted >= 0 ? myDeparted : now;
     354        6806 :     const SUMOTime waitingTime = getWaitingTime();
     355        6806 :     const SUMOTime duration = myArrived - myDeparted;
     356        6806 :     MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
     357        7293 :     os.openTag(transportable->isPerson() ? "ride" : "transport");
     358       13612 :     os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
     359        6806 :     os.writeAttr("vehicle", myVehicleID);
     360       13612 :     os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
     361       13612 :     os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
     362       13612 :     os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
     363       13852 :     os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
     364         240 :                  (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
     365       13612 :     os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
     366       13612 :     os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
     367        6806 :     os.closeTag();
     368        6806 : }
     369             : 
     370             : 
     371             : void
     372        1271 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
     373        1339 :     os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
     374        1271 :     if (getFromEdge() != nullptr) {
     375        1259 :         os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
     376          12 :     } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
     377          12 :         os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
     378             :     }
     379        1271 :     os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
     380        1271 :     std::string comment = "";
     381        1271 :     if (myDestinationStop != nullptr) {
     382         494 :         os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
     383         988 :         if (myDestinationStop->getMyName() != "") {
     384          72 :             comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
     385             :         }
     386         777 :     } else if (!unspecifiedArrivalPos()) {
     387         739 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
     388             :     }
     389        1271 :     os.writeAttr(SUMO_ATTR_LINES, myLines);
     390        1271 :     if (myIntendedVehicleID != "") {
     391             :         os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
     392             :     }
     393        1271 :     if (myIntendedDepart >= 0) {
     394         466 :         os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
     395             :     }
     396        1271 :     if (withRouteLength) {
     397          24 :         os.writeAttr("routeLength", myVehicleDistance);
     398             :     }
     399        2542 :     if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
     400          54 :         os.writeAttr("vehicle", myVehicleID);
     401          54 :         os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
     402         108 :         os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
     403             :     }
     404        2542 :     if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
     405           0 :         os.writeAttr(SUMO_ATTR_COST, getCosts());
     406             :     }
     407        1271 :     os.closeTag(comment);
     408        1271 : }
     409             : 
     410             : 
     411             : bool
     412      314275 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
     413             :     assert(myLines.size() > 0);
     414             :     return (myLines.count(vehicle->getID()) > 0
     415      295898 :             || ((myLines.count(vehicle->getParameter().line) > 0
     416      508516 :                  || myLines.count("ANY") > 0) &&
     417             :                 // even if the line matches we still have to check for stops (#14526)
     418      241691 :                 (myDestinationStop == nullptr
     419      241691 :                  ? vehicle->stopsAtEdge(myDestination)
     420       42839 :                  : vehicle->stopsAt(myDestinationStop)))
     421      611829 :             || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
     422             : }
     423             : 
     424             : 
     425             : bool
     426     3004704 : MSStageDriving::isWaiting4Vehicle() const {
     427     3004704 :     return myVehicle == nullptr && myArrived < 0;
     428             : }
     429             : 
     430             : 
     431             : SUMOTime
     432           0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
     433           0 :     return isWaiting4Vehicle() ? now - myWaitingSince : 0;
     434             : }
     435             : 
     436             : 
     437             : double
     438       76319 : MSStageDriving::getSpeed() const {
     439       76319 :     return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
     440             : }
     441             : 
     442             : 
     443             : ConstMSEdgeVector
     444         562 : MSStageDriving::getEdges() const {
     445             :     ConstMSEdgeVector result;
     446         562 :     result.push_back(getFromEdge());
     447         562 :     result.push_back(getDestination());
     448         562 :     return result;
     449             : }
     450             : 
     451             : 
     452             : double
     453       35169 : MSStageDriving::getArrivalPos() const {
     454       35169 :     return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
     455             : }
     456             : 
     457             : 
     458             : bool
     459      179490 : MSStageDriving::unspecifiedArrivalPos() const {
     460      179490 :     return myArrivalPos == std::numeric_limits<double>::infinity();
     461             : }
     462             : 
     463             : 
     464             : const std::string
     465       14151 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
     466       14151 :     MSStage::setArrived(net, transportable, now, vehicleArrived);
     467       14151 :     if (myVehicle != nullptr) {
     468             :         // distance was previously set to driven distance upon embarking
     469       14016 :         myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
     470       14016 :         myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
     471       14016 :         if (vehicleArrived) {
     472        3723 :             myArrivalPos = myVehicle->getArrivalPos();
     473             :         } else {
     474       10293 :             myArrivalPos = myVehicle->getPositionOnLane();
     475             :         }
     476             :         const MSStoppingPlace* const stop = getDestinationStop();
     477       14016 :         if (stop != nullptr) {
     478             :             bool useDoors = false;
     479        7746 :             for (const auto& access : stop->getAllAccessPos()) {
     480        3271 :                 if (access.useDoors) {
     481             :                     useDoors = true;
     482             :                     break;
     483             :                 }
     484             :             }
     485        4925 :             if (useDoors) {
     486         450 :                 MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
     487         450 :                 if (train != nullptr) {
     488         336 :                     MSTrainHelper trainHelper = MSTrainHelper(train);
     489         336 :                     const MSLane* const lane = myVehicle->getLane();
     490        1008 :                     if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
     491         336 :                         trainHelper.computeDoorPositions();
     492             :                         const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
     493         336 :                         const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
     494         336 :                         const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
     495         336 :                         const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
     496         336 :                         Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
     497             :                         // Jitter the position before projection because of possible train curvature.
     498             :                         Position direction = randomCarriage->front - randomCarriage->back;
     499         336 :                         direction.norm2D();
     500         336 :                         randomDoor.add(direction * RandHelper::rand(-0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH, 0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH));
     501             :                         // Project onto the lane.
     502         336 :                         myArrivalPos = lane->getShape().nearest_offset_to_point2D(randomDoor);
     503         336 :                         myArrivalPos = lane->interpolateGeometryPosToLanePos(myArrivalPos);
     504         672 :                         myArrivalPos = MIN2(MAX2(0., myArrivalPos), myVehicle->getEdge()->getLength());
     505             :                     } else {
     506           0 :                         std::vector<Position>& unboardingPositions = static_cast<MSDevice_Transportable*>(train->getDevice(typeid(MSDevice_Transportable)))->getUnboardingPositions();
     507           0 :                         if (unboardingPositions.empty()) {
     508           0 :                             const MSVehicleType* defaultPedestrianType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
     509           0 :                             const double defaultPassengerRadius = MAX2(defaultPedestrianType->getLength(), defaultPedestrianType->getWidth()) / 2.;
     510           0 :                             trainHelper.computeUnboardingPositions(defaultPassengerRadius, unboardingPositions);
     511             :                         }
     512             :                         // Random shuffling of the positions has already been done in the train helper.
     513           0 :                         const Position availableUnboardingPosition = unboardingPositions.back();
     514             :                         unboardingPositions.pop_back();
     515           0 :                         const Position arrivalPos = lane->getShape().transformToVectorCoordinates(availableUnboardingPosition);
     516           0 :                         myArrivalPos = arrivalPos.x();
     517           0 :                         myArrivalPosLat = arrivalPos.y();
     518             :                     }
     519         336 :                 }
     520             :             }
     521             :         }
     522             :     } else {
     523         135 :         myVehicleDistance = -1.;
     524         135 :         myTimeLoss = -1;
     525             :     }
     526       14151 :     myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
     527       14151 :     return "";
     528             : }
     529             : 
     530             : 
     531             : void
     532       14171 : MSStageDriving::setVehicle(SUMOVehicle* v) {
     533       14171 :     myVehicle = v;
     534       14171 :     if (myVehicle != nullptr) {
     535       14161 :         myVehicleID = v->getID();
     536       14161 :         myVehicleLine = v->getParameter().line;
     537       14161 :         myVehicleType = v->getVehicleType().getID();
     538       14161 :         myVehicleVClass = v->getVClass();
     539       14161 :         if (myVehicle->hasDeparted()) {
     540       10644 :             myVehicleDistance = myVehicle->getOdometer();
     541       10644 :             myTimeLoss = myVehicle->getTimeLoss();
     542             :         } else {
     543             :             // it probably got triggered by the person
     544        3517 :             myVehicleDistance = 0.;
     545        3517 :             myTimeLoss = 0;
     546             :         }
     547             :     }
     548       14171 : }
     549             : 
     550             : void
     551         152 : MSStageDriving::abort(MSTransportable* t) {
     552         152 :     myDestinationStop = nullptr;
     553         152 :     if (myVehicle != nullptr) {
     554             :         // jumping out of a moving vehicle!
     555          17 :         myVehicle->removeTransportable(t);
     556          31 :         myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
     557             :         // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
     558             :     } else {
     559         135 :         MSTransportableControl& tc = (t->isPerson() ?
     560         135 :                                       MSNet::getInstance()->getPersonControl() :
     561           0 :                                       MSNet::getInstance()->getContainerControl());
     562         135 :         tc.abortWaitingForVehicle(t);
     563         135 :         MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
     564         135 :         myDestination = myWaitingEdge;
     565             :     }
     566         152 : }
     567             : 
     568             : 
     569             : std::string
     570       29333 : MSStageDriving::getWaitingDescription() const {
     571       87999 :     return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
     572       58666 :                                   + " at " + (myDestinationStop == nullptr
     573       62371 :                                           ? ("edge '" + myWaitingEdge->getID() + "'")
     574       36743 :                                           : ("busStop '" + myDestinationStop->getID() + "'"))
     575       87999 :                                  ) : "";
     576             : }
     577             : 
     578             : 
     579             : bool
     580       83816 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
     581       83816 :     const MSEdge* stopEdge = stop.getEdge();
     582             :     bool canLeave = false;
     583       83816 :     if (t->getDestination() == stopEdge) {
     584             :         // if this is the last stage, we can use the arrivalPos of the person
     585       71772 :         const bool unspecifiedAP = unspecifiedArrivalPos() && (
     586       53787 :                                        t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
     587       71772 :         const double arrivalPos = (unspecifiedArrivalPos()
     588       71772 :                                    ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
     589             :                                            SUMO_ATTR_ARRIVALPOS, t->getID(), true)
     590       13812 :                                    : getArrivalPos());
     591       71772 :         if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
     592             :             canLeave = true;
     593             :         }
     594             :     }
     595       83816 :     if (myDestinationStop != nullptr) {
     596       12352 :         if (!canLeave) {
     597             :             // check with more tolerance due to busStop size and also check
     598             :             // access edges
     599        2018 :             const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
     600        2018 :             if (accessPos >= 0) {
     601         418 :                 double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
     602         418 :                 if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
     603             :                     // accessPos is in the middle of the stop
     604         170 :                     tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
     605             :                 }
     606         418 :                 canLeave = stop.isInRange(accessPos, tolerance);
     607             :             }
     608             :         }
     609             :     }
     610       83816 :     return canLeave;
     611             : }
     612             : 
     613             : 
     614             : void
     615          24 : MSStageDriving::saveState(std::ostringstream& out) {
     616          24 :     const bool hasVehicle = myVehicle != nullptr;
     617          96 :     out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
     618          24 :     if (hasVehicle) {
     619          42 :         out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
     620             :     }
     621          24 : }
     622             : 
     623             : 
     624             : void
     625          24 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
     626             :     bool hasVehicle;
     627          24 :     state >> myWaitingSince >> myTimeLoss >> myArrived >> hasVehicle;
     628          24 :     if (hasVehicle) {
     629             :         std::string vehID;
     630          14 :         state >> myDeparted >> vehID;
     631          14 :         SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
     632          14 :         setVehicle(startVeh);
     633          14 :         myVehicle->addTransportable(transportable);
     634          14 :         state >> myVehicleDistance;
     635             :     } else {
     636             :         // there should always be at least one prior WAITING_FOR_DEPART stage
     637             :         MSStage* previous = transportable->getNextStage(-1);
     638          10 :         myOriginStop = (previous->getStageType() == MSStageType::TRIP
     639          10 :                         ? previous->getOriginStop()
     640             :                         : previous->getDestinationStop());
     641          10 :         if (myOriginStop != nullptr) {
     642             :             // the arrival stop may have an access point
     643           3 :             myOriginStop->addTransportable(transportable);
     644           3 :             myWaitingEdge = &myOriginStop->getLane().getEdge();
     645           3 :             myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     646           3 :             myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     647             :         } else {
     648           7 :             myWaitingEdge = previous->getEdge();
     649           7 :             myStopWaitPos = Position::INVALID;
     650           7 :             myWaitingPos = previous->getArrivalPos();
     651             :         }
     652          10 :         registerWaiting(transportable, SIMSTEP);
     653             :     }
     654          24 : }
     655             : 
     656             : // ---------------------------------------------------------------------------
     657             : // MSStageDriving::BookReservation method definitions
     658             : // ---------------------------------------------------------------------------
     659             : SUMOTime
     660          78 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
     661         234 :     MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
     662          78 :                                   myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
     663             :     // do not repeat if execution fails
     664          78 :     return 0;
     665             : }
     666             : 
     667             : /****************************************************************************/

Generated by: LCOV version 1.14