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 79790 : 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 79790 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 79790 : myOrigin(origin),
59 79790 : myLines(lines.begin(), lines.end()),
60 79790 : myVehicle(nullptr),
61 79790 : myVehicleVClass(SVC_IGNORING),
62 79790 : myVehicleDistance(-1.),
63 79790 : myTimeLoss(-1),
64 79790 : myWaitingPos(-1),
65 79790 : myWaitingSince(-1),
66 79790 : myWaitingEdge(origin),
67 79790 : myStopWaitPos(Position::INVALID),
68 79790 : myOriginStop(nullptr),
69 79790 : myIntendedVehicleID(intendedVeh),
70 79790 : myIntendedDepart(intendedDepart) {
71 79790 : }
72 :
73 :
74 : MSStage*
75 67741 : MSStageDriving::clone() const {
76 67741 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
77 135482 : std::vector<std::string>(myLines.begin(), myLines.end()),
78 67741 : myGroup, myIntendedVehicleID, myIntendedDepart);
79 67741 : clon->setParameters(*this);
80 67741 : return clon;
81 : }
82 :
83 :
84 239352 : MSStageDriving::~MSStageDriving() {}
85 :
86 :
87 : void
88 74931 : MSStageDriving::init(MSTransportable* transportable) {
89 149862 : if (hasParameter("earliestPickupTime")) {
90 162 : SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
91 324 : if (hasParameter("reservationTime")) {
92 312 : reservationTime = string2time(getParameter("reservationTime"));
93 : }
94 324 : SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
95 162 : if (transportable->getNextStage(1) == this) {
96 : // if the ride is the first stage use the departPos (there is a unvisible stop before)
97 144 : myWaitingPos = transportable->getParameter().departPos;
98 : } else {
99 : // else use the middle of the edge, as also used as default for walk's arrivalPos
100 18 : myWaitingPos = myOrigin->getLength() / 2;
101 : }
102 162 : myReservationWaitingPos = myWaitingPos;
103 162 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new BookReservation(transportable, earliestPickupTime, this), reservationTime);
104 : }
105 74931 : }
106 :
107 :
108 : const MSEdge*
109 117242 : MSStageDriving::getEdge() const {
110 117242 : if (myVehicle != nullptr) {
111 99879 : if (myVehicle->getLane() != nullptr) {
112 87347 : return &myVehicle->getLane()->getEdge();
113 : }
114 12532 : return myVehicle->getEdge();
115 17363 : } else if (myArrived >= 0) {
116 15518 : return myDestination;
117 : } else {
118 1845 : return myWaitingEdge;
119 : }
120 : }
121 :
122 :
123 : const MSEdge*
124 5161 : MSStageDriving::getFromEdge() const {
125 5161 : return myWaitingEdge;
126 : }
127 :
128 :
129 : double
130 2881814 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
131 2881814 : if (isWaiting4Vehicle()) {
132 2783477 : return myWaitingPos;
133 98337 : } else if (myArrived >= 0) {
134 2669 : return myArrivalPos;
135 : } else {
136 : // vehicle may already have passed the lane (check whether this is correct)
137 95668 : return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
138 : }
139 : }
140 :
141 : int
142 84 : MSStageDriving::getDirection() const {
143 84 : if (isWaiting4Vehicle()) {
144 0 : return MSPModel::UNDEFINED_DIRECTION;
145 84 : } else if (myArrived >= 0) {
146 0 : return MSPModel::UNDEFINED_DIRECTION;
147 : } else {
148 84 : return MSPModel::FORWARD;
149 : }
150 : }
151 :
152 : const MSLane*
153 76 : MSStageDriving::getLane() const {
154 76 : return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
155 : }
156 :
157 :
158 : Position
159 410761 : MSStageDriving::getPosition(SUMOTime /* now */) const {
160 410761 : if (isWaiting4Vehicle()) {
161 : if (myStopWaitPos != Position::INVALID) {
162 141901 : return myStopWaitPos;
163 : }
164 215106 : return getEdgePosition(myWaitingEdge, myWaitingPos,
165 215106 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
166 53754 : } else if (myArrived >= 0) {
167 0 : return getEdgePosition(myDestination, myArrivalPos,
168 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
169 : } else {
170 53754 : return myVehicle->getPosition();
171 : }
172 : }
173 :
174 :
175 : double
176 410753 : MSStageDriving::getAngle(SUMOTime /* now */) const {
177 410753 : if (isWaiting4Vehicle()) {
178 357007 : const double offset = myOriginStop == nullptr ? M_PI / 2 : myOriginStop->getAngle();
179 713998 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + offset * (MSGlobals::gLefthand ? -1 : 1);
180 53746 : } else if (myArrived >= 0) {
181 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
182 : } else {
183 53746 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
184 53746 : if (veh != nullptr) {
185 48061 : return veh->getAngle();
186 : } else {
187 : return 0;
188 : }
189 : }
190 : }
191 :
192 :
193 : double
194 7779 : MSStageDriving::getDistance() const {
195 7779 : if (myVehicle != nullptr) {
196 : // distance was previously set to driven distance upon embarking
197 489 : return myVehicle->getOdometer() - myVehicleDistance;
198 : }
199 7290 : return myVehicleDistance;
200 : }
201 :
202 :
203 : std::string
204 81946 : MSStageDriving::getStageDescription(const bool isPerson) const {
205 152542 : return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
206 : }
207 :
208 :
209 : std::string
210 0 : MSStageDriving::getStageSummary(const bool isPerson) const {
211 0 : const std::string dest = (getDestinationStop() == nullptr ?
212 0 : " edge '" + getDestination()->getID() + "'" :
213 0 : " stop '" + getDestinationStop()->getID() + "'" + (
214 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
215 0 : const std::string intended = myIntendedVehicleID != "" ?
216 0 : " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
217 0 : "";
218 0 : const std::string modeName = isPerson ? "driving" : "transported";
219 0 : return isWaiting4Vehicle() ?
220 0 : "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
221 0 : modeName + " to " + dest;
222 : }
223 :
224 :
225 : void
226 79178 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
227 79178 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
228 79178 : ? previous->getOriginStop()
229 : : previous->getDestinationStop());
230 79178 : myWaitingSince = now;
231 79178 : const bool isPerson = transportable->isPerson();
232 79178 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
233 79178 : && transportable->getCurrentStageIndex() == 1) {
234 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
235 : const std::string vehID = *myLines.begin();
236 1722 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
237 1722 : if (startVeh == nullptr && net->hasFlow(vehID)) {
238 808 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
239 : }
240 1722 : if (startVeh == nullptr) {
241 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
242 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
243 : }
244 1722 : if (transportable->isPerson()) {
245 1700 : const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
246 1700 : if (startVeh->getPersonNumber() >= pCap) {
247 312 : WRITE_WARNING(TLF("Vehicle '%' exceeds personCapacity % when placing triggered person '%', time=%",
248 : startVeh->getID(), pCap, transportable->getID(), time2string(SIMSTEP)));
249 : }
250 : } else {
251 22 : const int cCap = startVeh->getVehicleType().getParameter().containerCapacity;
252 22 : if (startVeh->getContainerNumber() >= cCap) {
253 48 : WRITE_WARNING(TLF("Vehicle '%' exceeds containerCapacity % when placing triggered container '%', time=%",
254 : startVeh->getID(), cCap, transportable->getID(), time2string(SIMSTEP)));
255 : }
256 : }
257 1722 : myDeparted = now;
258 1722 : setVehicle(startVeh);
259 1722 : if (myOriginStop != nullptr) {
260 0 : myOriginStop->removeTransportable(transportable);
261 : }
262 1722 : myWaitingEdge = previous->getEdge();
263 1722 : myStopWaitPos = Position::INVALID;
264 1722 : myWaitingPos = previous->getEdgePos(now);
265 1722 : myVehicle->addTransportable(transportable);
266 : return;
267 : }
268 77456 : if (myOriginStop != nullptr) {
269 : // the arrival stop may have an access point
270 24003 : myWaitingEdge = &myOriginStop->getLane().getEdge();
271 24003 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
272 24003 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
273 : } else {
274 53453 : myWaitingEdge = previous->getEdge();
275 53453 : myStopWaitPos = Position::INVALID;
276 53453 : myWaitingPos = previous->getEdgePos(now);
277 : }
278 51396 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
279 77479 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
280 : // transfer at junction (rather than access)
281 15 : myWaitingEdge = myOrigin;
282 15 : myWaitingPos = 0;
283 : }
284 77456 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
285 77456 : const bool triggered = availableVehicle != nullptr &&
286 4582 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
287 311 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
288 2084 : if (triggered && !availableVehicle->hasDeparted()) {
289 2056 : setVehicle(availableVehicle);
290 2056 : if (myOriginStop != nullptr) {
291 0 : myOriginStop->removeTransportable(transportable);
292 : }
293 2056 : myVehicle->addTransportable(transportable);
294 2056 : net->getInsertionControl().add(myVehicle);
295 2056 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
296 : } else {
297 75400 : registerWaiting(transportable, now);
298 : }
299 : }
300 :
301 :
302 : void
303 75492 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
304 : // check if the ride can be conducted and reserve it
305 75492 : if (MSDevice_Taxi::isReservation(getLines())) {
306 3253 : const MSEdge* to = getDestination();
307 3253 : double toPos = getArrivalPos();
308 3253 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
309 : // try to find usable access edge
310 23 : for (const auto& access : getDestinationStop()->getAllAccessPos()) {
311 6 : const MSEdge* accessEdge = &access.lane->getEdge();
312 6 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
313 : to = accessEdge;
314 6 : toPos = access.endPos;
315 6 : break;
316 : }
317 : }
318 : }
319 3253 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
320 : // try to find usable access edge
321 28 : for (const auto& access : myOriginStop->getAllAccessPos()) {
322 11 : const MSEdge* accessEdge = &access.lane->getEdge();
323 11 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
324 11 : myWaitingEdge = accessEdge;
325 11 : myStopWaitPos = Position::INVALID;
326 11 : myWaitingPos = access.endPos;
327 11 : break;
328 : }
329 : }
330 : }
331 : // Create reservation only if not already created by previous reservationTime
332 3253 : if (myReservationWaitingPos == INVALID_DOUBLE) {
333 3091 : MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
334 : } else {
335 : // update "fromPos" with current (new) value of myWaitingPos
336 162 : MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationWaitingPos, to, toPos, myGroup, myWaitingPos);
337 : }
338 : }
339 : // check required for state-loading
340 75492 : if (myVehicle == nullptr) {
341 75466 : if (transportable->isPerson()) {
342 21821 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
343 : } else {
344 53645 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
345 : }
346 75466 : myWaitingEdge->addTransportable(transportable);
347 : }
348 75492 : }
349 :
350 : SUMOTime
351 7578 : MSStageDriving::getDuration() const {
352 7578 : return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
353 : }
354 :
355 :
356 : SUMOTime
357 7578 : MSStageDriving::getTravelTime() const {
358 7578 : return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
359 : }
360 :
361 :
362 : SUMOTime
363 15232 : MSStageDriving::getWaitingTime() const {
364 15232 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
365 15232 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
366 : }
367 :
368 :
369 : SUMOTime
370 14817 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
371 14817 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
372 : }
373 :
374 : void
375 7578 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
376 7578 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
377 7578 : const SUMOTime waitingTime = getWaitingTime();
378 7578 : const SUMOTime duration = myArrived - myDeparted;
379 7578 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
380 8213 : os.openTag(transportable->isPerson() ? "ride" : "transport");
381 15156 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
382 14796 : os.writeAttr("vehicle", myVehicleID.empty() ? "NULL" : myVehicleID);
383 7578 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
384 7578 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
385 7578 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
386 7917 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
387 339 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
388 7578 : os.writeAttr(SUMO_ATTR_ROUTELENGTH, myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
389 7578 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
390 7578 : os.closeTag();
391 7578 : }
392 :
393 :
394 : void
395 2311 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous, const bool withTiming, const bool /*saveState*/) const {
396 2403 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
397 2311 : if (getFromEdge() != nullptr) {
398 2309 : os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
399 2 : } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
400 0 : os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
401 : }
402 2311 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
403 2311 : std::string comment = "";
404 2311 : if (myDestinationStop != nullptr) {
405 743 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
406 743 : if (myDestinationStop->getMyName() != "") {
407 138 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
408 : }
409 1568 : } else if (!unspecifiedArrivalPos()) {
410 1350 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
411 : }
412 2311 : if (myLines.size() > 1 || *myLines.begin() != LINE_ANY) {
413 : // no need to write the default
414 1986 : os.writeAttr(SUMO_ATTR_LINES, myLines);
415 : }
416 2311 : if (myIntendedVehicleID != "") {
417 289 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
418 : }
419 2311 : if (myIntendedDepart >= 0) {
420 289 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
421 : }
422 2311 : if (withRouteLength) {
423 37 : os.writeAttr("routeLength", myVehicleDistance);
424 : }
425 2311 : if (withTiming) {
426 144 : os.writeAttr("vehicle", myVehicleID.empty() ? "NULL" : myVehicleID);
427 87 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
428 87 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
429 : }
430 4622 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
431 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
432 : }
433 2311 : os.closeTag(comment);
434 2311 : }
435 :
436 :
437 : bool
438 2913357 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
439 : assert(myLines.size() > 0);
440 : return (myLines.count(vehicle->getID()) > 0
441 2894072 : || ((myLines.count(vehicle->getParameter().line) > 0
442 190416 : || myLines.count(LINE_ANY) > 0) &&
443 : // even if the line matches we still have to check for stops (#14526)
444 2842008 : (myDestinationStop == nullptr
445 2842008 : ? vehicle->stopsAtEdge(myDestination)
446 2651592 : : vehicle->stopsAt(myDestinationStop)))
447 2901359 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
448 : }
449 :
450 :
451 : bool
452 5684989 : MSStageDriving::isWaiting4Vehicle() const {
453 5684989 : return myVehicle == nullptr && myArrived < 0;
454 : }
455 :
456 :
457 : SUMOTime
458 0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
459 0 : return isWaiting4Vehicle() ? now - myWaitingSince : 0;
460 : }
461 :
462 :
463 : double
464 163698 : MSStageDriving::getSpeed() const {
465 163698 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
466 : }
467 :
468 :
469 : ConstMSEdgeVector
470 536 : MSStageDriving::getEdges() const {
471 : ConstMSEdgeVector result;
472 536 : result.push_back(getFromEdge());
473 536 : result.push_back(getDestination());
474 536 : return result;
475 0 : }
476 :
477 :
478 : double
479 48583 : MSStageDriving::getArrivalPos() const {
480 48583 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
481 : }
482 :
483 :
484 : const std::string
485 14173 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
486 14173 : MSStage::setArrived(net, transportable, now, vehicleArrived);
487 14173 : if (myVehicle != nullptr) {
488 : // distance was previously set to driven distance upon embarking
489 14080 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
490 14080 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
491 14080 : if (vehicleArrived) {
492 4211 : myArrivalPos = myVehicle->getArrivalPos();
493 : } else {
494 9869 : myArrivalPos = myVehicle->getPositionOnLane();
495 : }
496 : const MSStoppingPlace* const stop = getDestinationStop();
497 14080 : if (stop != nullptr) {
498 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
499 7242 : for (const auto& access : stop->getAllAccessPos()) {
500 2676 : if (access.exit != exit) {
501 : exit = access.exit;
502 : break;
503 : }
504 : }
505 5016 : if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
506 450 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
507 450 : if (train != nullptr) {
508 336 : MSTrainHelper trainHelper = MSTrainHelper(train);
509 336 : const MSLane* const lane = myVehicle->getLane();
510 672 : if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
511 336 : trainHelper.computeDoorPositions();
512 : const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
513 336 : const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
514 336 : const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
515 336 : const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
516 336 : Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
517 : // Jitter the position before projection because of possible train curvature.
518 : Position direction = randomCarriage->front - randomCarriage->back;
519 336 : direction.norm2D();
520 336 : const double doorWidth = train->getVehicleType().getParameter().carriageDoorWidth;
521 336 : randomDoor.add(direction * RandHelper::rand(-0.5 * doorWidth, 0.5 * doorWidth));
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 93 : myVehicleDistance = -1.;
545 93 : myTimeLoss = -1;
546 : }
547 14173 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
548 14173 : return "";
549 : }
550 :
551 :
552 : void
553 14257 : MSStageDriving::setVehicle(SUMOVehicle* v) {
554 14257 : myVehicle = v;
555 14257 : if (myVehicle != nullptr) {
556 14247 : myVehicleID = v->getID();
557 14247 : myVehicleLine = v->getParameter().line;
558 14247 : myVehicleType = v->getVehicleType().getID();
559 14247 : myVehicleVClass = v->getVClass();
560 14247 : if (myVehicle->hasDeparted()) {
561 11270 : myVehicleDistance = myVehicle->getOdometer();
562 11270 : myTimeLoss = myVehicle->getTimeLoss();
563 : } else {
564 : // it probably got triggered by the person
565 2977 : myVehicleDistance = 0.;
566 2977 : myTimeLoss = 0;
567 : }
568 : }
569 14257 : }
570 :
571 :
572 : void
573 107 : MSStageDriving::abort(MSTransportable* t) {
574 107 : myDestinationStop = nullptr;
575 107 : if (myVehicle != nullptr) {
576 : // jumping out of a moving vehicle!
577 14 : myVehicle->removeTransportable(t);
578 14 : myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
579 14 : myArrivalPos = myVehicle->getPositionOnLane();
580 : // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
581 : } else {
582 93 : MSTransportableControl& tc = (t->isPerson() ?
583 93 : MSNet::getInstance()->getPersonControl() :
584 0 : MSNet::getInstance()->getContainerControl());
585 93 : tc.abortWaitingForVehicle(t);
586 93 : MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
587 93 : myDestination = myWaitingEdge;
588 93 : myDestinationStop = myOriginStop;
589 93 : myArrivalPos = myWaitingPos;
590 : }
591 107 : }
592 :
593 :
594 : std::string
595 64632 : MSStageDriving::getWaitingDescription() const {
596 193896 : return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
597 64632 : + " at " + (myOriginStop == nullptr
598 129264 : ? ("edge '" + myWaitingEdge->getID() + "'")
599 139936 : : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
600 129264 : ) : "";
601 : }
602 :
603 :
604 : bool
605 103425 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
606 103425 : const MSEdge* stopEdge = stop.getEdge();
607 : bool canLeave = false;
608 103425 : if (t->getDestination() == stopEdge) {
609 : // if this is the last stage, we can use the arrivalPos of the person
610 95354 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
611 63862 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
612 95354 : const double arrivalPos = (unspecifiedArrivalPos()
613 95354 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
614 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
615 27928 : : getArrivalPos());
616 95354 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
617 : canLeave = true;
618 : }
619 : }
620 103425 : if (myDestinationStop != nullptr) {
621 22665 : if (!canLeave) {
622 : // check with more tolerance due to busStop size and also check
623 : // access edges
624 1822 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
625 1822 : if (accessPos >= 0) {
626 533 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
627 533 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
628 : // accessPos is in the middle of the stop
629 285 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
630 : }
631 533 : canLeave = stop.isInRange(accessPos, tolerance);
632 : }
633 : }
634 : }
635 103425 : return canLeave;
636 : }
637 :
638 :
639 : void
640 92 : MSStageDriving::saveState(std::ostringstream& out, MSTransportable* transportable) {
641 92 : const bool hasVehicle = myVehicle != nullptr;
642 276 : out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
643 92 : if (hasVehicle) {
644 78 : out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
645 66 : } else if (myOriginStop != nullptr) {
646 2 : out.setf(std::ios::fixed, std::ios::floatfield);
647 2 : out << std::setprecision(gPrecision);
648 2 : out << " " << myOriginStop->checkWaitingSpot(transportable);
649 2 : out << " " << myWaitingPos << " " << myStopWaitPos.x() << " " << myStopWaitPos.y();
650 : }
651 92 : }
652 :
653 :
654 : void
655 92 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
656 : // there should always be at least one prior WAITING_FOR_DEPART stage
657 : MSStage* previous = transportable->getNextStage(-1);
658 92 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
659 92 : ? previous->getOriginStop()
660 : : previous->getDestinationStop());
661 : bool hasVehicle;
662 : SUMOTime loadedTimeLoss;
663 184 : state >> myWaitingSince >> loadedTimeLoss >> myArrived >> hasVehicle;
664 92 : if (hasVehicle) {
665 : std::string vehID;
666 26 : state >> myDeparted >> vehID;
667 26 : SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
668 26 : setVehicle(startVeh);
669 26 : myTimeLoss = loadedTimeLoss;
670 26 : myVehicle->addTransportable(transportable);
671 26 : state >> myVehicleDistance;
672 66 : } else if (myOriginStop != nullptr) {
673 : int waitingSpot;
674 2 : state >> waitingSpot;
675 2 : state >> myWaitingPos;
676 : double x, y;
677 : state >> x;
678 : state >> y;
679 2 : myStopWaitPos = Position(x, y);
680 2 : myOriginStop->addTransportable(transportable, waitingSpot);
681 2 : myWaitingEdge = &myOriginStop->getLane().getEdge();
682 : } else {
683 64 : myWaitingEdge = previous->getEdge();
684 64 : myStopWaitPos = Position::INVALID;
685 64 : myWaitingPos = previous->getArrivalPos();
686 : }
687 : // running reservations will be converted in MSDevice_Taxi::addReservation
688 92 : registerWaiting(transportable, myWaitingSince);
689 92 : }
690 :
691 : // ---------------------------------------------------------------------------
692 : // MSStageDriving::BookReservation method definitions
693 : // ---------------------------------------------------------------------------
694 : SUMOTime
695 162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
696 486 : MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
697 162 : myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
698 162 : return 0; // do not repeat
699 : }
700 :
701 : /****************************************************************************/
|