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 223286 : 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 223286 : const double departPosLat, const bool hasArrivalPos, const double arrivalPos):
57 : MSStage(MSStageType::TRIP, destination, toStop, arrivalPos, 0.0, group),
58 223286 : myOrigin(origin),
59 223286 : myOriginStop(fromStop),
60 223286 : myDuration(duration),
61 223286 : myModeSet(modeSet),
62 223286 : myVTypes(vTypes),
63 223286 : mySpeed(speed),
64 223286 : myWalkFactor(walkFactor),
65 223286 : myDepartPosLat(departPosLat),
66 223286 : myHaveArrivalPos(hasArrivalPos) {
67 223286 : }
68 :
69 :
70 446560 : MSStageTrip::~MSStageTrip() {}
71 :
72 : MSStage*
73 215233 : MSStageTrip::clone() const {
74 215233 : MSStage* const clon = new MSStageTrip(myOrigin, const_cast<MSStoppingPlace*>(myOriginStop),
75 215233 : myDestination, myDestinationStop, myDuration,
76 215233 : myModeSet, myVTypes, mySpeed, myWalkFactor, myGroup,
77 215233 : myDepartPosLat, myHaveArrivalPos, myArrivalPos);
78 215233 : clon->setParameters(*this);
79 215233 : 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 357626 : MSStageTrip::getEdge() const {
99 357626 : return myOrigin;
100 : }
101 :
102 :
103 : double
104 350323 : MSStageTrip::getEdgePos(SUMOTime /* now */) const {
105 350323 : return myDepartPos;
106 : }
107 :
108 :
109 : std::vector<SUMOVehicle*>
110 176493 : MSStageTrip::getVehicles(MSVehicleControl& vehControl, MSTransportable* transportable, const MSEdge* origin) {
111 : std::vector<SUMOVehicleParameter*> pars;
112 353085 : for (StringTokenizer st(myVTypes); st.hasNext();) {
113 99 : pars.push_back(new SUMOVehicleParameter());
114 198 : pars.back()->vtypeid = st.next();
115 99 : pars.back()->parametersSet |= VEHPARS_VTYPE_SET;
116 99 : pars.back()->departProcedure = DepartDefinition::TRIGGERED;
117 198 : pars.back()->id = transportable->getID() + "_" + toString(pars.size() - 1);
118 176493 : }
119 176493 : if (pars.empty()) {
120 176394 : if ((myModeSet & SVC_PASSENGER) != 0) {
121 1552 : pars.push_back(new SUMOVehicleParameter());
122 3104 : pars.back()->id = transportable->getID() + "_0";
123 1552 : pars.back()->departProcedure = DepartDefinition::TRIGGERED;
124 : }
125 176394 : if ((myModeSet & SVC_TAXI) != 0) {
126 122 : pars.push_back(new SUMOVehicleParameter());
127 122 : pars.back()->vtypeid = DEFAULT_TAXITYPE_ID;
128 244 : pars.back()->id = transportable->getID() + "_taxi";
129 122 : pars.back()->line = "taxi";
130 : }
131 176394 : if ((myModeSet & SVC_BICYCLE) != 0) {
132 37 : pars.push_back(new SUMOVehicleParameter());
133 37 : pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
134 74 : pars.back()->id = transportable->getID() + "_b0";
135 37 : pars.back()->departProcedure = DepartDefinition::TRIGGERED;
136 : }
137 : }
138 352986 : ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>(transportable->getID() + "_0", ConstMSEdgeVector({ origin }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
139 : std::vector<SUMOVehicle*> result;
140 178303 : for (SUMOVehicleParameter* vehPar : pars) {
141 1810 : const bool isTaxi = vehPar->vtypeid == DEFAULT_TAXITYPE_ID && vehPar->line == "taxi";
142 1810 : if (myDepartPos != 0) {
143 58 : vehPar->departPosProcedure = DepartPosDefinition::GIVEN;
144 58 : vehPar->departPos = myDepartPos;
145 58 : vehPar->parametersSet |= VEHPARS_DEPARTPOS_SET;
146 : }
147 1810 : vehPar->parametersSet |= VEHPARS_ARRIVALPOS_SET;
148 1810 : vehPar->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
149 1810 : vehPar->parametersSet |= VEHPARS_ARRIVALSPEED_SET;
150 1810 : vehPar->arrivalSpeedProcedure = ArrivalSpeedDefinition::GIVEN;
151 1810 : vehPar->arrivalSpeed = 0;
152 1810 : MSVehicleType* type = vehControl.getVType(vehPar->vtypeid);
153 1810 : if (type->getVehicleClass() != SVC_IGNORING && (origin->getPermissions() & type->getVehicleClass()) == 0 && !isTaxi) {
154 120 : WRITE_WARNINGF(TL("Ignoring vehicle type '%' when routing person '%' because it is not allowed on the start edge."), type->getID(), transportable->getID());
155 40 : delete vehPar;
156 : } else {
157 3540 : result.push_back(vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes));
158 : }
159 : }
160 176493 : if (result.empty()) {
161 : // walking only but may use access infrastructure
162 174753 : result.push_back(nullptr);
163 : }
164 176493 : return result;
165 176493 : }
166 :
167 :
168 : const std::string
169 176493 : MSStageTrip::reroute(const SUMOTime time, MSTransportableRouter& router, MSTransportable* const transportable,
170 : MSStage* previous, const MSEdge* origin, const MSEdge* destination, std::vector<MSStage*>& stages) {
171 176493 : if (origin->isTazConnector() && origin->getSuccessors().size() == 0) {
172 : // previous stage ended at a taz sink-edge
173 299 : origin = transportable->getNextStage(-1)->getDestination();
174 : }
175 176493 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
176 : double minCost = std::numeric_limits<double>::max();
177 : std::vector<MSTransportableRouter::TripItem> minResult;
178 : SUMOVehicle* minVehicle = nullptr;
179 353016 : for (SUMOVehicle* vehicle : getVehicles(vehControl, transportable, origin)) {
180 : std::vector<MSTransportableRouter::TripItem> result;
181 176523 : double departPos = previous->getArrivalPos();
182 : MSStoppingPlace* const prevStop = previous->getDestinationStop();
183 176523 : if (MSGlobals::gUseMesoSim && prevStop != nullptr) {
184 188 : departPos = (prevStop->getBeginLanePosition() + prevStop->getEndLanePosition()) / 2.;
185 : }
186 372194 : if (router.compute(origin, destination, departPos, prevStop == nullptr ? "" : prevStop->getID(),
187 322659 : myArrivalPos, myDestinationStop == nullptr ? "" : myDestinationStop->getID(),
188 176523 : transportable->getMaxSpeed() * myWalkFactor, vehicle, myModeSet, time, result)) {
189 : double totalCost = 0;
190 377861 : for (const MSTransportableRouter::TripItem& item : result) {
191 201401 : totalCost += item.cost;
192 : }
193 176460 : if (totalCost < minCost) {
194 : minCost = totalCost;
195 : minResult.swap(result);
196 : std::swap(minVehicle, vehicle);
197 : }
198 : }
199 176523 : if (vehicle != nullptr) {
200 37 : vehControl.deleteVehicle(vehicle, true);
201 : }
202 353016 : }
203 176493 : if (minCost != std::numeric_limits<double>::max()) {
204 176430 : const bool isTaxi = minVehicle != nullptr && minVehicle->getParameter().vtypeid == DEFAULT_TAXITYPE_ID && minVehicle->getParameter().line == "taxi";
205 : bool carUsed = false;
206 377801 : for (std::vector<MSTransportableRouter::TripItem>::iterator it = minResult.begin(); it != minResult.end(); ++it) {
207 201371 : if (!it->edges.empty()) {
208 182230 : MSStoppingPlace* bs = MSNet::getInstance()->getStoppingPlace(it->destStop, SUMO_TAG_BUS_STOP);
209 182230 : double localArrivalPos = bs != nullptr ? bs->getAccessPos(it->edges.back()) : it->edges.back()->getLength() / 2.;
210 182230 : const MSEdge* const first = it->edges.front();
211 182230 : const MSEdge* const rideOrigin = origin->isTazConnector() && stages.empty() ? first : nullptr;
212 182230 : if (it + 1 == minResult.end() && myHaveArrivalPos) {
213 5553 : localArrivalPos = myArrivalPos;
214 : }
215 182230 : if (it->line == "") {
216 : // determine walk departPos
217 177724 : double depPos = previous->getArrivalPos();
218 177724 : if (previous->getDestinationStop() != nullptr) {
219 21943 : depPos = previous->getDestinationStop()->getAccessPos(first, first->getLanes()[0]->getRNG());
220 155781 : } else if (origin->isTazConnector()) {
221 : // walk the whole length of the first edge
222 105 : if (std::find(first->getPredecessors().begin(), first->getPredecessors().end(), origin) != first->getPredecessors().end()) {
223 : depPos = 0;
224 : } else {
225 : depPos = first->getLength();
226 : }
227 155676 : } else if (previous->getDestination() != first) {
228 49 : if ((previous->getDestination()->getToJunction() == first->getToJunction())
229 49 : || (previous->getDestination()->getFromJunction() == first->getToJunction())) {
230 : depPos = first->getLength();
231 : } else {
232 : depPos = 0.;
233 : }
234 : }
235 177724 : if (destination->isTazConnector()) {
236 : // walk the whole length of the last edge
237 745 : const MSEdge* last = it->edges.back();
238 745 : if (std::find(last->getSuccessors().begin(), last->getSuccessors().end(), destination) != last->getSuccessors().end()) {
239 : localArrivalPos = last->getLength();
240 : } else {
241 : localArrivalPos = 0;
242 : }
243 : }
244 177724 : previous = new MSStageWalking(transportable->getID(), it->edges, bs, myDuration, mySpeed, depPos, localArrivalPos, myDepartPosLat);
245 177724 : previous->setParameters(*this);
246 177724 : previous->setCosts(it->cost);
247 : previous->setTrip(this);
248 177724 : stages.push_back(previous);
249 4506 : } else if (isTaxi) {
250 105 : const ConstMSEdgeVector& prevEdges = previous->getEdges();
251 105 : if (prevEdges.size() >= 2 && previous->getDestinationStop() == nullptr) {
252 : // determine walking direction and let the previous
253 : // stage end after entering its final edge
254 6 : const MSEdge* last = prevEdges.back();
255 6 : const MSEdge* prev = prevEdges[prevEdges.size() - 2];
256 6 : if (last->getFromJunction() == prev->getToJunction() || prev->getFromJunction() == last->getFromJunction()) {
257 : previous->setArrivalPos(MIN2(last->getLength(), 10.0));
258 : } else {
259 6 : previous->setArrivalPos(MAX2(0.0, last->getLength() - 10));
260 : }
261 : }
262 315 : previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ "taxi" }), myGroup);
263 105 : previous->setParameters(*this);
264 105 : previous->setCosts(it->cost);
265 : previous->setTrip(this);
266 105 : stages.push_back(previous);
267 4506 : } else if (minVehicle != nullptr && it->line == minVehicle->getID()) {
268 1487 : if (bs == nullptr && it + 1 != minResult.end()) {
269 : // we have no defined endpoint and are in the middle of the trip, drive as far as possible
270 49 : localArrivalPos = it->edges.back()->getLength();
271 : }
272 4461 : previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ it->line }));
273 1487 : previous->setParameters(*this);
274 1487 : previous->setCosts(it->cost);
275 : previous->setTrip(this);
276 1487 : stages.push_back(previous);
277 1487 : minVehicle->replaceRouteEdges(it->edges, -1, 0, "person:" + transportable->getID(), true);
278 1487 : minVehicle->setArrivalPos(localArrivalPos);
279 1487 : const_cast<SUMOVehicleParameter&>(minVehicle->getParameter()).arrivalPos = localArrivalPos;
280 1487 : vehControl.addVehicle(minVehicle->getID(), minVehicle);
281 : carUsed = true;
282 : } else {
283 8742 : previous = new MSStageDriving(rideOrigin, it->edges.back(), bs, localArrivalPos, 0.0, std::vector<std::string>({ it->line }), myGroup, it->intended, TIME2STEPS(it->depart));
284 2914 : previous->setParameters(*this);
285 2914 : previous->setCosts(it->cost);
286 : previous->setTrip(this);
287 2914 : stages.push_back(previous);
288 : }
289 : }
290 : }
291 176430 : if (wasSet(VEHPARS_ARRIVALPOS_SET) && !stages.empty()) {
292 : // mark the last stage
293 1175 : stages.back()->markSet(VEHPARS_ARRIVALPOS_SET);
294 : }
295 : setCosts(minCost);
296 176430 : if (minVehicle != nullptr && (isTaxi || !carUsed)) {
297 246 : vehControl.deleteVehicle(minVehicle, true);
298 : }
299 : } else {
300 : // append stage so the GUI won't crash due to inconsistent state
301 63 : previous = new MSStageWalking(transportable->getID(), ConstMSEdgeVector({ origin, destination }), myDestinationStop, myDuration, mySpeed, previous->getArrivalPos(), myArrivalPos, myDepartPosLat);
302 63 : previous->setParameters(*this);
303 63 : stages.push_back(previous);
304 63 : if (MSGlobals::gCheckRoutes) { // if not pedestrians will teleport
305 117 : return "No connection found between " + getOriginDescription() + " and " + getDestinationDescription() + " for person '" + transportable->getID() + "'.";
306 : }
307 : }
308 176454 : if (stages.empty()) {
309 : // append stage so the GUI won't crash due to inconsistent state
310 14 : if (myOriginStop != nullptr && myOriginStop == myDestinationStop) {
311 28 : stages.push_back(new MSStageWaiting(destination, myDestinationStop, 0, -1, previous->getArrivalPos(), "sameStop", false));
312 : } else {
313 0 : stages.push_back(new MSStageWalking(transportable->getID(), ConstMSEdgeVector({ origin, destination }), myDestinationStop, myDuration, mySpeed, previous->getArrivalPos(), myArrivalPos, myDepartPosLat));
314 0 : if (MSGlobals::gCheckRoutes) { // if not pedestrians will teleport
315 0 : return "Empty route between " + getOriginDescription() + " and " + getDestinationDescription() + " for person '" + transportable->getID() + "'.";
316 : }
317 : }
318 : }
319 176454 : return "";
320 176703 : }
321 :
322 :
323 : const std::string
324 176413 : MSStageTrip::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
325 352826 : MSStage::setArrived(net, transportable, now, vehicleArrived);
326 : std::vector<MSStage*> stages;
327 : std::string result;
328 176413 : if (transportable->getCurrentStageIndex() == 0) {
329 0 : myDepartPos = transportable->getParameter().departPos;
330 0 : if (transportable->getParameter().departPosProcedure == DepartPosDefinition::RANDOM) {
331 : // TODO we should probably use the rng of the lane here
332 0 : myDepartPos = RandHelper::rand(myOrigin->getLength());
333 : }
334 0 : MSStageWaiting start(myOrigin, myOriginStop, -1, transportable->getParameter().depart, myDepartPos, "start", true);
335 0 : result = reroute(transportable->getParameter().depart, net->getIntermodalRouter(0), transportable, &start, myOrigin, myDestination, stages);
336 0 : } else {
337 : MSStage* previous = transportable->getNextStage(-1);
338 176413 : myDepartPos = previous->getArrivalPos();
339 352826 : result = reroute(now, net->getIntermodalRouter(0), transportable, previous, myOrigin, myDestination, stages);
340 : }
341 : int idx = 1;
342 358596 : for (MSStage* stage : stages) {
343 182183 : transportable->appendStage(stage, idx++);
344 : }
345 176413 : return result;
346 176413 : }
347 :
348 :
349 : void
350 176413 : MSStageTrip::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* /* previous */) {
351 : // just skip the stage, every interesting happens in setArrived
352 176413 : transportable->proceed(net, now);
353 176374 : }
354 :
355 :
356 : std::string
357 39 : MSStageTrip::getOriginDescription() const {
358 39 : return (myOriginStop != nullptr
359 85 : ? toString(myOriginStop->getElement()) + " '" + myOriginStop->getID()
360 71 : : "edge '" + myOrigin->getID()) + "'";
361 : }
362 :
363 : std::string
364 39 : MSStageTrip::getDestinationDescription() const {
365 39 : return (myDestinationStop != nullptr
366 85 : ? toString(myDestinationStop->getElement()) + " '" + myDestinationStop->getID()
367 71 : : "edge '" + myDestination->getID()) + "'";
368 : }
369 :
370 : std::string
371 0 : MSStageTrip::getStageSummary(const bool) const {
372 0 : return "trip from " + getOriginDescription() + " to " + getDestinationDescription();
373 : }
374 :
375 : void
376 1419 : MSStageTrip::routeOutput(const bool /*isPerson*/, OutputDevice& os, const bool /*withRouteLength*/, const MSStage* const previous) const {
377 1419 : if (myArrived < 0) {
378 10 : const bool walkFactorSet = myWalkFactor != OptionsCont::getOptions().getFloat("persontrip.walkfactor");
379 10 : const bool groupSet = myGroup != OptionsCont::getOptions().getString("persontrip.default.group");
380 : // could still be a persontrip but most likely it was a walk in the input
381 10 : SumoXMLTag tag = myModeSet == 0 && !walkFactorSet && !groupSet ? SUMO_TAG_WALK : SUMO_TAG_PERSONTRIP;
382 10 : os.openTag(tag);
383 10 : if (previous == nullptr || previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
384 4 : os.writeAttr(SUMO_ATTR_FROM, myOrigin->getID());
385 : }
386 10 : if (myDestinationStop == nullptr) {
387 10 : os.writeAttr(SUMO_ATTR_TO, myDestination->getID());
388 10 : if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
389 6 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
390 : }
391 : } else {
392 0 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
393 : }
394 : std::vector<std::string> modes;
395 10 : if ((myModeSet & SVC_PASSENGER) != 0) {
396 4 : modes.push_back("car");
397 : }
398 10 : if ((myModeSet & SVC_BICYCLE) != 0) {
399 0 : modes.push_back("bicycle");
400 : }
401 10 : if ((myModeSet & SVC_TAXI) != 0) {
402 0 : modes.push_back("taxi");
403 : }
404 10 : if ((myModeSet & SVC_BUS) != 0) {
405 0 : modes.push_back("public");
406 : }
407 10 : if (modes.size() > 0) {
408 : os.writeAttr(SUMO_ATTR_MODES, modes);
409 : }
410 10 : if (myVTypes.size() > 0) {
411 0 : os.writeAttr(SUMO_ATTR_VTYPES, myVTypes);
412 : }
413 10 : if (groupSet) {
414 : os.writeAttr(SUMO_ATTR_GROUP, myGroup);
415 : }
416 10 : if (walkFactorSet) {
417 0 : os.writeAttr(SUMO_ATTR_WALKFACTOR, myWalkFactor);
418 : }
419 20 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
420 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
421 : }
422 10 : os.closeTag();
423 10 : }
424 1419 : }
425 :
426 : /****************************************************************************/
|