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

Generated by: LCOV version 2.0-1