LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSStageDriving.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.7 % 376 341
Test Date: 2026-04-16 16:39:47 Functions: 94.6 % 37 35

            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    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        79614 : 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        79614 :                                const std::string& intendedVeh, SUMOTime intendedDepart) :
      57              :     MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
      58        79614 :     myOrigin(origin),
      59        79614 :     myLines(lines.begin(), lines.end()),
      60        79614 :     myVehicle(nullptr),
      61        79614 :     myVehicleID("NULL"),
      62        79614 :     myVehicleVClass(SVC_IGNORING),
      63        79614 :     myVehicleDistance(-1.),
      64        79614 :     myTimeLoss(-1),
      65        79614 :     myWaitingPos(-1),
      66        79614 :     myWaitingSince(-1),
      67        79614 :     myWaitingEdge(nullptr),
      68        79614 :     myStopWaitPos(Position::INVALID),
      69        79614 :     myOriginStop(nullptr),
      70        79614 :     myIntendedVehicleID(intendedVeh),
      71        79614 :     myIntendedDepart(intendedDepart) {
      72        79614 : }
      73              : 
      74              : 
      75              : MSStage*
      76        67746 : MSStageDriving::clone() const {
      77        67746 :     MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
      78       135492 :             std::vector<std::string>(myLines.begin(), myLines.end()),
      79        67746 :             myGroup, myIntendedVehicleID, myIntendedDepart);
      80        67746 :     clon->setParameters(*this);
      81        67746 :     return clon;
      82              : }
      83              : 
      84              : 
      85       238827 : MSStageDriving::~MSStageDriving() {}
      86              : 
      87              : 
      88              : void
      89        74883 : MSStageDriving::init(MSTransportable* transportable) {
      90       149766 :     if (hasParameter("earliestPickupTime")) {
      91          162 :         SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
      92          324 :         if (hasParameter("reservationTime")) {
      93          312 :             reservationTime = string2time(getParameter("reservationTime"));
      94              :         }
      95          324 :         SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
      96          162 :         if (transportable->getNextStage(1) == this) {
      97              :             // if the ride is the first stage use the departPos (there is a unvisible stop before)
      98          144 :             myWaitingPos = transportable->getParameter().departPos;
      99              :         } else {
     100              :             // else use the middle of the edge, as also used as default for walk's arrivalPos
     101           18 :             myWaitingPos = myOrigin->getLength() / 2;
     102              :         }
     103          162 :         myReservationWaitingPos = myWaitingPos;
     104          162 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new BookReservation(transportable, earliestPickupTime, this), reservationTime);
     105              :     }
     106        74883 : }
     107              : 
     108              : 
     109              : const MSEdge*
     110       112935 : MSStageDriving::getEdge() const {
     111       112935 :     if (myVehicle != nullptr) {
     112        95708 :         if (myVehicle->getLane() != nullptr) {
     113        87332 :             return &myVehicle->getLane()->getEdge();
     114              :         }
     115         8376 :         return myVehicle->getEdge();
     116        17227 :     } else if (myArrived >= 0) {
     117        15382 :         return myDestination;
     118              :     } else {
     119         1845 :         return myWaitingEdge;
     120              :     }
     121              : }
     122              : 
     123              : 
     124              : const MSEdge*
     125         4723 : MSStageDriving::getFromEdge() const {
     126         4723 :     return myWaitingEdge;
     127              : }
     128              : 
     129              : 
     130              : double
     131      2446214 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
     132      2446214 :     if (isWaiting4Vehicle()) {
     133      2352024 :         return myWaitingPos;
     134        94190 :     } else if (myArrived >= 0) {
     135         2653 :         return myArrivalPos;
     136              :     } else {
     137              :         // vehicle may already have passed the lane (check whether this is correct)
     138        91537 :         return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
     139              :     }
     140              : }
     141              : 
     142              : int
     143           84 : MSStageDriving::getDirection() const {
     144           84 :     if (isWaiting4Vehicle()) {
     145            0 :         return MSPModel::UNDEFINED_DIRECTION;
     146           84 :     } else if (myArrived >= 0) {
     147            0 :         return MSPModel::UNDEFINED_DIRECTION;
     148              :     } else {
     149           84 :         return MSPModel::FORWARD;
     150              :     }
     151              : }
     152              : 
     153              : const MSLane*
     154           76 : MSStageDriving::getLane() const {
     155           76 :     return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
     156              : }
     157              : 
     158              : 
     159              : Position
     160       405775 : MSStageDriving::getPosition(SUMOTime /* now */) const {
     161       405775 :     if (isWaiting4Vehicle()) {
     162              :         if (myStopWaitPos != Position::INVALID) {
     163       138975 :             return myStopWaitPos;
     164              :         }
     165       214991 :         return getEdgePosition(myWaitingEdge, myWaitingPos,
     166       214991 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     167        51809 :     } else if (myArrived >= 0) {
     168            0 :         return getEdgePosition(myDestination, myArrivalPos,
     169            0 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     170              :     } else {
     171        51809 :         return myVehicle->getPosition();
     172              :     }
     173              : }
     174              : 
     175              : 
     176              : double
     177       405767 : MSStageDriving::getAngle(SUMOTime /* now */) const {
     178       405767 :     if (isWaiting4Vehicle()) {
     179       353966 :         const double offset = myOriginStop == nullptr ? M_PI / 2 : myOriginStop->getAngle();
     180       707916 :         return getEdgeAngle(myWaitingEdge, myWaitingPos) + offset * (MSGlobals::gLefthand ? -1 : 1);
     181        51801 :     } else if (myArrived >= 0) {
     182            0 :         return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
     183              :     } else {
     184        51801 :         MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
     185        51801 :         if (veh != nullptr) {
     186        48180 :             return veh->getAngle();
     187              :         } else {
     188              :             return 0;
     189              :         }
     190              :     }
     191              : }
     192              : 
     193              : 
     194              : double
     195         7680 : MSStageDriving::getDistance() const {
     196         7680 :     if (myVehicle != nullptr) {
     197              :         // distance was previously set to driven distance upon embarking
     198          485 :         return myVehicle->getOdometer() - myVehicleDistance;
     199              :     }
     200         7195 :     return myVehicleDistance;
     201              : }
     202              : 
     203              : 
     204              : std::string
     205        76131 : MSStageDriving::getStageDescription(const bool isPerson) const {
     206       139227 :     return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
     207              : }
     208              : 
     209              : 
     210              : std::string
     211            0 : MSStageDriving::getStageSummary(const bool isPerson) const {
     212            0 :     const std::string dest = (getDestinationStop() == nullptr ?
     213            0 :                               " edge '" + getDestination()->getID() + "'" :
     214            0 :                               " stop '" + getDestinationStop()->getID() + "'" + (
     215            0 :                                   getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
     216            0 :     const std::string intended = myIntendedVehicleID != "" ?
     217            0 :                                  " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
     218            0 :                                  "";
     219            0 :     const std::string modeName = isPerson ? "driving" : "transported";
     220            0 :     return isWaiting4Vehicle() ?
     221            0 :            "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
     222            0 :            modeName + " to " + dest;
     223              : }
     224              : 
     225              : 
     226              : void
     227        79047 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
     228        79047 :     myOriginStop = (previous->getStageType() == MSStageType::TRIP
     229        79047 :                     ? previous->getOriginStop()
     230              :                     : previous->getDestinationStop());
     231        79047 :     myWaitingSince = now;
     232        79047 :     const bool isPerson = transportable->isPerson();
     233        79047 :     if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
     234        79047 :             && transportable->getCurrentStageIndex() == 1) {
     235              :         // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
     236              :         const std::string vehID = *myLines.begin();
     237         1712 :         SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
     238         1712 :         if (startVeh == nullptr && net->hasFlow(vehID)) {
     239          808 :             startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
     240              :         }
     241         1712 :         if (startVeh == nullptr) {
     242            0 :             throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
     243            0 :                                (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
     244              :         }
     245         1712 :         if (transportable->isPerson()) {
     246         1690 :             const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
     247         1690 :             if (startVeh->getPersonNumber() >= pCap) {
     248          312 :                 WRITE_WARNING(TLF("Vehicle '%' exceeds personCapacity % when placing triggered person '%', time=%",
     249              :                                   startVeh->getID(), pCap, transportable->getID(), time2string(SIMSTEP)));
     250              :             }
     251              :         } else {
     252           22 :             const int cCap = startVeh->getVehicleType().getParameter().containerCapacity;
     253           22 :             if (startVeh->getContainerNumber() >= cCap) {
     254           48 :                 WRITE_WARNING(TLF("Vehicle '%' exceeds containerCapacity % when placing triggered container '%', time=%",
     255              :                                   startVeh->getID(), cCap, transportable->getID(), time2string(SIMSTEP)));
     256              :             }
     257              :         }
     258         1712 :         myDeparted = now;
     259         1712 :         setVehicle(startVeh);
     260         1712 :         if (myOriginStop != nullptr) {
     261            0 :             myOriginStop->removeTransportable(transportable);
     262              :         }
     263         1712 :         myWaitingEdge = previous->getEdge();
     264         1712 :         myStopWaitPos = Position::INVALID;
     265         1712 :         myWaitingPos = previous->getEdgePos(now);
     266         1712 :         myVehicle->addTransportable(transportable);
     267              :         return;
     268              :     }
     269        77335 :     if (myOriginStop != nullptr) {
     270              :         // the arrival stop may have an access point
     271        23998 :         myWaitingEdge = &myOriginStop->getLane().getEdge();
     272        23998 :         myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     273        23998 :         myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     274              :     } else {
     275        53337 :         myWaitingEdge = previous->getEdge();
     276        53337 :         myStopWaitPos = Position::INVALID;
     277        53337 :         myWaitingPos = previous->getEdgePos(now);
     278              :     }
     279        51318 :     if (myOrigin != nullptr && myOrigin != myWaitingEdge
     280        77358 :             && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
     281              :         // transfer at junction (rather than access)
     282           15 :         myWaitingEdge = myOrigin;
     283           15 :         myWaitingPos = 0;
     284              :     }
     285        77335 :     SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
     286        77335 :     const bool triggered = availableVehicle != nullptr &&
     287         4540 :                            ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
     288          311 :                             (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
     289         2062 :     if (triggered && !availableVehicle->hasDeparted()) {
     290         2034 :         setVehicle(availableVehicle);
     291         2034 :         if (myOriginStop != nullptr) {
     292            0 :             myOriginStop->removeTransportable(transportable);
     293              :         }
     294         2034 :         myVehicle->addTransportable(transportable);
     295         2034 :         net->getInsertionControl().add(myVehicle);
     296         2034 :         net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
     297              :     } else {
     298        75301 :         registerWaiting(transportable, now);
     299              :     }
     300              : }
     301              : 
     302              : 
     303              : void
     304        75379 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
     305              :     // check if the ride can be conducted and reserve it
     306        75379 :     if (MSDevice_Taxi::isReservation(getLines())) {
     307         3150 :         const MSEdge* to = getDestination();
     308         3150 :         double toPos = getArrivalPos();
     309         3150 :         if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
     310              :             // try to find usable access edge
     311           24 :             for (const auto& access : getDestinationStop()->getAllAccessPos()) {
     312            6 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     313            6 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     314              :                     to = accessEdge;
     315            6 :                     toPos = access.endPos;
     316            6 :                     break;
     317              :                 }
     318              :             }
     319              :         }
     320         3150 :         if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
     321              :             // try to find usable access edge
     322           29 :             for (const auto& access : myOriginStop->getAllAccessPos()) {
     323           11 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     324           11 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     325           11 :                     myWaitingEdge = accessEdge;
     326           11 :                     myStopWaitPos = Position::INVALID;
     327           11 :                     myWaitingPos = access.endPos;
     328           11 :                     break;
     329              :                 }
     330              :             }
     331              :         }
     332              :         // Create reservation only if not already created by previous reservationTime
     333         3150 :         if (myReservationWaitingPos == INVALID_DOUBLE) {
     334         2988 :             MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
     335              :         } else {
     336              :             // update "fromPos" with current (new) value of myWaitingPos
     337          162 :             MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationWaitingPos, to, toPos, myGroup, myWaitingPos);
     338              :         }
     339              :     }
     340              :     // check required for state-loading
     341        75379 :     if (myVehicle == nullptr) {
     342        75364 :         if (transportable->isPerson()) {
     343        21719 :             MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
     344              :         } else {
     345        53645 :             MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
     346              :         }
     347        75364 :         myWaitingEdge->addTransportable(transportable);
     348              :     }
     349        75379 : }
     350              : 
     351              : SUMOTime
     352         7480 : MSStageDriving::getDuration() const {
     353         7480 :     return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
     354              : }
     355              : 
     356              : 
     357              : SUMOTime
     358         7480 : MSStageDriving::getTravelTime() const {
     359         7480 :     return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
     360              : }
     361              : 
     362              : 
     363              : SUMOTime
     364        15036 : MSStageDriving::getWaitingTime() const {
     365        15036 :     const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
     366        15036 :     return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
     367              : }
     368              : 
     369              : 
     370              : SUMOTime
     371        14624 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
     372        14624 :     return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
     373              : }
     374              : 
     375              : void
     376         7480 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
     377         7480 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     378         7480 :     const SUMOTime waitingTime = getWaitingTime();
     379         7480 :     const SUMOTime duration = myArrived - myDeparted;
     380         7480 :     MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
     381         8115 :     os.openTag(transportable->isPerson() ? "ride" : "transport");
     382         7480 :     os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
     383         7480 :     os.writeAttr("vehicle", myVehicleID);
     384         7480 :     os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
     385         7480 :     os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
     386         7480 :     os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
     387         7816 :     os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
     388          336 :                  (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
     389         7480 :     os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
     390         7480 :     os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
     391         7480 :     os.closeTag();
     392         7480 : }
     393              : 
     394              : 
     395              : void
     396         2144 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
     397         2236 :     os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
     398         2144 :     if (getFromEdge() != nullptr) {
     399         2038 :         os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
     400          106 :     } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
     401          106 :         os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
     402              :     }
     403         2144 :     os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
     404         2144 :     std::string comment = "";
     405         2144 :     if (myDestinationStop != nullptr) {
     406          701 :         os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
     407          701 :         if (myDestinationStop->getMyName() != "") {
     408          132 :             comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
     409              :         }
     410         1443 :     } else if (!unspecifiedArrivalPos()) {
     411         1273 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
     412              :     }
     413         2144 :     if (myLines.size() > 1 || *myLines.begin() != LINE_ANY) {
     414              :         // no need to write the default
     415         1833 :         os.writeAttr(SUMO_ATTR_LINES, myLines);
     416              :     }
     417         2144 :     if (myIntendedVehicleID != "") {
     418          275 :         os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
     419              :     }
     420         2144 :     if (myIntendedDepart >= 0) {
     421          275 :         os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
     422              :     }
     423         2144 :     if (withRouteLength) {
     424           12 :         os.writeAttr("routeLength", myVehicleDistance);
     425              :     }
     426         4288 :     if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
     427           54 :         os.writeAttr("vehicle", myVehicleID);
     428           54 :         os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
     429           54 :         os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
     430              :     }
     431         4288 :     if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
     432            0 :         os.writeAttr(SUMO_ATTR_COST, getCosts());
     433              :     }
     434         2144 :     os.closeTag(comment);
     435         2144 : }
     436              : 
     437              : 
     438              : bool
     439      2519104 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
     440              :     assert(myLines.size() > 0);
     441              :     return (myLines.count(vehicle->getID()) > 0
     442      2499855 :             || ((myLines.count(vehicle->getParameter().line) > 0
     443       190210 :                  || myLines.count(LINE_ANY) > 0) &&
     444              :                 // even if the line matches we still have to check for stops (#14526)
     445      2447787 :                 (myDestinationStop == nullptr
     446      2447787 :                  ? vehicle->stopsAtEdge(myDestination)
     447      2257577 :                  : vehicle->stopsAt(myDestinationStop)))
     448      2506962 :             || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
     449              : }
     450              : 
     451              : 
     452              : bool
     453      5237729 : MSStageDriving::isWaiting4Vehicle() const {
     454      5237729 :     return myVehicle == nullptr && myArrived < 0;
     455              : }
     456              : 
     457              : 
     458              : SUMOTime
     459            0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
     460            0 :     return isWaiting4Vehicle() ? now - myWaitingSince : 0;
     461              : }
     462              : 
     463              : 
     464              : double
     465       152068 : MSStageDriving::getSpeed() const {
     466       152068 :     return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
     467              : }
     468              : 
     469              : 
     470              : ConstMSEdgeVector
     471          536 : MSStageDriving::getEdges() const {
     472              :     ConstMSEdgeVector result;
     473          536 :     result.push_back(getFromEdge());
     474          536 :     result.push_back(getDestination());
     475          536 :     return result;
     476            0 : }
     477              : 
     478              : 
     479              : double
     480        47613 : MSStageDriving::getArrivalPos() const {
     481        47613 :     return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
     482              : }
     483              : 
     484              : 
     485              : const std::string
     486        14046 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
     487        14046 :     MSStage::setArrived(net, transportable, now, vehicleArrived);
     488        14046 :     if (myVehicle != nullptr) {
     489              :         // distance was previously set to driven distance upon embarking
     490        13953 :         myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
     491        13953 :         myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
     492        13953 :         if (vehicleArrived) {
     493         4190 :             myArrivalPos = myVehicle->getArrivalPos();
     494              :         } else {
     495         9763 :             myArrivalPos = myVehicle->getPositionOnLane();
     496              :         }
     497              :         const MSStoppingPlace* const stop = getDestinationStop();
     498        13953 :         if (stop != nullptr) {
     499              :             MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
     500         7202 :             for (const auto& access : stop->getAllAccessPos()) {
     501         2612 :                 if (access.exit != exit) {
     502              :                     exit = access.exit;
     503              :                     break;
     504              :                 }
     505              :             }
     506         4983 :             if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
     507          393 :                 MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
     508          393 :                 if (train != nullptr) {
     509          336 :                     MSTrainHelper trainHelper = MSTrainHelper(train);
     510          336 :                     const MSLane* const lane = myVehicle->getLane();
     511          672 :                     if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
     512          336 :                         trainHelper.computeDoorPositions();
     513              :                         const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
     514          336 :                         const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
     515          336 :                         const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
     516          336 :                         const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
     517          336 :                         Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
     518              :                         // Jitter the position before projection because of possible train curvature.
     519              :                         Position direction = randomCarriage->front - randomCarriage->back;
     520          336 :                         direction.norm2D();
     521          336 :                         const double doorWidth = train->getVehicleType().getParameter().carriageDoorWidth;
     522          336 :                         randomDoor.add(direction * RandHelper::rand(-0.5 * doorWidth, 0.5 * doorWidth));
     523              :                         // Project onto the lane.
     524          336 :                         myArrivalPos = lane->getShape().nearest_offset_to_point2D(randomDoor);
     525          336 :                         myArrivalPos = lane->interpolateGeometryPosToLanePos(myArrivalPos);
     526          672 :                         myArrivalPos = MIN2(MAX2(0., myArrivalPos), myVehicle->getEdge()->getLength());
     527              :                     } else {
     528            0 :                         std::vector<Position>& unboardingPositions = static_cast<MSDevice_Transportable*>(train->getDevice(typeid(MSDevice_Transportable)))->getUnboardingPositions();
     529            0 :                         if (unboardingPositions.empty()) {
     530            0 :                             const MSVehicleType* defaultPedestrianType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
     531            0 :                             const double defaultPassengerRadius = MAX2(defaultPedestrianType->getLength(), defaultPedestrianType->getWidth()) / 2.;
     532            0 :                             trainHelper.computeUnboardingPositions(defaultPassengerRadius, unboardingPositions);
     533              :                         }
     534              :                         // Random shuffling of the positions has already been done in the train helper.
     535            0 :                         const Position availableUnboardingPosition = unboardingPositions.back();
     536              :                         unboardingPositions.pop_back();
     537            0 :                         const Position arrivalPos = lane->getShape().transformToVectorCoordinates(availableUnboardingPosition);
     538            0 :                         myArrivalPos = arrivalPos.x();
     539            0 :                         myArrivalPosLat = arrivalPos.y();
     540              :                     }
     541          336 :                 }
     542              :             }
     543              :         }
     544              :     } else {
     545           93 :         myVehicleDistance = -1.;
     546           93 :         myTimeLoss = -1;
     547              :     }
     548        14046 :     myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
     549        14046 :     return "";
     550              : }
     551              : 
     552              : 
     553              : void
     554        14126 : MSStageDriving::setVehicle(SUMOVehicle* v) {
     555        14126 :     myVehicle = v;
     556        14126 :     if (myVehicle != nullptr) {
     557        14116 :         myVehicleID = v->getID();
     558        14116 :         myVehicleLine = v->getParameter().line;
     559        14116 :         myVehicleType = v->getVehicleType().getID();
     560        14116 :         myVehicleVClass = v->getVClass();
     561        14116 :         if (myVehicle->hasDeparted()) {
     562        11171 :             myVehicleDistance = myVehicle->getOdometer();
     563        11171 :             myTimeLoss = myVehicle->getTimeLoss();
     564              :         } else {
     565              :             // it probably got triggered by the person
     566         2945 :             myVehicleDistance = 0.;
     567         2945 :             myTimeLoss = 0;
     568              :         }
     569              :     }
     570        14126 : }
     571              : 
     572              : 
     573              : void
     574          106 : MSStageDriving::abort(MSTransportable* t) {
     575          106 :     myDestinationStop = nullptr;
     576          106 :     if (myVehicle != nullptr) {
     577              :         // jumping out of a moving vehicle!
     578           13 :         myVehicle->removeTransportable(t);
     579           13 :         myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
     580           13 :         myArrivalPos = myVehicle->getPositionOnLane();
     581              :         // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
     582              :     } else {
     583           93 :         MSTransportableControl& tc = (t->isPerson() ?
     584           93 :                                       MSNet::getInstance()->getPersonControl() :
     585            0 :                                       MSNet::getInstance()->getContainerControl());
     586           93 :         tc.abortWaitingForVehicle(t);
     587           93 :         MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
     588           93 :         myDestination = myWaitingEdge;
     589           93 :         myDestinationStop = myOriginStop;
     590           93 :         myArrivalPos = myWaitingPos;
     591              :     }
     592          106 : }
     593              : 
     594              : 
     595              : std::string
     596        64633 : MSStageDriving::getWaitingDescription() const {
     597       193899 :     return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
     598        64633 :                                   + " at " + (myOriginStop == nullptr
     599       129266 :                                           ? ("edge '" + myWaitingEdge->getID() + "'")
     600       139941 :                                           : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
     601       129266 :                                  ) : "";
     602              : }
     603              : 
     604              : 
     605              : bool
     606       101692 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
     607       101692 :     const MSEdge* stopEdge = stop.getEdge();
     608              :     bool canLeave = false;
     609       101692 :     if (t->getDestination() == stopEdge) {
     610              :         // if this is the last stage, we can use the arrivalPos of the person
     611        93624 :         const bool unspecifiedAP = unspecifiedArrivalPos() && (
     612        62729 :                                        t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
     613        93624 :         const double arrivalPos = (unspecifiedArrivalPos()
     614        93624 :                                    ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
     615              :                                            SUMO_ATTR_ARRIVALPOS, t->getID(), true)
     616        27331 :                                    : getArrivalPos());
     617        93624 :         if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
     618              :             canLeave = true;
     619              :         }
     620              :     }
     621       101692 :     if (myDestinationStop != nullptr) {
     622        22369 :         if (!canLeave) {
     623              :             // check with more tolerance due to busStop size and also check
     624              :             // access edges
     625         1794 :             const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
     626         1794 :             if (accessPos >= 0) {
     627          508 :                 double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
     628          508 :                 if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
     629              :                     // accessPos is in the middle of the stop
     630          260 :                     tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
     631              :                 }
     632          508 :                 canLeave = stop.isInRange(accessPos, tolerance);
     633              :             }
     634              :         }
     635              :     }
     636       101692 :     return canLeave;
     637              : }
     638              : 
     639              : 
     640              : void
     641           78 : MSStageDriving::saveState(std::ostringstream& out) {
     642           78 :     const bool hasVehicle = myVehicle != nullptr;
     643          234 :     out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
     644           78 :     if (hasVehicle) {
     645           45 :         out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
     646              :     }
     647           78 : }
     648              : 
     649              : 
     650              : void
     651           78 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
     652              :     bool hasVehicle;
     653              :     SUMOTime loadedTimeLoss;
     654          156 :     state >> myWaitingSince >> loadedTimeLoss >> myArrived >> hasVehicle;
     655           78 :     if (hasVehicle) {
     656              :         std::string vehID;
     657           15 :         state >> myDeparted >> vehID;
     658           15 :         SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
     659           15 :         setVehicle(startVeh);
     660           15 :         myTimeLoss = loadedTimeLoss;
     661           15 :         myVehicle->addTransportable(transportable);
     662           15 :         state >> myVehicleDistance;
     663              :     }
     664              :     // there should always be at least one prior WAITING_FOR_DEPART stage
     665              :     MSStage* previous = transportable->getNextStage(-1);
     666           78 :     myOriginStop = (previous->getStageType() == MSStageType::TRIP
     667           78 :                     ? previous->getOriginStop()
     668              :                     : previous->getDestinationStop());
     669           78 :     if (myOriginStop != nullptr) {
     670            2 :         if (!hasVehicle) {
     671              :             // the arrival stop may have an access point
     672            2 :             myOriginStop->addTransportable(transportable);
     673              :         }
     674            2 :         myWaitingEdge = &myOriginStop->getLane().getEdge();
     675            2 :         myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     676            2 :         myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     677              :     } else {
     678           76 :         myWaitingEdge = previous->getEdge();
     679           76 :         myStopWaitPos = Position::INVALID;
     680           76 :         myWaitingPos = previous->getArrivalPos();
     681              :     }
     682              :     // running reservations will be converted in MSDevice_Taxi::addReservation
     683           78 :     registerWaiting(transportable, myWaitingSince);
     684           78 : }
     685              : 
     686              : // ---------------------------------------------------------------------------
     687              : // MSStageDriving::BookReservation method definitions
     688              : // ---------------------------------------------------------------------------
     689              : SUMOTime
     690          162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
     691          486 :     MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
     692          162 :                                   myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
     693          162 :     return 0; // do not repeat
     694              : }
     695              : 
     696              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1