LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSStageTrip.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 182 203 89.7 %
Date: 2024-05-06 15:32:35 Functions: 11 14 78.6 %

          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    MSStageTrip.cpp
      15             : /// @author  Melanie Weber
      16             : /// @author  Andreas Kendziorra
      17             : /// @author  Michael Behrisch
      18             : /// @author  Jakob Erdmann
      19             : /// @date    Wed, 1 Jun 2022
      20             : ///
      21             : // An intermodal routing request (to be transformed into a sequence of walks and rides)
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <utils/common/StringTokenizer.h>
      26             : #include <utils/geom/GeomHelper.h>
      27             : #include <utils/options/OptionsCont.h>
      28             : #include <utils/vehicle/SUMOVehicleParameter.h>
      29             : #include <utils/router/PedestrianRouter.h>
      30             : #include <utils/router/IntermodalRouter.h>
      31             : #include <microsim/MSEdge.h>
      32             : #include <microsim/MSLane.h>
      33             : #include <microsim/MSNet.h>
      34             : #include <microsim/MSStoppingPlace.h>
      35             : #include <microsim/MSVehicleControl.h>
      36             : #include <microsim/transportables/MSStageDriving.h>
      37             : #include <microsim/transportables/MSStageWaiting.h>
      38             : #include <microsim/transportables/MSStageWalking.h>
      39             : #include <microsim/transportables/MSTransportable.h>
      40             : #include <microsim/transportables/MSPerson.h>
      41             : #include <microsim/transportables/MSStageTrip.h>
      42             : 
      43             : 
      44             : // ===========================================================================
      45             : // method definitions
      46             : // ===========================================================================
      47             : 
      48             : /* -------------------------------------------------------------------------
      49             : * MSStageTrip - methods
      50             : * ----------------------------------------------------------------------- */
      51      251653 : MSStageTrip::MSStageTrip(const MSEdge* origin, MSStoppingPlace* fromStop,
      52             :                          const MSEdge* destination, MSStoppingPlace* toStop,
      53             :                          const SUMOTime duration, const SVCPermissions modeSet,
      54             :                          const std::string& vTypes, const double speed, const double walkFactor,
      55             :                          const std::string& group,
      56      251653 :                          const double departPosLat, const bool hasArrivalPos, const double arrivalPos):
      57             :     MSStage(MSStageType::TRIP, destination, toStop, arrivalPos, 0.0, group),
      58      251653 :     myOrigin(origin),
      59      251653 :     myOriginStop(fromStop),
      60      251653 :     myDuration(duration),
      61      251653 :     myModeSet(modeSet),
      62      251653 :     myVTypes(vTypes),
      63      251653 :     mySpeed(speed),
      64      251653 :     myWalkFactor(walkFactor),
      65      251653 :     myDepartPosLat(departPosLat),
      66      251653 :     myHaveArrivalPos(hasArrivalPos) {
      67      251653 : }
      68             : 
      69             : 
      70      503296 : MSStageTrip::~MSStageTrip() {}
      71             : 
      72             : MSStage*
      73      245955 : MSStageTrip::clone() const {
      74      245955 :     MSStage* const clon = new MSStageTrip(myOrigin, const_cast<MSStoppingPlace*>(myOriginStop),
      75      245955 :                                           myDestination, myDestinationStop, myDuration,
      76      245955 :                                           myModeSet, myVTypes, mySpeed, myWalkFactor, myGroup,
      77      245955 :                                           myDepartPosLat, myHaveArrivalPos, myArrivalPos);
      78      245955 :     clon->setParameters(*this);
      79      245955 :     return clon;
      80             : }
      81             : 
      82             : 
      83             : Position
      84           0 : MSStageTrip::getPosition(SUMOTime /* now */) const {
      85             :     // may be called concurrently while the trip is still being routed
      86           0 :     return getEdgePosition(myOrigin, myDepartPos, ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
      87             : }
      88             : 
      89             : 
      90             : double
      91           0 : MSStageTrip::getAngle(SUMOTime /* now */) const {
      92             :     // may be called concurrently while the trip is still being routed
      93           0 :     return getEdgeAngle(myOrigin, myDepartPos) + M_PI / 2 * (MSGlobals::gLefthand ? -1 : 1);
      94             : }
      95             : 
      96             : 
      97             : const MSEdge*
      98      474872 : MSStageTrip::getEdge() const {
      99      474872 :     return myOrigin;
     100             : }
     101             : 
     102             : 
     103             : double
     104      466181 : MSStageTrip::getEdgePos(SUMOTime /* now */) const {
     105      466181 :     return myDepartPos;
     106             : }
     107             : 
     108             : 
     109             : const std::string
     110      234965 : MSStageTrip::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
     111      234965 :     MSStage::setArrived(net, transportable, now, vehicleArrived);
     112      234965 :     if (myOrigin->isTazConnector() && myOrigin->getSuccessors().size() == 0) {
     113             :         // previous stage ended at a taz sink-edge
     114          21 :         myOrigin = transportable->getNextStage(-1)->getDestination();
     115             :     }
     116             :     MSVehicleControl& vehControl = net->getVehicleControl();
     117             :     std::vector<SUMOVehicleParameter*> pars;
     118      470023 :     for (StringTokenizer st(myVTypes); st.hasNext();) {
     119         186 :         pars.push_back(new SUMOVehicleParameter());
     120         186 :         pars.back()->vtypeid = st.next();
     121          93 :         pars.back()->parametersSet |= VEHPARS_VTYPE_SET;
     122          93 :         pars.back()->departProcedure = DepartDefinition::TRIGGERED;
     123         186 :         pars.back()->id = transportable->getID() + "_" + toString(pars.size() - 1);
     124      234965 :     }
     125      234965 :     if (pars.empty()) {
     126      234872 :         if ((myModeSet & SVC_PASSENGER) != 0) {
     127        3114 :             pars.push_back(new SUMOVehicleParameter());
     128        3114 :             pars.back()->id = transportable->getID() + "_0";
     129        1557 :             pars.back()->departProcedure = DepartDefinition::TRIGGERED;
     130      233315 :         } else if ((myModeSet & SVC_TAXI) != 0) {
     131         240 :             pars.push_back(new SUMOVehicleParameter());
     132         120 :             pars.back()->vtypeid = DEFAULT_TAXITYPE_ID;
     133         240 :             pars.back()->id = transportable->getID() + "_taxi";
     134         120 :             pars.back()->line = "taxi";
     135      233195 :         } else if ((myModeSet & SVC_BICYCLE) != 0) {
     136          14 :             pars.push_back(new SUMOVehicleParameter());
     137           7 :             pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
     138          14 :             pars.back()->id = transportable->getID() + "_b0";
     139           7 :             pars.back()->departProcedure = DepartDefinition::TRIGGERED;
     140             :         } else {
     141             :             // allow shortcut via busStop even when not intending to ride
     142      233188 :             pars.push_back(nullptr);
     143             :         }
     144             :     }
     145             :     MSStage* previous;
     146      234965 :     SUMOTime time = MSNet::getInstance()->getCurrentTimeStep();
     147      234965 :     if (transportable->getCurrentStageIndex() == 0) {
     148           0 :         myDepartPos = transportable->getParameter().departPos;
     149           0 :         if (transportable->getParameter().departPosProcedure == DepartPosDefinition::RANDOM) {
     150             :             // TODO we should probably use the rng of the lane here
     151           0 :             myDepartPos = RandHelper::rand(myOrigin->getLength());
     152             :         }
     153           0 :         previous = new MSStageWaiting(myOrigin, nullptr, -1, transportable->getParameter().depart, myDepartPos, "start", true);
     154           0 :         time = transportable->getParameter().depart;
     155             :     } else {
     156             :         previous = transportable->getNextStage(-1);
     157      234965 :         myDepartPos = previous->getArrivalPos();
     158             :     }
     159             :     // TODO This works currently only for a single vehicle type
     160             :     const int oldNumStages = transportable->getNumStages();
     161      469898 :     for (SUMOVehicleParameter* vehPar : pars) {
     162             :         SUMOVehicle* vehicle = nullptr;
     163             :         bool isTaxi = false;
     164      234965 :         if (vehPar != nullptr) {
     165        1777 :             isTaxi = vehPar->vtypeid == DEFAULT_TAXITYPE_ID && vehPar->line == "taxi";
     166        1777 :             if (myDepartPos != 0) {
     167          56 :                 vehPar->departPosProcedure = DepartPosDefinition::GIVEN;
     168          56 :                 vehPar->departPos = myDepartPos;
     169          56 :                 vehPar->parametersSet |= VEHPARS_DEPARTPOS_SET;
     170             :             }
     171        1777 :             pars.back()->parametersSet |= VEHPARS_ARRIVALPOS_SET;
     172        1777 :             pars.back()->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
     173        1777 :             pars.back()->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
     174        1777 :             pars.back()->arrivalSpeedProcedure = ArrivalSpeedDefinition::GIVEN;
     175        1777 :             pars.back()->arrivalSpeed = 0;
     176             : 
     177        1777 :             MSVehicleType* type = vehControl.getVType(vehPar->vtypeid);
     178        1777 :             if (type->getVehicleClass() != SVC_IGNORING && (myOrigin->getPermissions() & type->getVehicleClass()) == 0 && !isTaxi) {
     179         120 :                 WRITE_WARNINGF(TL("Ignoring vehicle type '%' when routing person '%' because it is not allowed on the start edge."), type->getID(), transportable->getID());
     180          40 :                 delete vehPar;
     181             :             } else {
     182        3474 :                 ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>(vehPar->id, ConstMSEdgeVector({ myOrigin }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
     183        3474 :                 vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
     184             :             }
     185             :         }
     186             :         bool carUsed = false;
     187             :         std::vector<MSTransportableRouter::TripItem> result;
     188             :         int stageIndex = 1;
     189      234965 :         double departPos = previous->getArrivalPos();
     190             :         MSStoppingPlace* const prevStop = previous->getDestinationStop();
     191      234965 :         if (MSGlobals::gUseMesoSim && prevStop != nullptr) {
     192          96 :             departPos = (prevStop->getBeginLanePosition() + prevStop->getEndLanePosition()) / 2.;
     193             :         }
     194      704895 :         if (net->getIntermodalRouter(0).compute(myOrigin, myDestination,
     195      469930 :                                                 departPos, myOriginStop == nullptr ? "" : myOriginStop->getID(),
     196      437156 :                                                 myArrivalPos, myDestinationStop == nullptr ? "" : myDestinationStop->getID(),
     197      234965 :                                                 transportable->getMaxSpeed() * myWalkFactor, vehicle, myModeSet, time, result)) {
     198             :             double totalCost = 0;
     199      477317 :             for (std::vector<MSTransportableRouter::TripItem>::iterator it = result.begin(); it != result.end(); ++it) {
     200      242408 :                 totalCost += it->cost;
     201      242408 :                 if (!it->edges.empty()) {
     202      241935 :                     MSStoppingPlace* bs = MSNet::getInstance()->getStoppingPlace(it->destStop, SUMO_TAG_BUS_STOP);
     203      241935 :                     double localArrivalPos = bs != nullptr ? bs->getAccessPos(it->edges.back()) : it->edges.back()->getLength() / 2.;
     204      241935 :                     const MSEdge* const first = it->edges.front();
     205      241935 :                     const MSEdge* const rideOrigin = myOrigin->isTazConnector() && (transportable->getNumStages() == oldNumStages) ? first : nullptr;
     206      241935 :                     if (it + 1 == result.end() && myHaveArrivalPos) {
     207        6050 :                         localArrivalPos = myArrivalPos;
     208             :                     }
     209      241935 :                     if (it->line == "") {
     210             :                         // determine walk departPos
     211      236835 :                         double depPos = previous->getArrivalPos();
     212      236835 :                         if (previous->getDestinationStop() != nullptr) {
     213        3945 :                             depPos = previous->getDestinationStop()->getAccessPos(first, first->getLanes()[0]->getRNG());
     214      232890 :                         } else if (myOrigin->isTazConnector()) {
     215             :                             // walk the whole length of the first edge
     216        1891 :                             if (std::find(first->getPredecessors().begin(), first->getPredecessors().end(), myOrigin) != first->getPredecessors().end()) {
     217             :                                 depPos = 0;
     218             :                             } else {
     219             :                                 depPos = first->getLength();
     220             :                             }
     221      230999 :                         } else if (previous->getDestination() != first) {
     222          49 :                             if ((previous->getDestination()->getToJunction() == first->getToJunction())
     223          49 :                                     || (previous->getDestination()->getFromJunction() == first->getToJunction())) {
     224             :                                 depPos = first->getLength();
     225             :                             } else {
     226             :                                 depPos = 0.;
     227             :                             }
     228             :                         }
     229      236835 :                         if (myDestination->isTazConnector()) {
     230             :                             // walk the whole length of the last edge
     231         116 :                             const MSEdge* last = it->edges.back();
     232         116 :                             if (std::find(last->getSuccessors().begin(), last->getSuccessors().end(), myDestination) != last->getSuccessors().end()) {
     233             :                                 localArrivalPos = last->getLength();
     234             :                             } else {
     235             :                                 localArrivalPos = 0;
     236             :                             }
     237             :                         }
     238      236835 :                         previous = new MSStageWalking(transportable->getID(), it->edges, bs, myDuration, mySpeed, depPos, localArrivalPos, myDepartPosLat);
     239      236835 :                         previous->setParameters(*this);
     240      236835 :                         previous->setCosts(it->cost);
     241      236835 :                         transportable->appendStage(previous, stageIndex++);
     242        5100 :                     } else if (isTaxi) {
     243         102 :                         const ConstMSEdgeVector& prevEdges = previous->getEdges();
     244         102 :                         if (prevEdges.size() >= 2 && previous->getDestinationStop() == nullptr) {
     245             :                             // determine walking direction and let the previous
     246             :                             // stage end after entering its final edge
     247           6 :                             const MSEdge* last = prevEdges.back();
     248           6 :                             const MSEdge* prev = prevEdges[prevEdges.size() - 2];
     249           6 :                             if (last->getFromJunction() == prev->getToJunction() || prev->getFromJunction() == last->getFromJunction()) {
     250             :                                 previous->setArrivalPos(MIN2(last->getLength(), 10.0));
     251             :                             } else {
     252           6 :                                 previous->setArrivalPos(MAX2(0.0, last->getLength() - 10));
     253             :                             }
     254             :                         }
     255         306 :                         previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ "taxi" }), myGroup);
     256         102 :                         previous->setParameters(*this);
     257         102 :                         previous->setCosts(it->cost);
     258         102 :                         transportable->appendStage(previous, stageIndex++);
     259        4998 :                     } else if (vehicle != nullptr && it->line == vehicle->getID()) {
     260        1488 :                         if (bs == nullptr && it + 1 != result.end()) {
     261             :                             // we have no defined endpoint and are in the middle of the trip, drive as far as possible
     262          49 :                             localArrivalPos = it->edges.back()->getLength();
     263             :                         }
     264        5952 :                         previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ it->line }));
     265        1488 :                         previous->setParameters(*this);
     266        1488 :                         previous->setCosts(it->cost);
     267        1488 :                         transportable->appendStage(previous, stageIndex++);
     268        1488 :                         vehicle->replaceRouteEdges(it->edges, -1, 0, "person:" + transportable->getID(), true);
     269        1488 :                         vehicle->setArrivalPos(localArrivalPos);
     270        1488 :                         const_cast<SUMOVehicleParameter&>(vehicle->getParameter()).arrivalPos = localArrivalPos;
     271        1488 :                         vehControl.addVehicle(vehPar->id, vehicle);
     272             :                         carUsed = true;
     273             :                     } else {
     274       10530 :                         previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ it->line }), myGroup, it->intended, TIME2STEPS(it->depart));
     275        3510 :                         previous->setParameters(*this);
     276        3510 :                         previous->setCosts(it->cost);
     277        3510 :                         transportable->appendStage(previous, stageIndex++);
     278             :                     }
     279             :                 }
     280             :             }
     281      234909 :             if (wasSet(VEHPARS_ARRIVALPOS_SET) && stageIndex > 1) {
     282             :                 // mark the last stage
     283        1179 :                 transportable->getNextStage(stageIndex - 1)->markSet(VEHPARS_ARRIVALPOS_SET);
     284             :             }
     285             :             setCosts(totalCost);
     286             :         } else {
     287             :             // append stage so the GUI won't crash due to inconsistent state
     288         112 :             previous = new MSStageWalking(transportable->getID(), ConstMSEdgeVector({ myOrigin, myDestination }), myDestinationStop, myDuration, mySpeed, previous->getArrivalPos(), myArrivalPos, myDepartPosLat);
     289          56 :             previous->setParameters(*this);
     290          56 :             transportable->appendStage(previous, stageIndex++);
     291          56 :             if (MSGlobals::gCheckRoutes) {  // if not pedestrians will teleport
     292          32 :                 if (vehicle != nullptr) {
     293           7 :                     vehControl.deleteVehicle(vehicle, true);
     294             :                 }
     295          64 :                 return "No connection found between " + getOriginDescription() + " and " + getDestinationDescription() + " for person '" + transportable->getID() + "'.";
     296             :             }
     297             :         }
     298      234933 :         if (vehicle != nullptr && (isTaxi || !carUsed)) {
     299         242 :             vehControl.deleteVehicle(vehicle, true);
     300             :         }
     301      234965 :     }
     302      234933 :     if (transportable->getNumStages() == oldNumStages) {
     303             :         // append stage so the GUI won't crash due to inconsistent state
     304          14 :         if (myOriginStop != nullptr && myOriginStop == myDestinationStop) {
     305          28 :             transportable->appendStage(new MSStageWaiting(myDestination, myDestinationStop, 0, -1, previous->getArrivalPos(), "sameStop", false), 1);
     306             :         } else {
     307           0 :             transportable->appendStage(new MSStageWalking(transportable->getID(), ConstMSEdgeVector({ myOrigin, myDestination }), myDestinationStop, myDuration, mySpeed, previous->getArrivalPos(), myArrivalPos, myDepartPosLat), 1);
     308           0 :             if (MSGlobals::gCheckRoutes) {  // if not pedestrians will teleport
     309           0 :                 return "Empty route between " + getOriginDescription() + " and " + getDestinationDescription() + " for person '" + transportable->getID() + "'.";
     310             :             }
     311             :         }
     312             :     }
     313      234933 :     return "";
     314             : }
     315             : 
     316             : 
     317             : void
     318      234965 : MSStageTrip::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* /* previous */) {
     319             :     // just skip the stage, every interesting happens in setArrived
     320      234965 :     transportable->proceed(net, now);
     321      234933 : }
     322             : 
     323             : 
     324             : std::string
     325          32 : MSStageTrip::getOriginDescription() const {
     326          32 :     return (myOriginStop != nullptr
     327          71 :             ? toString(myOriginStop->getElement()) + " '" + myOriginStop->getID()
     328          64 :             : "edge '" + myOrigin->getID()) + "'";
     329             : }
     330             : 
     331             : std::string
     332          32 : MSStageTrip::getDestinationDescription() const {
     333          32 :     return (myDestinationStop != nullptr
     334          71 :             ? toString(myDestinationStop->getElement()) + " '" + myDestinationStop->getID()
     335          64 :             : "edge '" + myDestination->getID()) + "'";
     336             : }
     337             : 
     338             : std::string
     339           0 : MSStageTrip::getStageSummary(const bool) const {
     340           0 :     return "trip from " + getOriginDescription() + " to " + getDestinationDescription();
     341             : }
     342             : 
     343             : void
     344        1368 : MSStageTrip::routeOutput(const bool /*isPerson*/, OutputDevice& os, const bool /*withRouteLength*/, const MSStage* const previous) const {
     345        1368 :     if (myArrived < 0) {
     346          12 :         const bool walkFactorSet = myWalkFactor != OptionsCont::getOptions().getFloat("persontrip.walkfactor");
     347          12 :         const bool groupSet = myGroup != OptionsCont::getOptions().getString("persontrip.default.group");
     348             :         // could still be a persontrip but most likely it was a walk in the input
     349          12 :         SumoXMLTag tag = myModeSet == 0 && !walkFactorSet && !groupSet ? SUMO_TAG_WALK : SUMO_TAG_PERSONTRIP;
     350          12 :         os.openTag(tag);
     351          12 :         if (previous == nullptr || previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
     352           6 :             os.writeAttr(SUMO_ATTR_FROM, myOrigin->getID());
     353             :         }
     354          12 :         if (myDestinationStop == nullptr) {
     355          12 :             os.writeAttr(SUMO_ATTR_TO, myDestination->getID());
     356          12 :             if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
     357           6 :                 os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
     358             :             }
     359             :         } else {
     360           0 :             os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
     361             :         }
     362             :         std::vector<std::string> modes;
     363          12 :         if ((myModeSet & SVC_PASSENGER) != 0) {
     364           6 :             modes.push_back("car");
     365             :         }
     366          12 :         if ((myModeSet & SVC_BICYCLE) != 0) {
     367           0 :             modes.push_back("bicycle");
     368             :         }
     369          12 :         if ((myModeSet & SVC_TAXI) != 0) {
     370           0 :             modes.push_back("taxi");
     371             :         }
     372          12 :         if ((myModeSet & SVC_BUS) != 0) {
     373           0 :             modes.push_back("public");
     374             :         }
     375          12 :         if (modes.size() > 0) {
     376             :             os.writeAttr(SUMO_ATTR_MODES, modes);
     377             :         }
     378          12 :         if (myVTypes.size() > 0) {
     379           0 :             os.writeAttr(SUMO_ATTR_VTYPES, myVTypes);
     380             :         }
     381          12 :         if (groupSet) {
     382             :             os.writeAttr(SUMO_ATTR_GROUP, myGroup);
     383             :         }
     384          12 :         if (walkFactorSet) {
     385           0 :             os.writeAttr(SUMO_ATTR_WALKFACTOR, myWalkFactor);
     386             :         }
     387          24 :         if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
     388           0 :             os.writeAttr(SUMO_ATTR_COST, getCosts());
     389             :         }
     390          12 :         os.closeTag();
     391          12 :     }
     392        1368 : }
     393             : 
     394             : /****************************************************************************/

Generated by: LCOV version 1.14