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

Generated by: LCOV version 2.0-1