LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSStageDriving.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 370 335
Test Date: 2024-12-21 15:45:41 Functions: 94.7 % 38 36

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSStageDriving.cpp
      15              : /// @author  Melanie Weber
      16              : /// @author  Andreas Kendziorra
      17              : /// @author  Michael Behrisch
      18              : /// @date    Thu, 12 Jun 2014
      19              : ///
      20              : // A stage performing the travelling by a transport system (cars, public transport)
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <utils/common/StringTokenizer.h>
      25              : #include <utils/geom/GeomHelper.h>
      26              : #include <utils/vehicle/SUMOVehicleParameter.h>
      27              : #include <utils/router/PedestrianRouter.h>
      28              : #include <utils/router/IntermodalRouter.h>
      29              : #include <microsim/MSEdge.h>
      30              : #include <microsim/MSEventControl.h>
      31              : #include <microsim/MSLane.h>
      32              : #include <microsim/MSNet.h>
      33              : #include <microsim/MSStop.h>
      34              : #include <microsim/MSInsertionControl.h>
      35              : #include <microsim/MSVehicleControl.h>
      36              : #include <microsim/MSStoppingPlace.h>
      37              : #include <microsim/MSTrainHelper.h>
      38              : #include <microsim/MSVehicleType.h>
      39              : #include <microsim/devices/MSTransportableDevice.h>
      40              : #include <microsim/devices/MSDevice_Taxi.h>
      41              : #include <microsim/devices/MSDevice_Transportable.h>
      42              : #include <microsim/devices/MSDevice_Tripinfo.h>
      43              : #include <microsim/devices/MSDispatch.h>
      44              : #include <microsim/transportables/MSTransportableControl.h>
      45              : #include <microsim/transportables/MSStageDriving.h>
      46              : #include <microsim/transportables/MSPModel.h>
      47              : #include <microsim/transportables/MSPerson.h>
      48              : 
      49              : 
      50              : // ===========================================================================
      51              : // method definitions
      52              : // ===========================================================================
      53        79181 : 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        79181 :                                const std::string& intendedVeh, SUMOTime intendedDepart) :
      57              :     MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
      58        79181 :     myOrigin(origin),
      59        79181 :     myLines(lines.begin(), lines.end()),
      60        79181 :     myVehicle(nullptr),
      61        79181 :     myVehicleID("NULL"),
      62        79181 :     myVehicleVClass(SVC_IGNORING),
      63        79181 :     myVehicleDistance(-1.),
      64        79181 :     myTimeLoss(-1),
      65        79181 :     myWaitingPos(-1),
      66        79181 :     myWaitingSince(-1),
      67        79181 :     myWaitingEdge(nullptr),
      68        79181 :     myStopWaitPos(Position::INVALID),
      69        79181 :     myOriginStop(nullptr),
      70        79181 :     myIntendedVehicleID(intendedVeh),
      71        79181 :     myIntendedDepart(intendedDepart),
      72        79181 :     myReservationCommand(nullptr) {
      73        79181 : }
      74              : 
      75              : 
      76              : MSStage*
      77        68962 : MSStageDriving::clone() const {
      78        68962 :     MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
      79       137924 :             std::vector<std::string>(myLines.begin(), myLines.end()),
      80        68962 :             myGroup, myIntendedVehicleID, myIntendedDepart);
      81        68962 :     clon->setParameters(*this);
      82        68962 :     return clon;
      83              : }
      84              : 
      85              : 
      86       237453 : MSStageDriving::~MSStageDriving() {}
      87              : 
      88              : 
      89              : void
      90        74552 : MSStageDriving::init(MSTransportable* transportable) {
      91       149104 :     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        74552 : }
     108              : 
     109              : 
     110              : const MSEdge*
     111       114488 : MSStageDriving::getEdge() const {
     112       114488 :     if (myVehicle != nullptr) {
     113        98297 :         if (myVehicle->getLane() != nullptr) {
     114        85959 :             return &myVehicle->getLane()->getEdge();
     115              :         }
     116        12338 :         return myVehicle->getEdge();
     117        16191 :     } else if (myArrived >= 0) {
     118        14369 :         return myDestination;
     119              :     } else {
     120         1822 :         return myWaitingEdge;
     121              :     }
     122              : }
     123              : 
     124              : 
     125              : const MSEdge*
     126         3073 : MSStageDriving::getFromEdge() const {
     127         3073 :     return myWaitingEdge;
     128              : }
     129              : 
     130              : 
     131              : double
     132       343977 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
     133       343977 :     if (isWaiting4Vehicle()) {
     134       247149 :         return myWaitingPos;
     135        96828 :     } else if (myArrived >= 0) {
     136         2512 :         return myArrivalPos;
     137              :     } else {
     138              :         // vehicle may already have passed the lane (check whether this is correct)
     139        94316 :         return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
     140              :     }
     141              : }
     142              : 
     143              : int
     144           60 : MSStageDriving::getDirection() const {
     145           60 :     if (isWaiting4Vehicle()) {
     146            0 :         return MSPModel::UNDEFINED_DIRECTION;
     147           60 :     } else if (myArrived >= 0) {
     148            0 :         return MSPModel::UNDEFINED_DIRECTION;
     149              :     } else {
     150           60 :         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       409453 : MSStageDriving::getPosition(SUMOTime /* now */) const {
     162       409453 :     if (isWaiting4Vehicle()) {
     163              :         if (myStopWaitPos != Position::INVALID) {
     164       142567 :             return myStopWaitPos;
     165              :         }
     166       214226 :         return getEdgePosition(myWaitingEdge, myWaitingPos,
     167       428452 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     168        52660 :     } else if (myArrived >= 0) {
     169            0 :         return getEdgePosition(myDestination, myArrivalPos,
     170            0 :                                ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
     171              :     } else {
     172        52660 :         return myVehicle->getPosition();
     173              :     }
     174              : }
     175              : 
     176              : 
     177              : double
     178       410618 : MSStageDriving::getAngle(SUMOTime /* now */) const {
     179       410618 :     if (isWaiting4Vehicle()) {
     180       714129 :         return getEdgeAngle(myWaitingEdge, myWaitingPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
     181        53545 :     } else if (myArrived >= 0) {
     182            0 :         return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
     183              :     } else {
     184        53545 :         MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
     185        53545 :         if (veh != nullptr) {
     186        47939 :             return veh->getAngle();
     187              :         } else {
     188              :             return 0;
     189              :         }
     190              :     }
     191              : }
     192              : 
     193              : 
     194              : double
     195         6625 : MSStageDriving::getDistance() const {
     196         6625 :     if (myVehicle != nullptr) {
     197              :         // distance was previously set to driven distance upon embarking
     198          481 :         return myVehicle->getOdometer() - myVehicleDistance;
     199              :     }
     200         6144 :     return myVehicleDistance;
     201              : }
     202              : 
     203              : 
     204              : std::string
     205         1698 : MSStageDriving::getStageDescription(const bool isPerson) const {
     206         2940 :     return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
     207              : }
     208              : 
     209              : 
     210              : std::string
     211            0 : MSStageDriving::getStageSummary(const bool isPerson) const {
     212            0 :     const std::string dest = (getDestinationStop() == nullptr ?
     213            0 :                               " edge '" + getDestination()->getID() + "'" :
     214            0 :                               " stop '" + getDestinationStop()->getID() + "'" + (
     215            0 :                                   getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
     216            0 :     const std::string intended = myIntendedVehicleID != "" ?
     217            0 :                                  " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
     218            0 :                                  "";
     219            0 :     const std::string modeName = isPerson ? "driving" : "transported";
     220            0 :     return isWaiting4Vehicle() ?
     221            0 :            "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
     222            0 :            modeName + " to " + dest;
     223              : }
     224              : 
     225              : 
     226              : void
     227        78628 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
     228        78628 :     myOriginStop = (previous->getStageType() == MSStageType::TRIP
     229        78628 :                     ? previous->getOriginStop()
     230              :                     : previous->getDestinationStop());
     231        78628 :     myWaitingSince = now;
     232        78628 :     const bool isPerson = transportable->isPerson();
     233        78628 :     if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
     234        78628 :             && transportable->getCurrentStageIndex() == 1) {
     235              :         // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
     236              :         const std::string vehID = *myLines.begin();
     237         1458 :         SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
     238         1458 :         if (startVeh == nullptr && net->hasFlow(vehID)) {
     239          568 :             startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
     240              :         }
     241         1458 :         if (startVeh == nullptr) {
     242            0 :             throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
     243            0 :                                (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
     244              :         }
     245         1458 :         if (transportable->isPerson()) {
     246         1436 :             const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
     247         1436 :             if (startVeh->getPersonNumber() >= pCap) {
     248          312 :                 WRITE_WARNING(TLF("Vehicle '%' exceeds personCapacity % when placing triggered person '%', time=%",
     249              :                                   startVeh->getID(), pCap, transportable->getID(), time2string(SIMSTEP)));
     250              :             }
     251              :         } else {
     252           22 :             const int cCap = startVeh->getVehicleType().getParameter().containerCapacity;
     253           22 :             if (startVeh->getContainerNumber() >= cCap) {
     254           48 :                 WRITE_WARNING(TLF("Vehicle '%' exceeds containerCapacity % when placing triggered container '%', time=%",
     255              :                                   startVeh->getID(), cCap, transportable->getID(), time2string(SIMSTEP)));
     256              :             }
     257              :         }
     258         1458 :         myDeparted = now;
     259         1458 :         setVehicle(startVeh);
     260         1458 :         if (myOriginStop != nullptr) {
     261            0 :             myOriginStop->removeTransportable(transportable);
     262              :         }
     263         1458 :         myWaitingEdge = previous->getEdge();
     264         1458 :         myStopWaitPos = Position::INVALID;
     265         1458 :         myWaitingPos = previous->getEdgePos(now);
     266         1458 :         myVehicle->addTransportable(transportable);
     267              :         return;
     268              :     }
     269        77170 :     if (myOriginStop != nullptr) {
     270              :         // the arrival stop may have an access point
     271        23379 :         myWaitingEdge = &myOriginStop->getLane().getEdge();
     272        23379 :         myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     273        23379 :         myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     274              :     } else {
     275        53791 :         myWaitingEdge = previous->getEdge();
     276        53791 :         myStopWaitPos = Position::INVALID;
     277        53791 :         myWaitingPos = previous->getEdgePos(now);
     278              :     }
     279        51824 :     if (myOrigin != nullptr && myOrigin != myWaitingEdge
     280        77193 :             && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
     281              :         // transfer at junction (rather than access)
     282           15 :         myWaitingEdge = myOrigin;
     283           15 :         myWaitingPos = 0;
     284              :     }
     285        77170 :     SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
     286        77170 :     const bool triggered = availableVehicle != nullptr &&
     287         4470 :                            ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
     288          311 :                             (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
     289         2034 :     if (triggered && !availableVehicle->hasDeparted()) {
     290         2006 :         setVehicle(availableVehicle);
     291         2006 :         if (myOriginStop != nullptr) {
     292            0 :             myOriginStop->removeTransportable(transportable);
     293              :         }
     294         2006 :         myVehicle->addTransportable(transportable);
     295         2006 :         net->getInsertionControl().add(myVehicle);
     296         2006 :         net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
     297              :     } else {
     298        75164 :         registerWaiting(transportable, now);
     299              :     }
     300              : }
     301              : 
     302              : 
     303              : void
     304        75171 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
     305              :     // check if the ride can be conducted and reserve it
     306        75171 :     if (MSDevice_Taxi::isReservation(getLines())) {
     307         2384 :         const MSEdge* to = getDestination();
     308         2384 :         double toPos = getArrivalPos();
     309         2384 :         if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
     310              :             // try to find usable access edge
     311            6 :             for (const auto& access : getDestinationStop()->getAllAccessPos()) {
     312            6 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     313            6 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     314              :                     to = accessEdge;
     315            6 :                     toPos = access.endPos;
     316            6 :                     break;
     317              :                 }
     318              :             }
     319              :         }
     320         2384 :         if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
     321              :             // try to find usable access edge
     322           11 :             for (const auto& access : myOriginStop->getAllAccessPos()) {
     323           11 :                 const MSEdge* accessEdge = &access.lane->getEdge();
     324           11 :                 if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
     325           11 :                     myWaitingEdge = accessEdge;
     326           11 :                     myStopWaitPos = Position::INVALID;
     327           11 :                     myWaitingPos = access.endPos;
     328           11 :                     break;
     329              :                 }
     330              :             }
     331              :         }
     332              :         // Create reservation only if not already created by previous reservationTime
     333         2384 :         if (myReservationCommand == nullptr) {
     334         2222 :             MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
     335              :         } else {
     336              :             // update "fromPos" with current (new) value of myWaitingPos
     337          162 :             MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationCommand->myWaitingPos, to, toPos, myGroup, myWaitingPos);
     338              :         }
     339              :     }
     340        75171 :     if (transportable->isPerson()) {
     341        20880 :         MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
     342              :     } else {
     343        54291 :         MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
     344              :     }
     345        75171 :     myWaitingEdge->addTransportable(transportable);
     346        75171 : }
     347              : 
     348              : SUMOTime
     349         6361 : MSStageDriving::getDuration() const {
     350         6361 :     return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
     351              : }
     352              : 
     353              : 
     354              : SUMOTime
     355         6361 : MSStageDriving::getTravelTime() const {
     356         6361 :     return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
     357              : }
     358              : 
     359              : 
     360              : SUMOTime
     361        12722 : MSStageDriving::getWaitingTime() const {
     362        12722 :     const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
     363        12722 :     return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
     364              : }
     365              : 
     366              : 
     367              : SUMOTime
     368        12455 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
     369        12455 :     return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
     370              : }
     371              : 
     372              : void
     373         6361 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
     374         6361 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     375         6361 :     const SUMOTime waitingTime = getWaitingTime();
     376         6361 :     const SUMOTime duration = myArrived - myDeparted;
     377         6361 :     MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
     378         6996 :     os.openTag(transportable->isPerson() ? "ride" : "transport");
     379        12722 :     os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
     380         6361 :     os.writeAttr("vehicle", myVehicleID);
     381        12722 :     os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
     382        12722 :     os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
     383        12722 :     os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
     384        12989 :     os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
     385          267 :                  (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
     386        12722 :     os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
     387        12722 :     os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
     388         6361 :     os.closeTag();
     389         6361 : }
     390              : 
     391              : 
     392              : void
     393         1273 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
     394         1357 :     os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
     395         1273 :     if (getFromEdge() != nullptr) {
     396         1265 :         os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
     397            8 :     } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
     398            8 :         os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
     399              :     }
     400         1273 :     os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
     401         1273 :     std::string comment = "";
     402         1273 :     if (myDestinationStop != nullptr) {
     403          539 :         os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
     404          539 :         if (myDestinationStop->getMyName() != "") {
     405          132 :             comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
     406              :         }
     407          734 :     } else if (!unspecifiedArrivalPos()) {
     408          703 :         os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
     409              :     }
     410         1273 :     os.writeAttr(SUMO_ATTR_LINES, myLines);
     411         1273 :     if (myIntendedVehicleID != "") {
     412              :         os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
     413              :     }
     414         1273 :     if (myIntendedDepart >= 0) {
     415          482 :         os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
     416              :     }
     417         1273 :     if (withRouteLength) {
     418           24 :         os.writeAttr("routeLength", myVehicleDistance);
     419              :     }
     420         2546 :     if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
     421           54 :         os.writeAttr("vehicle", myVehicleID);
     422           54 :         os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
     423          108 :         os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
     424              :     }
     425         2546 :     if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
     426            0 :         os.writeAttr(SUMO_ATTR_COST, getCosts());
     427              :     }
     428         1273 :     os.closeTag(comment);
     429         1273 : }
     430              : 
     431              : 
     432              : bool
     433       369250 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
     434              :     assert(myLines.size() > 0);
     435              :     return (myLines.count(vehicle->getID()) > 0
     436       350676 :             || ((myLines.count(vehicle->getParameter().line) > 0
     437       562445 :                  || myLines.count("ANY") > 0) &&
     438              :                 // even if the line matches we still have to check for stops (#14526)
     439       297579 :                 (myDestinationStop == nullptr
     440       297579 :                  ? vehicle->stopsAtEdge(myDestination)
     441       112744 :                  : vehicle->stopsAt(myDestinationStop)))
     442       795056 :             || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
     443              : }
     444              : 
     445              : 
     446              : bool
     447      2997219 : MSStageDriving::isWaiting4Vehicle() const {
     448      2997219 :     return myVehicle == nullptr && myArrived < 0;
     449              : }
     450              : 
     451              : 
     452              : SUMOTime
     453            0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
     454            0 :     return isWaiting4Vehicle() ? now - myWaitingSince : 0;
     455              : }
     456              : 
     457              : 
     458              : double
     459        80726 : MSStageDriving::getSpeed() const {
     460        80726 :     return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
     461              : }
     462              : 
     463              : 
     464              : ConstMSEdgeVector
     465          535 : MSStageDriving::getEdges() const {
     466              :     ConstMSEdgeVector result;
     467          535 :     result.push_back(getFromEdge());
     468          535 :     result.push_back(getDestination());
     469          535 :     return result;
     470            0 : }
     471              : 
     472              : 
     473              : double
     474        36992 : MSStageDriving::getArrivalPos() const {
     475        36992 :     return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
     476              : }
     477              : 
     478              : 
     479              : bool
     480       176582 : MSStageDriving::unspecifiedArrivalPos() const {
     481       176582 :     return myArrivalPos == std::numeric_limits<double>::infinity();
     482              : }
     483              : 
     484              : 
     485              : const std::string
     486        12858 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
     487        12858 :     MSStage::setArrived(net, transportable, now, vehicleArrived);
     488        12858 :     if (myVehicle != nullptr) {
     489              :         // distance was previously set to driven distance upon embarking
     490        12780 :         myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
     491        12780 :         myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
     492        12780 :         if (vehicleArrived) {
     493         3929 :             myArrivalPos = myVehicle->getArrivalPos();
     494              :         } else {
     495         8851 :             myArrivalPos = myVehicle->getPositionOnLane();
     496              :         }
     497              :         const MSStoppingPlace* const stop = getDestinationStop();
     498        12780 :         if (stop != nullptr) {
     499              :             MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
     500         6883 :             for (const auto& access : stop->getAllAccessPos()) {
     501         2570 :                 if (access.exit != exit) {
     502              :                     exit = access.exit;
     503              :                     break;
     504              :                 }
     505              :             }
     506         4763 :             if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
     507          450 :                 MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
     508          450 :                 if (train != nullptr) {
     509          336 :                     MSTrainHelper trainHelper = MSTrainHelper(train);
     510          336 :                     const MSLane* const lane = myVehicle->getLane();
     511          672 :                     if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
     512          336 :                         trainHelper.computeDoorPositions();
     513              :                         const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
     514          336 :                         const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
     515          336 :                         const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
     516          336 :                         const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
     517          336 :                         Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
     518              :                         // Jitter the position before projection because of possible train curvature.
     519              :                         Position direction = randomCarriage->front - randomCarriage->back;
     520          336 :                         direction.norm2D();
     521          336 :                         randomDoor.add(direction * RandHelper::rand(-0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH, 0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH));
     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           78 :         myVehicleDistance = -1.;
     545           78 :         myTimeLoss = -1;
     546              :     }
     547        12858 :     myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
     548        12858 :     return "";
     549              : }
     550              : 
     551              : 
     552              : void
     553        12925 : MSStageDriving::setVehicle(SUMOVehicle* v) {
     554        12925 :     myVehicle = v;
     555        12925 :     if (myVehicle != nullptr) {
     556        12915 :         myVehicleID = v->getID();
     557        12915 :         myVehicleLine = v->getParameter().line;
     558        12915 :         myVehicleType = v->getVehicleType().getID();
     559        12915 :         myVehicleVClass = v->getVClass();
     560        12915 :         if (myVehicle->hasDeparted()) {
     561        10012 :             myVehicleDistance = myVehicle->getOdometer();
     562        10012 :             myTimeLoss = myVehicle->getTimeLoss();
     563              :         } else {
     564              :             // it probably got triggered by the person
     565         2903 :             myVehicleDistance = 0.;
     566         2903 :             myTimeLoss = 0;
     567              :         }
     568              :     }
     569        12925 : }
     570              : 
     571              : 
     572              : void
     573           91 : MSStageDriving::abort(MSTransportable* t) {
     574           91 :     myDestinationStop = nullptr;
     575           91 :     if (myVehicle != nullptr) {
     576              :         // jumping out of a moving vehicle!
     577           13 :         myVehicle->removeTransportable(t);
     578           23 :         myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
     579              :         // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
     580              :     } else {
     581           78 :         MSTransportableControl& tc = (t->isPerson() ?
     582           78 :                                       MSNet::getInstance()->getPersonControl() :
     583            0 :                                       MSNet::getInstance()->getContainerControl());
     584           78 :         tc.abortWaitingForVehicle(t);
     585           78 :         MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
     586           78 :         myDestination = myWaitingEdge;
     587           78 :         myDestinationStop = myOriginStop;
     588              :     }
     589           91 : }
     590              : 
     591              : 
     592              : std::string
     593          605 : MSStageDriving::getWaitingDescription() const {
     594         1815 :     return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
     595          605 :                                   + " at " + (myOriginStop == nullptr
     596         1210 :                                           ? ("edge '" + myWaitingEdge->getID() + "'")
     597         1689 :                                           : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
     598         1210 :                                  ) : "";
     599              : }
     600              : 
     601              : 
     602              : bool
     603        76558 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
     604        76558 :     const MSEdge* stopEdge = stop.getEdge();
     605              :     bool canLeave = false;
     606        76558 :     if (t->getDestination() == stopEdge) {
     607              :         // if this is the last stage, we can use the arrivalPos of the person
     608        69428 :         const bool unspecifiedAP = unspecifiedArrivalPos() && (
     609        46984 :                                        t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
     610        69428 :         const double arrivalPos = (unspecifiedArrivalPos()
     611        69428 :                                    ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
     612              :                                            SUMO_ATTR_ARRIVALPOS, t->getID(), true)
     613        18915 :                                    : getArrivalPos());
     614        69428 :         if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
     615              :             canLeave = true;
     616              :         }
     617              :     }
     618        76558 :     if (myDestinationStop != nullptr) {
     619        16640 :         if (!canLeave) {
     620              :             // check with more tolerance due to busStop size and also check
     621              :             // access edges
     622         1777 :             const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
     623         1777 :             if (accessPos >= 0) {
     624          523 :                 double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
     625          523 :                 if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
     626              :                     // accessPos is in the middle of the stop
     627          275 :                     tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
     628              :                 }
     629          523 :                 canLeave = stop.isInRange(accessPos, tolerance);
     630              :             }
     631              :         }
     632              :     }
     633        76558 :     return canLeave;
     634              : }
     635              : 
     636              : 
     637              : void
     638           16 : MSStageDriving::saveState(std::ostringstream& out) {
     639           16 :     const bool hasVehicle = myVehicle != nullptr;
     640           48 :     out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
     641           16 :     if (hasVehicle) {
     642           27 :         out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
     643              :     }
     644           16 : }
     645              : 
     646              : 
     647              : void
     648           16 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
     649              :     bool hasVehicle;
     650           16 :     state >> myWaitingSince >> myTimeLoss >> myArrived >> hasVehicle;
     651           16 :     if (hasVehicle) {
     652              :         std::string vehID;
     653            9 :         state >> myDeparted >> vehID;
     654            9 :         SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
     655            9 :         setVehicle(startVeh);
     656            9 :         myVehicle->addTransportable(transportable);
     657            9 :         state >> myVehicleDistance;
     658              :     } else {
     659              :         // there should always be at least one prior WAITING_FOR_DEPART stage
     660              :         MSStage* previous = transportable->getNextStage(-1);
     661            7 :         myOriginStop = (previous->getStageType() == MSStageType::TRIP
     662            7 :                         ? previous->getOriginStop()
     663              :                         : previous->getDestinationStop());
     664            7 :         if (myOriginStop != nullptr) {
     665              :             // the arrival stop may have an access point
     666            2 :             myOriginStop->addTransportable(transportable);
     667            2 :             myWaitingEdge = &myOriginStop->getLane().getEdge();
     668            2 :             myStopWaitPos = myOriginStop->getWaitPosition(transportable);
     669            2 :             myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
     670              :         } else {
     671            5 :             myWaitingEdge = previous->getEdge();
     672            5 :             myStopWaitPos = Position::INVALID;
     673            5 :             myWaitingPos = previous->getArrivalPos();
     674              :         }
     675            7 :         registerWaiting(transportable, SIMSTEP);
     676              :     }
     677           16 : }
     678              : 
     679              : // ---------------------------------------------------------------------------
     680              : // MSStageDriving::BookReservation method definitions
     681              : // ---------------------------------------------------------------------------
     682              : SUMOTime
     683          162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
     684          486 :     MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
     685          162 :                                   myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
     686              :     // do not repeat if execution fails
     687          162 :     return 0;
     688              : }
     689              : 
     690              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1