Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSStageDriving.cpp
15 : /// @author Melanie Weber
16 : /// @author Andreas Kendziorra
17 : /// @author Michael Behrisch
18 : /// @date Thu, 12 Jun 2014
19 : ///
20 : // A stage performing the travelling by a transport system (cars, public transport)
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <utils/common/StringTokenizer.h>
25 : #include <utils/geom/GeomHelper.h>
26 : #include <utils/vehicle/SUMOVehicleParameter.h>
27 : #include <utils/router/PedestrianRouter.h>
28 : #include <utils/router/IntermodalRouter.h>
29 : #include <microsim/MSEdge.h>
30 : #include <microsim/MSEventControl.h>
31 : #include <microsim/MSLane.h>
32 : #include <microsim/MSNet.h>
33 : #include <microsim/MSStop.h>
34 : #include <microsim/MSInsertionControl.h>
35 : #include <microsim/MSVehicleControl.h>
36 : #include <microsim/MSStoppingPlace.h>
37 : #include <microsim/MSTrainHelper.h>
38 : #include <microsim/MSVehicleType.h>
39 : #include <microsim/devices/MSTransportableDevice.h>
40 : #include <microsim/devices/MSDevice_Taxi.h>
41 : #include <microsim/devices/MSDevice_Transportable.h>
42 : #include <microsim/devices/MSDevice_Tripinfo.h>
43 : #include <microsim/devices/MSDispatch.h>
44 : #include <microsim/transportables/MSTransportableControl.h>
45 : #include <microsim/transportables/MSStageDriving.h>
46 : #include <microsim/transportables/MSPModel.h>
47 : #include <microsim/transportables/MSPerson.h>
48 :
49 :
50 : // ===========================================================================
51 : // method definitions
52 : // ===========================================================================
53 79614 : 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 79614 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 79614 : myOrigin(origin),
59 79614 : myLines(lines.begin(), lines.end()),
60 79614 : myVehicle(nullptr),
61 79614 : myVehicleID("NULL"),
62 79614 : myVehicleVClass(SVC_IGNORING),
63 79614 : myVehicleDistance(-1.),
64 79614 : myTimeLoss(-1),
65 79614 : myWaitingPos(-1),
66 79614 : myWaitingSince(-1),
67 79614 : myWaitingEdge(nullptr),
68 79614 : myStopWaitPos(Position::INVALID),
69 79614 : myOriginStop(nullptr),
70 79614 : myIntendedVehicleID(intendedVeh),
71 79614 : myIntendedDepart(intendedDepart) {
72 79614 : }
73 :
74 :
75 : MSStage*
76 67746 : MSStageDriving::clone() const {
77 67746 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
78 135492 : std::vector<std::string>(myLines.begin(), myLines.end()),
79 67746 : myGroup, myIntendedVehicleID, myIntendedDepart);
80 67746 : clon->setParameters(*this);
81 67746 : return clon;
82 : }
83 :
84 :
85 238827 : MSStageDriving::~MSStageDriving() {}
86 :
87 :
88 : void
89 74883 : MSStageDriving::init(MSTransportable* transportable) {
90 149766 : if (hasParameter("earliestPickupTime")) {
91 162 : SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
92 324 : if (hasParameter("reservationTime")) {
93 312 : reservationTime = string2time(getParameter("reservationTime"));
94 : }
95 324 : SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
96 162 : if (transportable->getNextStage(1) == this) {
97 : // if the ride is the first stage use the departPos (there is a unvisible stop before)
98 144 : myWaitingPos = transportable->getParameter().departPos;
99 : } else {
100 : // else use the middle of the edge, as also used as default for walk's arrivalPos
101 18 : myWaitingPos = myOrigin->getLength() / 2;
102 : }
103 162 : myReservationWaitingPos = myWaitingPos;
104 162 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new BookReservation(transportable, earliestPickupTime, this), reservationTime);
105 : }
106 74883 : }
107 :
108 :
109 : const MSEdge*
110 112935 : MSStageDriving::getEdge() const {
111 112935 : if (myVehicle != nullptr) {
112 95708 : if (myVehicle->getLane() != nullptr) {
113 87332 : return &myVehicle->getLane()->getEdge();
114 : }
115 8376 : return myVehicle->getEdge();
116 17227 : } else if (myArrived >= 0) {
117 15382 : return myDestination;
118 : } else {
119 1845 : return myWaitingEdge;
120 : }
121 : }
122 :
123 :
124 : const MSEdge*
125 4723 : MSStageDriving::getFromEdge() const {
126 4723 : return myWaitingEdge;
127 : }
128 :
129 :
130 : double
131 2446214 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
132 2446214 : if (isWaiting4Vehicle()) {
133 2352024 : return myWaitingPos;
134 94190 : } else if (myArrived >= 0) {
135 2653 : return myArrivalPos;
136 : } else {
137 : // vehicle may already have passed the lane (check whether this is correct)
138 91537 : return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
139 : }
140 : }
141 :
142 : int
143 84 : MSStageDriving::getDirection() const {
144 84 : if (isWaiting4Vehicle()) {
145 0 : return MSPModel::UNDEFINED_DIRECTION;
146 84 : } else if (myArrived >= 0) {
147 0 : return MSPModel::UNDEFINED_DIRECTION;
148 : } else {
149 84 : return MSPModel::FORWARD;
150 : }
151 : }
152 :
153 : const MSLane*
154 76 : MSStageDriving::getLane() const {
155 76 : return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
156 : }
157 :
158 :
159 : Position
160 405775 : MSStageDriving::getPosition(SUMOTime /* now */) const {
161 405775 : if (isWaiting4Vehicle()) {
162 : if (myStopWaitPos != Position::INVALID) {
163 138975 : return myStopWaitPos;
164 : }
165 214991 : return getEdgePosition(myWaitingEdge, myWaitingPos,
166 214991 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
167 51809 : } else if (myArrived >= 0) {
168 0 : return getEdgePosition(myDestination, myArrivalPos,
169 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
170 : } else {
171 51809 : return myVehicle->getPosition();
172 : }
173 : }
174 :
175 :
176 : double
177 405767 : MSStageDriving::getAngle(SUMOTime /* now */) const {
178 405767 : if (isWaiting4Vehicle()) {
179 353966 : const double offset = myOriginStop == nullptr ? M_PI / 2 : myOriginStop->getAngle();
180 707916 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + offset * (MSGlobals::gLefthand ? -1 : 1);
181 51801 : } else if (myArrived >= 0) {
182 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
183 : } else {
184 51801 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
185 51801 : if (veh != nullptr) {
186 48180 : return veh->getAngle();
187 : } else {
188 : return 0;
189 : }
190 : }
191 : }
192 :
193 :
194 : double
195 7680 : MSStageDriving::getDistance() const {
196 7680 : if (myVehicle != nullptr) {
197 : // distance was previously set to driven distance upon embarking
198 485 : return myVehicle->getOdometer() - myVehicleDistance;
199 : }
200 7195 : return myVehicleDistance;
201 : }
202 :
203 :
204 : std::string
205 76131 : MSStageDriving::getStageDescription(const bool isPerson) const {
206 139227 : 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 79047 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
228 79047 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
229 79047 : ? previous->getOriginStop()
230 : : previous->getDestinationStop());
231 79047 : myWaitingSince = now;
232 79047 : const bool isPerson = transportable->isPerson();
233 79047 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
234 79047 : && transportable->getCurrentStageIndex() == 1) {
235 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
236 : const std::string vehID = *myLines.begin();
237 1712 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
238 1712 : if (startVeh == nullptr && net->hasFlow(vehID)) {
239 808 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
240 : }
241 1712 : if (startVeh == nullptr) {
242 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
243 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
244 : }
245 1712 : if (transportable->isPerson()) {
246 1690 : const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
247 1690 : 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 1712 : myDeparted = now;
259 1712 : setVehicle(startVeh);
260 1712 : if (myOriginStop != nullptr) {
261 0 : myOriginStop->removeTransportable(transportable);
262 : }
263 1712 : myWaitingEdge = previous->getEdge();
264 1712 : myStopWaitPos = Position::INVALID;
265 1712 : myWaitingPos = previous->getEdgePos(now);
266 1712 : myVehicle->addTransportable(transportable);
267 : return;
268 : }
269 77335 : if (myOriginStop != nullptr) {
270 : // the arrival stop may have an access point
271 23998 : myWaitingEdge = &myOriginStop->getLane().getEdge();
272 23998 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
273 23998 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
274 : } else {
275 53337 : myWaitingEdge = previous->getEdge();
276 53337 : myStopWaitPos = Position::INVALID;
277 53337 : myWaitingPos = previous->getEdgePos(now);
278 : }
279 51318 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
280 77358 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
281 : // transfer at junction (rather than access)
282 15 : myWaitingEdge = myOrigin;
283 15 : myWaitingPos = 0;
284 : }
285 77335 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
286 77335 : const bool triggered = availableVehicle != nullptr &&
287 4540 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
288 311 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
289 2062 : if (triggered && !availableVehicle->hasDeparted()) {
290 2034 : setVehicle(availableVehicle);
291 2034 : if (myOriginStop != nullptr) {
292 0 : myOriginStop->removeTransportable(transportable);
293 : }
294 2034 : myVehicle->addTransportable(transportable);
295 2034 : net->getInsertionControl().add(myVehicle);
296 2034 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
297 : } else {
298 75301 : registerWaiting(transportable, now);
299 : }
300 : }
301 :
302 :
303 : void
304 75379 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
305 : // check if the ride can be conducted and reserve it
306 75379 : if (MSDevice_Taxi::isReservation(getLines())) {
307 3150 : const MSEdge* to = getDestination();
308 3150 : double toPos = getArrivalPos();
309 3150 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
310 : // try to find usable access edge
311 24 : 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 3150 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
321 : // try to find usable access edge
322 29 : 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 3150 : if (myReservationWaitingPos == INVALID_DOUBLE) {
334 2988 : 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, myReservationWaitingPos, to, toPos, myGroup, myWaitingPos);
338 : }
339 : }
340 : // check required for state-loading
341 75379 : if (myVehicle == nullptr) {
342 75364 : if (transportable->isPerson()) {
343 21719 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
344 : } else {
345 53645 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
346 : }
347 75364 : myWaitingEdge->addTransportable(transportable);
348 : }
349 75379 : }
350 :
351 : SUMOTime
352 7480 : MSStageDriving::getDuration() const {
353 7480 : return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
354 : }
355 :
356 :
357 : SUMOTime
358 7480 : MSStageDriving::getTravelTime() const {
359 7480 : return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
360 : }
361 :
362 :
363 : SUMOTime
364 15036 : MSStageDriving::getWaitingTime() const {
365 15036 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
366 15036 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
367 : }
368 :
369 :
370 : SUMOTime
371 14624 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
372 14624 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
373 : }
374 :
375 : void
376 7480 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
377 7480 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
378 7480 : const SUMOTime waitingTime = getWaitingTime();
379 7480 : const SUMOTime duration = myArrived - myDeparted;
380 7480 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
381 8115 : os.openTag(transportable->isPerson() ? "ride" : "transport");
382 7480 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
383 7480 : os.writeAttr("vehicle", myVehicleID);
384 7480 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
385 7480 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
386 7480 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
387 7816 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
388 336 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
389 7480 : os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
390 7480 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
391 7480 : os.closeTag();
392 7480 : }
393 :
394 :
395 : void
396 2144 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
397 2236 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
398 2144 : if (getFromEdge() != nullptr) {
399 2038 : os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
400 106 : } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
401 106 : os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
402 : }
403 2144 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
404 2144 : std::string comment = "";
405 2144 : if (myDestinationStop != nullptr) {
406 701 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
407 701 : if (myDestinationStop->getMyName() != "") {
408 132 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
409 : }
410 1443 : } else if (!unspecifiedArrivalPos()) {
411 1273 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
412 : }
413 2144 : if (myLines.size() > 1 || *myLines.begin() != LINE_ANY) {
414 : // no need to write the default
415 1833 : os.writeAttr(SUMO_ATTR_LINES, myLines);
416 : }
417 2144 : if (myIntendedVehicleID != "") {
418 275 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
419 : }
420 2144 : if (myIntendedDepart >= 0) {
421 275 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
422 : }
423 2144 : if (withRouteLength) {
424 12 : os.writeAttr("routeLength", myVehicleDistance);
425 : }
426 4288 : if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
427 54 : os.writeAttr("vehicle", myVehicleID);
428 54 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
429 54 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
430 : }
431 4288 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
432 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
433 : }
434 2144 : os.closeTag(comment);
435 2144 : }
436 :
437 :
438 : bool
439 2519104 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
440 : assert(myLines.size() > 0);
441 : return (myLines.count(vehicle->getID()) > 0
442 2499855 : || ((myLines.count(vehicle->getParameter().line) > 0
443 190210 : || myLines.count(LINE_ANY) > 0) &&
444 : // even if the line matches we still have to check for stops (#14526)
445 2447787 : (myDestinationStop == nullptr
446 2447787 : ? vehicle->stopsAtEdge(myDestination)
447 2257577 : : vehicle->stopsAt(myDestinationStop)))
448 2506962 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
449 : }
450 :
451 :
452 : bool
453 5237729 : MSStageDriving::isWaiting4Vehicle() const {
454 5237729 : return myVehicle == nullptr && myArrived < 0;
455 : }
456 :
457 :
458 : SUMOTime
459 0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
460 0 : return isWaiting4Vehicle() ? now - myWaitingSince : 0;
461 : }
462 :
463 :
464 : double
465 152068 : MSStageDriving::getSpeed() const {
466 152068 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
467 : }
468 :
469 :
470 : ConstMSEdgeVector
471 536 : MSStageDriving::getEdges() const {
472 : ConstMSEdgeVector result;
473 536 : result.push_back(getFromEdge());
474 536 : result.push_back(getDestination());
475 536 : return result;
476 0 : }
477 :
478 :
479 : double
480 47613 : MSStageDriving::getArrivalPos() const {
481 47613 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
482 : }
483 :
484 :
485 : const std::string
486 14046 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
487 14046 : MSStage::setArrived(net, transportable, now, vehicleArrived);
488 14046 : if (myVehicle != nullptr) {
489 : // distance was previously set to driven distance upon embarking
490 13953 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
491 13953 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
492 13953 : if (vehicleArrived) {
493 4190 : myArrivalPos = myVehicle->getArrivalPos();
494 : } else {
495 9763 : myArrivalPos = myVehicle->getPositionOnLane();
496 : }
497 : const MSStoppingPlace* const stop = getDestinationStop();
498 13953 : if (stop != nullptr) {
499 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
500 7202 : for (const auto& access : stop->getAllAccessPos()) {
501 2612 : if (access.exit != exit) {
502 : exit = access.exit;
503 : break;
504 : }
505 : }
506 4983 : if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
507 393 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
508 393 : 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 : const double doorWidth = train->getVehicleType().getParameter().carriageDoorWidth;
522 336 : randomDoor.add(direction * RandHelper::rand(-0.5 * doorWidth, 0.5 * doorWidth));
523 : // Project onto the lane.
524 336 : myArrivalPos = lane->getShape().nearest_offset_to_point2D(randomDoor);
525 336 : myArrivalPos = lane->interpolateGeometryPosToLanePos(myArrivalPos);
526 672 : myArrivalPos = MIN2(MAX2(0., myArrivalPos), myVehicle->getEdge()->getLength());
527 : } else {
528 0 : std::vector<Position>& unboardingPositions = static_cast<MSDevice_Transportable*>(train->getDevice(typeid(MSDevice_Transportable)))->getUnboardingPositions();
529 0 : if (unboardingPositions.empty()) {
530 0 : const MSVehicleType* defaultPedestrianType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
531 0 : const double defaultPassengerRadius = MAX2(defaultPedestrianType->getLength(), defaultPedestrianType->getWidth()) / 2.;
532 0 : trainHelper.computeUnboardingPositions(defaultPassengerRadius, unboardingPositions);
533 : }
534 : // Random shuffling of the positions has already been done in the train helper.
535 0 : const Position availableUnboardingPosition = unboardingPositions.back();
536 : unboardingPositions.pop_back();
537 0 : const Position arrivalPos = lane->getShape().transformToVectorCoordinates(availableUnboardingPosition);
538 0 : myArrivalPos = arrivalPos.x();
539 0 : myArrivalPosLat = arrivalPos.y();
540 : }
541 336 : }
542 : }
543 : }
544 : } else {
545 93 : myVehicleDistance = -1.;
546 93 : myTimeLoss = -1;
547 : }
548 14046 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
549 14046 : return "";
550 : }
551 :
552 :
553 : void
554 14126 : MSStageDriving::setVehicle(SUMOVehicle* v) {
555 14126 : myVehicle = v;
556 14126 : if (myVehicle != nullptr) {
557 14116 : myVehicleID = v->getID();
558 14116 : myVehicleLine = v->getParameter().line;
559 14116 : myVehicleType = v->getVehicleType().getID();
560 14116 : myVehicleVClass = v->getVClass();
561 14116 : if (myVehicle->hasDeparted()) {
562 11171 : myVehicleDistance = myVehicle->getOdometer();
563 11171 : myTimeLoss = myVehicle->getTimeLoss();
564 : } else {
565 : // it probably got triggered by the person
566 2945 : myVehicleDistance = 0.;
567 2945 : myTimeLoss = 0;
568 : }
569 : }
570 14126 : }
571 :
572 :
573 : void
574 106 : MSStageDriving::abort(MSTransportable* t) {
575 106 : myDestinationStop = nullptr;
576 106 : if (myVehicle != nullptr) {
577 : // jumping out of a moving vehicle!
578 13 : myVehicle->removeTransportable(t);
579 13 : myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
580 13 : myArrivalPos = myVehicle->getPositionOnLane();
581 : // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
582 : } else {
583 93 : MSTransportableControl& tc = (t->isPerson() ?
584 93 : MSNet::getInstance()->getPersonControl() :
585 0 : MSNet::getInstance()->getContainerControl());
586 93 : tc.abortWaitingForVehicle(t);
587 93 : MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
588 93 : myDestination = myWaitingEdge;
589 93 : myDestinationStop = myOriginStop;
590 93 : myArrivalPos = myWaitingPos;
591 : }
592 106 : }
593 :
594 :
595 : std::string
596 64633 : MSStageDriving::getWaitingDescription() const {
597 193899 : return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
598 64633 : + " at " + (myOriginStop == nullptr
599 129266 : ? ("edge '" + myWaitingEdge->getID() + "'")
600 139941 : : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
601 129266 : ) : "";
602 : }
603 :
604 :
605 : bool
606 101692 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
607 101692 : const MSEdge* stopEdge = stop.getEdge();
608 : bool canLeave = false;
609 101692 : if (t->getDestination() == stopEdge) {
610 : // if this is the last stage, we can use the arrivalPos of the person
611 93624 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
612 62729 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
613 93624 : const double arrivalPos = (unspecifiedArrivalPos()
614 93624 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
615 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
616 27331 : : getArrivalPos());
617 93624 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
618 : canLeave = true;
619 : }
620 : }
621 101692 : if (myDestinationStop != nullptr) {
622 22369 : if (!canLeave) {
623 : // check with more tolerance due to busStop size and also check
624 : // access edges
625 1794 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
626 1794 : if (accessPos >= 0) {
627 508 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
628 508 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
629 : // accessPos is in the middle of the stop
630 260 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
631 : }
632 508 : canLeave = stop.isInRange(accessPos, tolerance);
633 : }
634 : }
635 : }
636 101692 : return canLeave;
637 : }
638 :
639 :
640 : void
641 78 : MSStageDriving::saveState(std::ostringstream& out) {
642 78 : const bool hasVehicle = myVehicle != nullptr;
643 234 : out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
644 78 : if (hasVehicle) {
645 45 : out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
646 : }
647 78 : }
648 :
649 :
650 : void
651 78 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
652 : bool hasVehicle;
653 : SUMOTime loadedTimeLoss;
654 156 : state >> myWaitingSince >> loadedTimeLoss >> myArrived >> hasVehicle;
655 78 : if (hasVehicle) {
656 : std::string vehID;
657 15 : state >> myDeparted >> vehID;
658 15 : SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
659 15 : setVehicle(startVeh);
660 15 : myTimeLoss = loadedTimeLoss;
661 15 : myVehicle->addTransportable(transportable);
662 15 : state >> myVehicleDistance;
663 : }
664 : // there should always be at least one prior WAITING_FOR_DEPART stage
665 : MSStage* previous = transportable->getNextStage(-1);
666 78 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
667 78 : ? previous->getOriginStop()
668 : : previous->getDestinationStop());
669 78 : if (myOriginStop != nullptr) {
670 2 : if (!hasVehicle) {
671 : // the arrival stop may have an access point
672 2 : myOriginStop->addTransportable(transportable);
673 : }
674 2 : myWaitingEdge = &myOriginStop->getLane().getEdge();
675 2 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
676 2 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
677 : } else {
678 76 : myWaitingEdge = previous->getEdge();
679 76 : myStopWaitPos = Position::INVALID;
680 76 : myWaitingPos = previous->getArrivalPos();
681 : }
682 : // running reservations will be converted in MSDevice_Taxi::addReservation
683 78 : registerWaiting(transportable, myWaitingSince);
684 78 : }
685 :
686 : // ---------------------------------------------------------------------------
687 : // MSStageDriving::BookReservation method definitions
688 : // ---------------------------------------------------------------------------
689 : SUMOTime
690 162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
691 486 : MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
692 162 : myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
693 162 : return 0; // do not repeat
694 : }
695 :
696 : /****************************************************************************/
|