Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 81428 : 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 81428 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 81428 : myOrigin(origin),
59 81428 : myLines(lines.begin(), lines.end()),
60 81428 : myVehicle(nullptr),
61 81428 : myVehicleID("NULL"),
62 81428 : myVehicleVClass(SVC_IGNORING),
63 81428 : myVehicleDistance(-1.),
64 81428 : myTimeLoss(-1),
65 81428 : myWaitingPos(-1),
66 81428 : myWaitingSince(-1),
67 81428 : myWaitingEdge(nullptr),
68 81428 : myStopWaitPos(Position::INVALID),
69 81428 : myOriginStop(nullptr),
70 81428 : myIntendedVehicleID(intendedVeh),
71 81428 : myIntendedDepart(intendedDepart),
72 81428 : myReservationCommand(nullptr) {
73 81428 : }
74 :
75 :
76 : MSStage*
77 70725 : MSStageDriving::clone() const {
78 70725 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
79 141450 : std::vector<std::string>(myLines.begin(), myLines.end()),
80 70725 : myGroup, myIntendedVehicleID, myIntendedDepart);
81 70725 : clon->setParameters(*this);
82 70725 : return clon;
83 : }
84 :
85 :
86 244197 : MSStageDriving::~MSStageDriving() {}
87 :
88 :
89 : void
90 76643 : MSStageDriving::init(MSTransportable* transportable) {
91 153286 : if (hasParameter("earliestPickupTime")) {
92 162 : SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
93 324 : if (hasParameter("reservationTime")) {
94 312 : reservationTime = string2time(getParameter("reservationTime"));
95 : }
96 324 : SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
97 162 : if (transportable->getNextStage(1) == this) {
98 : // if the ride is the first stage use the departPos (there is a unvisible stop before)
99 144 : myWaitingPos = transportable->getParameter().departPos;
100 : } else {
101 : // else use the middle of the edge, as also used as default for walk's arrivalPos
102 18 : myWaitingPos = myOrigin->getLength() / 2;
103 : }
104 162 : myReservationCommand = new BookReservation(transportable, earliestPickupTime, this);
105 162 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myReservationCommand, reservationTime);
106 : }
107 76643 : }
108 :
109 :
110 : const MSEdge*
111 115903 : MSStageDriving::getEdge() const {
112 115903 : if (myVehicle != nullptr) {
113 98851 : if (myVehicle->getLane() != nullptr) {
114 86386 : return &myVehicle->getLane()->getEdge();
115 : }
116 12465 : return myVehicle->getEdge();
117 17052 : } else if (myArrived >= 0) {
118 15207 : return myDestination;
119 : } else {
120 1845 : return myWaitingEdge;
121 : }
122 : }
123 :
124 :
125 : const MSEdge*
126 3492 : MSStageDriving::getFromEdge() const {
127 3492 : return myWaitingEdge;
128 : }
129 :
130 :
131 : double
132 4620200 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
133 4620200 : if (isWaiting4Vehicle()) {
134 4522880 : return myWaitingPos;
135 97320 : } else if (myArrived >= 0) {
136 2652 : return myArrivalPos;
137 : } else {
138 : // vehicle may already have passed the lane (check whether this is correct)
139 94668 : return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
140 : }
141 : }
142 :
143 : int
144 84 : MSStageDriving::getDirection() const {
145 84 : if (isWaiting4Vehicle()) {
146 0 : return MSPModel::UNDEFINED_DIRECTION;
147 84 : } else if (myArrived >= 0) {
148 0 : return MSPModel::UNDEFINED_DIRECTION;
149 : } else {
150 84 : return MSPModel::FORWARD;
151 : }
152 : }
153 :
154 : const MSLane*
155 76 : MSStageDriving::getLane() const {
156 76 : return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
157 : }
158 :
159 :
160 : Position
161 411384 : MSStageDriving::getPosition(SUMOTime /* now */) const {
162 411384 : if (isWaiting4Vehicle()) {
163 : if (myStopWaitPos != Position::INVALID) {
164 143403 : return myStopWaitPos;
165 : }
166 215095 : return getEdgePosition(myWaitingEdge, myWaitingPos,
167 215095 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
168 52886 : } else if (myArrived >= 0) {
169 0 : return getEdgePosition(myDestination, myArrivalPos,
170 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
171 : } else {
172 52886 : return myVehicle->getPosition();
173 : }
174 : }
175 :
176 :
177 : double
178 412549 : MSStageDriving::getAngle(SUMOTime /* now */) const {
179 412549 : if (isWaiting4Vehicle()) {
180 358778 : const double offset = myOriginStop == nullptr ? M_PI / 2 : myOriginStop->getAngle();
181 717540 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + offset * (MSGlobals::gLefthand ? -1 : 1);
182 53771 : } else if (myArrived >= 0) {
183 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
184 : } else {
185 53771 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
186 53771 : if (veh != nullptr) {
187 48136 : return veh->getAngle();
188 : } else {
189 : return 0;
190 : }
191 : }
192 : }
193 :
194 :
195 : double
196 7194 : MSStageDriving::getDistance() const {
197 7194 : if (myVehicle != nullptr) {
198 : // distance was previously set to driven distance upon embarking
199 481 : return myVehicle->getOdometer() - myVehicleDistance;
200 : }
201 6713 : return myVehicleDistance;
202 : }
203 :
204 :
205 : std::string
206 1698 : MSStageDriving::getStageDescription(const bool isPerson) const {
207 2940 : return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
208 : }
209 :
210 :
211 : std::string
212 0 : MSStageDriving::getStageSummary(const bool isPerson) const {
213 0 : const std::string dest = (getDestinationStop() == nullptr ?
214 0 : " edge '" + getDestination()->getID() + "'" :
215 0 : " stop '" + getDestinationStop()->getID() + "'" + (
216 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
217 0 : const std::string intended = myIntendedVehicleID != "" ?
218 0 : " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
219 0 : "";
220 0 : const std::string modeName = isPerson ? "driving" : "transported";
221 0 : return isWaiting4Vehicle() ?
222 0 : "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
223 0 : modeName + " to " + dest;
224 : }
225 :
226 :
227 : void
228 80755 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
229 80755 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
230 80755 : ? previous->getOriginStop()
231 : : previous->getDestinationStop());
232 80755 : myWaitingSince = now;
233 80755 : const bool isPerson = transportable->isPerson();
234 80755 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
235 80755 : && transportable->getCurrentStageIndex() == 1) {
236 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
237 : const std::string vehID = *myLines.begin();
238 1722 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
239 1722 : if (startVeh == nullptr && net->hasFlow(vehID)) {
240 808 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
241 : }
242 1722 : if (startVeh == nullptr) {
243 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
244 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
245 : }
246 1722 : if (transportable->isPerson()) {
247 1700 : const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
248 1700 : if (startVeh->getPersonNumber() >= pCap) {
249 312 : WRITE_WARNING(TLF("Vehicle '%' exceeds personCapacity % when placing triggered person '%', time=%",
250 : startVeh->getID(), pCap, transportable->getID(), time2string(SIMSTEP)));
251 : }
252 : } else {
253 22 : const int cCap = startVeh->getVehicleType().getParameter().containerCapacity;
254 22 : if (startVeh->getContainerNumber() >= cCap) {
255 48 : WRITE_WARNING(TLF("Vehicle '%' exceeds containerCapacity % when placing triggered container '%', time=%",
256 : startVeh->getID(), cCap, transportable->getID(), time2string(SIMSTEP)));
257 : }
258 : }
259 1722 : myDeparted = now;
260 1722 : setVehicle(startVeh);
261 1722 : if (myOriginStop != nullptr) {
262 0 : myOriginStop->removeTransportable(transportable);
263 : }
264 1722 : myWaitingEdge = previous->getEdge();
265 1722 : myStopWaitPos = Position::INVALID;
266 1722 : myWaitingPos = previous->getEdgePos(now);
267 1722 : myVehicle->addTransportable(transportable);
268 : return;
269 : }
270 79033 : if (myOriginStop != nullptr) {
271 : // the arrival stop may have an access point
272 23757 : myWaitingEdge = &myOriginStop->getLane().getEdge();
273 23757 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
274 23757 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
275 : } else {
276 55276 : myWaitingEdge = previous->getEdge();
277 55276 : myStopWaitPos = Position::INVALID;
278 55276 : myWaitingPos = previous->getEdgePos(now);
279 : }
280 53386 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
281 79056 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
282 : // transfer at junction (rather than access)
283 15 : myWaitingEdge = myOrigin;
284 15 : myWaitingPos = 0;
285 : }
286 79033 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
287 79033 : const bool triggered = availableVehicle != nullptr &&
288 4557 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
289 311 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
290 2070 : if (triggered && !availableVehicle->hasDeparted()) {
291 2042 : setVehicle(availableVehicle);
292 2042 : if (myOriginStop != nullptr) {
293 0 : myOriginStop->removeTransportable(transportable);
294 : }
295 2042 : myVehicle->addTransportable(transportable);
296 2042 : net->getInsertionControl().add(myVehicle);
297 2042 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
298 : } else {
299 76991 : registerWaiting(transportable, now);
300 : }
301 : }
302 :
303 :
304 : void
305 76998 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
306 : // check if the ride can be conducted and reserve it
307 76998 : if (MSDevice_Taxi::isReservation(getLines())) {
308 2613 : const MSEdge* to = getDestination();
309 2613 : double toPos = getArrivalPos();
310 2613 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
311 : // try to find usable access edge
312 6 : for (const auto& access : getDestinationStop()->getAllAccessPos()) {
313 6 : const MSEdge* accessEdge = &access.lane->getEdge();
314 6 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
315 : to = accessEdge;
316 6 : toPos = access.endPos;
317 6 : break;
318 : }
319 : }
320 : }
321 2613 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
322 : // try to find usable access edge
323 11 : for (const auto& access : myOriginStop->getAllAccessPos()) {
324 11 : const MSEdge* accessEdge = &access.lane->getEdge();
325 11 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
326 11 : myWaitingEdge = accessEdge;
327 11 : myStopWaitPos = Position::INVALID;
328 11 : myWaitingPos = access.endPos;
329 11 : break;
330 : }
331 : }
332 : }
333 : // Create reservation only if not already created by previous reservationTime
334 2613 : if (myReservationCommand == nullptr) {
335 2451 : MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
336 : } else {
337 : // update "fromPos" with current (new) value of myWaitingPos
338 162 : MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationCommand->myWaitingPos, to, toPos, myGroup, myWaitingPos);
339 : }
340 : }
341 76998 : if (transportable->isPerson()) {
342 21241 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
343 : } else {
344 55757 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
345 : }
346 76998 : myWaitingEdge->addTransportable(transportable);
347 76998 : }
348 :
349 : SUMOTime
350 6928 : MSStageDriving::getDuration() const {
351 6928 : return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
352 : }
353 :
354 :
355 : SUMOTime
356 6928 : MSStageDriving::getTravelTime() const {
357 6928 : return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
358 : }
359 :
360 :
361 : SUMOTime
362 13932 : MSStageDriving::getWaitingTime() const {
363 13932 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
364 13932 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
365 : }
366 :
367 :
368 : SUMOTime
369 13591 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
370 13591 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
371 : }
372 :
373 : void
374 6928 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
375 6928 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
376 6928 : const SUMOTime waitingTime = getWaitingTime();
377 6928 : const SUMOTime duration = myArrived - myDeparted;
378 6928 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
379 7563 : os.openTag(transportable->isPerson() ? "ride" : "transport");
380 13856 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
381 6928 : os.writeAttr("vehicle", myVehicleID);
382 13856 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
383 13856 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
384 13856 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
385 14121 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
386 265 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
387 13856 : os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
388 13856 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
389 6928 : os.closeTag();
390 6928 : }
391 :
392 :
393 : void
394 1480 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
395 1572 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
396 1480 : if (getFromEdge() != nullptr) {
397 1472 : os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
398 8 : } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
399 8 : os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
400 : }
401 1480 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
402 1480 : std::string comment = "";
403 1480 : if (myDestinationStop != nullptr) {
404 581 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
405 581 : if (myDestinationStop->getMyName() != "") {
406 132 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
407 : }
408 899 : } else if (!unspecifiedArrivalPos()) {
409 873 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
410 : }
411 1480 : if (myLines.size() > 1 || *myLines.begin() != LINE_ANY) {
412 : // no need to write the default
413 1169 : os.writeAttr(SUMO_ATTR_LINES, myLines);
414 : }
415 1480 : if (myIntendedVehicleID != "") {
416 275 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
417 : }
418 1480 : if (myIntendedDepart >= 0) {
419 550 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
420 : }
421 1480 : if (withRouteLength) {
422 24 : os.writeAttr("routeLength", myVehicleDistance);
423 : }
424 2960 : if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
425 54 : os.writeAttr("vehicle", myVehicleID);
426 54 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
427 108 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
428 : }
429 2960 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
430 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
431 : }
432 1480 : os.closeTag(comment);
433 1480 : }
434 :
435 :
436 : bool
437 4651512 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
438 : assert(myLines.size() > 0);
439 : return (myLines.count(vehicle->getID()) > 0
440 4632254 : || ((myLines.count(vehicle->getParameter().line) > 0
441 188562 : || myLines.count(LINE_ANY) > 0) &&
442 : // even if the line matches we still have to check for stops (#14526)
443 4580193 : (myDestinationStop == nullptr
444 4580193 : ? vehicle->stopsAtEdge(myDestination)
445 4391631 : : vehicle->stopsAt(myDestinationStop)))
446 4638605 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
447 : }
448 :
449 :
450 : bool
451 7284356 : MSStageDriving::isWaiting4Vehicle() const {
452 7284356 : return myVehicle == nullptr && myArrived < 0;
453 : }
454 :
455 :
456 : SUMOTime
457 0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
458 0 : return isWaiting4Vehicle() ? now - myWaitingSince : 0;
459 : }
460 :
461 :
462 : double
463 81046 : MSStageDriving::getSpeed() const {
464 81046 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
465 : }
466 :
467 :
468 : ConstMSEdgeVector
469 535 : MSStageDriving::getEdges() const {
470 : ConstMSEdgeVector result;
471 535 : result.push_back(getFromEdge());
472 535 : result.push_back(getDestination());
473 535 : return result;
474 0 : }
475 :
476 :
477 : double
478 41492 : MSStageDriving::getArrivalPos() const {
479 41492 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
480 : }
481 :
482 :
483 : const std::string
484 13618 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
485 13618 : MSStage::setArrived(net, transportable, now, vehicleArrived);
486 13618 : if (myVehicle != nullptr) {
487 : // distance was previously set to driven distance upon embarking
488 13525 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
489 13525 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
490 13525 : if (vehicleArrived) {
491 4195 : myArrivalPos = myVehicle->getArrivalPos();
492 : } else {
493 9330 : myArrivalPos = myVehicle->getPositionOnLane();
494 : }
495 : const MSStoppingPlace* const stop = getDestinationStop();
496 13525 : if (stop != nullptr) {
497 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
498 7186 : for (const auto& access : stop->getAllAccessPos()) {
499 2674 : if (access.exit != exit) {
500 : exit = access.exit;
501 : break;
502 : }
503 : }
504 4962 : if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
505 450 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
506 450 : if (train != nullptr) {
507 336 : MSTrainHelper trainHelper = MSTrainHelper(train);
508 336 : const MSLane* const lane = myVehicle->getLane();
509 672 : if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
510 336 : trainHelper.computeDoorPositions();
511 : const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
512 336 : const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
513 336 : const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
514 336 : const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
515 336 : Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
516 : // Jitter the position before projection because of possible train curvature.
517 : Position direction = randomCarriage->front - randomCarriage->back;
518 336 : direction.norm2D();
519 336 : const double doorWidth = train->getVehicleType().getParameter().carriageDoorWidth;
520 336 : randomDoor.add(direction * RandHelper::rand(-0.5 * doorWidth, 0.5 * doorWidth));
521 : // Project onto the lane.
522 336 : myArrivalPos = lane->getShape().nearest_offset_to_point2D(randomDoor);
523 336 : myArrivalPos = lane->interpolateGeometryPosToLanePos(myArrivalPos);
524 672 : myArrivalPos = MIN2(MAX2(0., myArrivalPos), myVehicle->getEdge()->getLength());
525 : } else {
526 0 : std::vector<Position>& unboardingPositions = static_cast<MSDevice_Transportable*>(train->getDevice(typeid(MSDevice_Transportable)))->getUnboardingPositions();
527 0 : if (unboardingPositions.empty()) {
528 0 : const MSVehicleType* defaultPedestrianType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
529 0 : const double defaultPassengerRadius = MAX2(defaultPedestrianType->getLength(), defaultPedestrianType->getWidth()) / 2.;
530 0 : trainHelper.computeUnboardingPositions(defaultPassengerRadius, unboardingPositions);
531 : }
532 : // Random shuffling of the positions has already been done in the train helper.
533 0 : const Position availableUnboardingPosition = unboardingPositions.back();
534 : unboardingPositions.pop_back();
535 0 : const Position arrivalPos = lane->getShape().transformToVectorCoordinates(availableUnboardingPosition);
536 0 : myArrivalPos = arrivalPos.x();
537 0 : myArrivalPosLat = arrivalPos.y();
538 : }
539 336 : }
540 : }
541 : }
542 : } else {
543 93 : myVehicleDistance = -1.;
544 93 : myTimeLoss = -1;
545 : }
546 13618 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
547 13618 : return "";
548 : }
549 :
550 :
551 : void
552 13694 : MSStageDriving::setVehicle(SUMOVehicle* v) {
553 13694 : myVehicle = v;
554 13694 : if (myVehicle != nullptr) {
555 13684 : myVehicleID = v->getID();
556 13684 : myVehicleLine = v->getParameter().line;
557 13684 : myVehicleType = v->getVehicleType().getID();
558 13684 : myVehicleVClass = v->getVClass();
559 13684 : if (myVehicle->hasDeparted()) {
560 10721 : myVehicleDistance = myVehicle->getOdometer();
561 10721 : myTimeLoss = myVehicle->getTimeLoss();
562 : } else {
563 : // it probably got triggered by the person
564 2963 : myVehicleDistance = 0.;
565 2963 : myTimeLoss = 0;
566 : }
567 : }
568 13694 : }
569 :
570 :
571 : void
572 106 : MSStageDriving::abort(MSTransportable* t) {
573 106 : myDestinationStop = nullptr;
574 106 : if (myVehicle != nullptr) {
575 : // jumping out of a moving vehicle!
576 13 : myVehicle->removeTransportable(t);
577 13 : myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
578 13 : myArrivalPos = myVehicle->getPositionOnLane();
579 : // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
580 : } else {
581 93 : MSTransportableControl& tc = (t->isPerson() ?
582 93 : MSNet::getInstance()->getPersonControl() :
583 0 : MSNet::getInstance()->getContainerControl());
584 93 : tc.abortWaitingForVehicle(t);
585 93 : MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
586 93 : myDestination = myWaitingEdge;
587 93 : myDestinationStop = myOriginStop;
588 93 : myArrivalPos = myWaitingPos;
589 : }
590 106 : }
591 :
592 :
593 : std::string
594 604 : MSStageDriving::getWaitingDescription() const {
595 1812 : return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
596 604 : + " at " + (myOriginStop == nullptr
597 1208 : ? ("edge '" + myWaitingEdge->getID() + "'")
598 1676 : : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
599 1208 : ) : "";
600 : }
601 :
602 :
603 : bool
604 85820 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
605 85820 : const MSEdge* stopEdge = stop.getEdge();
606 : bool canLeave = false;
607 85820 : if (t->getDestination() == stopEdge) {
608 : // if this is the last stage, we can use the arrivalPos of the person
609 77905 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
610 51977 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
611 77905 : const double arrivalPos = (unspecifiedArrivalPos()
612 77905 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
613 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
614 22365 : : getArrivalPos());
615 77905 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
616 : canLeave = true;
617 : }
618 : }
619 85820 : if (myDestinationStop != nullptr) {
620 17875 : if (!canLeave) {
621 : // check with more tolerance due to busStop size and also check
622 : // access edges
623 1805 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
624 1805 : if (accessPos >= 0) {
625 529 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
626 529 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
627 : // accessPos is in the middle of the stop
628 281 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
629 : }
630 529 : canLeave = stop.isInRange(accessPos, tolerance);
631 : }
632 : }
633 : }
634 85820 : return canLeave;
635 : }
636 :
637 :
638 : void
639 16 : MSStageDriving::saveState(std::ostringstream& out) {
640 16 : const bool hasVehicle = myVehicle != nullptr;
641 48 : out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
642 16 : if (hasVehicle) {
643 27 : out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
644 : }
645 16 : }
646 :
647 :
648 : void
649 16 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
650 : bool hasVehicle;
651 16 : state >> myWaitingSince >> myTimeLoss >> myArrived >> hasVehicle;
652 16 : if (hasVehicle) {
653 : std::string vehID;
654 9 : state >> myDeparted >> vehID;
655 9 : SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
656 9 : setVehicle(startVeh);
657 9 : myVehicle->addTransportable(transportable);
658 9 : state >> myVehicleDistance;
659 : } else {
660 : // there should always be at least one prior WAITING_FOR_DEPART stage
661 : MSStage* previous = transportable->getNextStage(-1);
662 7 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
663 7 : ? previous->getOriginStop()
664 : : previous->getDestinationStop());
665 7 : if (myOriginStop != nullptr) {
666 : // the arrival stop may have an access point
667 2 : myOriginStop->addTransportable(transportable);
668 2 : myWaitingEdge = &myOriginStop->getLane().getEdge();
669 2 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
670 2 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
671 : } else {
672 5 : myWaitingEdge = previous->getEdge();
673 5 : myStopWaitPos = Position::INVALID;
674 5 : myWaitingPos = previous->getArrivalPos();
675 : }
676 7 : registerWaiting(transportable, SIMSTEP);
677 : }
678 16 : }
679 :
680 : // ---------------------------------------------------------------------------
681 : // MSStageDriving::BookReservation method definitions
682 : // ---------------------------------------------------------------------------
683 : SUMOTime
684 162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
685 486 : MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
686 162 : myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
687 : // do not repeat if execution fails
688 162 : return 0;
689 : }
690 :
691 : /****************************************************************************/
|