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 138763 : 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 138763 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 138763 : myOrigin(origin),
59 138763 : myLines(lines.begin(), lines.end()),
60 138763 : myVehicle(nullptr),
61 138763 : myVehicleVClass(SVC_IGNORING),
62 138763 : myVehicleDistance(-1.),
63 138763 : myTimeLoss(-1),
64 138763 : myWaitingPos(-1),
65 138763 : myWaitingSince(-1),
66 138763 : myWaitingEdge(origin),
67 138763 : myStopWaitPos(Position::INVALID),
68 138763 : myOriginStop(nullptr),
69 138763 : myIntendedVehicleID(intendedVeh),
70 138763 : myIntendedDepart(intendedDepart) {
71 138763 : }
72 :
73 :
74 : MSStage*
75 126693 : MSStageDriving::clone() const {
76 126693 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
77 253386 : std::vector<std::string>(myLines.begin(), myLines.end()),
78 126693 : myGroup, myIntendedVehicleID, myIntendedDepart);
79 126693 : clon->setParameters(*this);
80 126693 : return clon;
81 : }
82 :
83 :
84 416274 : MSStageDriving::~MSStageDriving() {}
85 :
86 :
87 : void
88 133890 : MSStageDriving::init(MSTransportable* transportable) {
89 267780 : 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 133890 : }
106 :
107 :
108 : const MSEdge*
109 174359 : MSStageDriving::getEdge() const {
110 174359 : if (myVehicle != nullptr) {
111 98021 : if (myVehicle->getLane() != nullptr) {
112 87350 : return &myVehicle->getLane()->getEdge();
113 : }
114 10671 : return myVehicle->getEdge();
115 76338 : } else if (myArrived >= 0) {
116 74493 : return myDestination;
117 : } else {
118 1845 : return myWaitingEdge;
119 : }
120 : }
121 :
122 :
123 : const MSEdge*
124 5182 : MSStageDriving::getFromEdge() const {
125 5182 : return myWaitingEdge;
126 : }
127 :
128 :
129 : double
130 4218561 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
131 4218561 : if (isWaiting4Vehicle()) {
132 4122002 : return myWaitingPos;
133 96559 : } else if (myArrived >= 0) {
134 2671 : return myArrivalPos;
135 : } else {
136 : // vehicle may already have passed the lane (check whether this is correct)
137 93888 : 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 411168 : MSStageDriving::getPosition(SUMOTime /* now */) const {
160 411168 : if (isWaiting4Vehicle()) {
161 : if (myStopWaitPos != Position::INVALID) {
162 142260 : return myStopWaitPos;
163 : }
164 215902 : return getEdgePosition(myWaitingEdge, myWaitingPos,
165 215902 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
166 53006 : } else if (myArrived >= 0) {
167 0 : return getEdgePosition(myDestination, myArrivalPos,
168 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
169 : } else {
170 53006 : return myVehicle->getPosition();
171 : }
172 : }
173 :
174 :
175 : double
176 411160 : MSStageDriving::getAngle(SUMOTime /* now */) const {
177 411160 : if (isWaiting4Vehicle()) {
178 358162 : const double offset = myOriginStop == nullptr ? M_PI / 2 : myOriginStop->getAngle();
179 716308 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + offset * (MSGlobals::gLefthand ? -1 : 1);
180 52998 : } else if (myArrived >= 0) {
181 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
182 : } else {
183 52998 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
184 52998 : if (veh != nullptr) {
185 48194 : return veh->getAngle();
186 : } else {
187 : return 0;
188 : }
189 : }
190 : }
191 :
192 :
193 : double
194 7788 : MSStageDriving::getDistance() const {
195 7788 : if (myVehicle != nullptr) {
196 : // distance was previously set to driven distance upon embarking
197 489 : return myVehicle->getOdometer() - myVehicleDistance;
198 : }
199 7299 : return myVehicleDistance;
200 : }
201 :
202 :
203 : std::string
204 81063 : MSStageDriving::getStageDescription(const bool isPerson) const {
205 151659 : 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 138152 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
227 138152 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
228 138152 : ? previous->getOriginStop()
229 : : previous->getDestinationStop());
230 138152 : myWaitingSince = now;
231 138152 : const bool isPerson = transportable->isPerson();
232 138152 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
233 138152 : && transportable->getCurrentStageIndex() == 1) {
234 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
235 : const std::string vehID = *myLines.begin();
236 1712 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
237 1712 : if (startVeh == nullptr && net->hasFlow(vehID)) {
238 808 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
239 : }
240 1712 : if (startVeh == nullptr) {
241 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
242 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
243 : }
244 1712 : if (transportable->isPerson()) {
245 1690 : const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
246 1690 : 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 1712 : myDeparted = now;
258 1712 : setVehicle(startVeh);
259 1712 : if (myOriginStop != nullptr) {
260 0 : myOriginStop->removeTransportable(transportable);
261 : }
262 1712 : myWaitingEdge = previous->getEdge();
263 1712 : myStopWaitPos = Position::INVALID;
264 1712 : myWaitingPos = previous->getEdgePos(now);
265 1712 : myVehicle->addTransportable(transportable);
266 : return;
267 : }
268 136440 : if (myOriginStop != nullptr) {
269 : // the arrival stop may have an access point
270 83050 : myWaitingEdge = &myOriginStop->getLane().getEdge();
271 83050 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
272 83050 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
273 : } else {
274 53390 : myWaitingEdge = previous->getEdge();
275 53390 : myStopWaitPos = Position::INVALID;
276 53390 : myWaitingPos = previous->getEdgePos(now);
277 : }
278 51362 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
279 136463 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
280 : // transfer at junction (rather than access)
281 15 : myWaitingEdge = myOrigin;
282 15 : myWaitingPos = 0;
283 : }
284 136440 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
285 136440 : const bool triggered = availableVehicle != nullptr &&
286 24797 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
287 302 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
288 2095 : if (triggered && !availableVehicle->hasDeparted()) {
289 2067 : setVehicle(availableVehicle);
290 2067 : if (myOriginStop != nullptr) {
291 0 : myOriginStop->removeTransportable(transportable);
292 : }
293 2067 : myVehicle->addTransportable(transportable);
294 2067 : net->getInsertionControl().add(myVehicle);
295 2067 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
296 : } else {
297 134373 : registerWaiting(transportable, now);
298 : }
299 : }
300 :
301 :
302 : void
303 134465 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
304 : // check if the ride can be conducted and reserve it
305 134465 : if (MSDevice_Taxi::isReservation(getLines())) {
306 3262 : const MSEdge* to = getDestination();
307 3262 : double toPos = getArrivalPos();
308 3262 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
309 : // try to find usable access edge
310 24 : 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 3262 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
320 : // try to find usable access edge
321 29 : 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 3262 : if (myReservationWaitingPos == INVALID_DOUBLE) {
333 3100 : 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 134465 : if (myVehicle == nullptr) {
341 134439 : if (transportable->isPerson()) {
342 80804 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
343 : } else {
344 53635 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
345 : }
346 134439 : myWaitingEdge->addTransportable(transportable);
347 : }
348 134465 : }
349 :
350 : SUMOTime
351 7580 : MSStageDriving::getDuration() const {
352 7580 : return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
353 : }
354 :
355 :
356 : SUMOTime
357 7580 : MSStageDriving::getTravelTime() const {
358 7580 : return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
359 : }
360 :
361 :
362 : SUMOTime
363 15236 : MSStageDriving::getWaitingTime() const {
364 15236 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
365 15236 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
366 : }
367 :
368 :
369 : SUMOTime
370 14821 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
371 14821 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
372 : }
373 :
374 : void
375 7580 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
376 7580 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
377 7580 : const SUMOTime waitingTime = getWaitingTime();
378 7580 : const SUMOTime duration = myArrived - myDeparted;
379 7580 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
380 8215 : os.openTag(transportable->isPerson() ? "ride" : "transport");
381 15160 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
382 14800 : os.writeAttr("vehicle", myVehicleID.empty() ? "NULL" : myVehicleID);
383 7580 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
384 7580 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
385 7580 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
386 7919 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
387 339 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
388 7580 : os.writeAttr(SUMO_ATTR_ROUTELENGTH, myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
389 7580 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
390 7580 : os.closeTag();
391 7580 : }
392 :
393 :
394 : void
395 2318 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous, const bool withTiming, const bool /*saveState*/) const {
396 2410 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
397 2318 : if (getFromEdge() != nullptr) {
398 2316 : 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 2318 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
403 2318 : std::string comment = "";
404 2318 : if (myDestinationStop != nullptr) {
405 744 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
406 744 : if (myDestinationStop->getMyName() != "") {
407 138 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
408 : }
409 1574 : } else if (!unspecifiedArrivalPos()) {
410 1356 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
411 : }
412 2318 : if (myLines.size() > 1 || *myLines.begin() != LINE_ANY) {
413 : // no need to write the default
414 1993 : os.writeAttr(SUMO_ATTR_LINES, myLines);
415 : }
416 2318 : if (myIntendedVehicleID != "") {
417 289 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
418 : }
419 2318 : if (myIntendedDepart >= 0) {
420 289 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
421 : }
422 2318 : if (withRouteLength) {
423 37 : os.writeAttr("routeLength", myVehicleDistance);
424 : }
425 2318 : 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 4636 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
431 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
432 : }
433 2318 : os.closeTag(comment);
434 2318 : }
435 :
436 :
437 : bool
438 4375199 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
439 : assert(myLines.size() > 0);
440 : return (myLines.count(vehicle->getID()) > 0
441 4355899 : || ((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 4303835 : (myDestinationStop == nullptr
445 4303835 : ? vehicle->stopsAtEdge(myDestination)
446 4113419 : : vehicle->stopsAt(myDestinationStop)))
447 4363186 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
448 : }
449 :
450 :
451 : bool
452 7019888 : MSStageDriving::isWaiting4Vehicle() const {
453 7019888 : 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 161918 : MSStageDriving::getSpeed() const {
465 161918 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
466 : }
467 :
468 :
469 : ConstMSEdgeVector
470 543 : MSStageDriving::getEdges() const {
471 : ConstMSEdgeVector result;
472 543 : result.push_back(getFromEdge());
473 543 : result.push_back(getDestination());
474 543 : return result;
475 0 : }
476 :
477 :
478 : double
479 109562 : MSStageDriving::getArrivalPos() const {
480 109562 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
481 : }
482 :
483 :
484 : const std::string
485 73147 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
486 73147 : MSStage::setArrived(net, transportable, now, vehicleArrived);
487 73147 : if (myVehicle != nullptr) {
488 : // distance was previously set to driven distance upon embarking
489 73054 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
490 73054 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
491 73054 : if (vehicleArrived) {
492 4224 : myArrivalPos = myVehicle->getArrivalPos();
493 : } else {
494 68830 : myArrivalPos = myVehicle->getPositionOnLane();
495 : }
496 : const MSStoppingPlace* const stop = getDestinationStop();
497 73054 : if (stop != nullptr) {
498 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
499 66155 : for (const auto& access : stop->getAllAccessPos()) {
500 2626 : if (access.exit != exit) {
501 : exit = access.exit;
502 : break;
503 : }
504 : }
505 63969 : if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
506 440 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
507 440 : 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 73147 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
548 73147 : return "";
549 : }
550 :
551 :
552 : void
553 73231 : MSStageDriving::setVehicle(SUMOVehicle* v) {
554 73231 : myVehicle = v;
555 73231 : if (myVehicle != nullptr) {
556 73221 : myVehicleID = v->getID();
557 73221 : myVehicleLine = v->getParameter().line;
558 73221 : myVehicleType = v->getVehicleType().getID();
559 73221 : myVehicleVClass = v->getVClass();
560 73221 : if (myVehicle->hasDeparted()) {
561 70243 : myVehicleDistance = myVehicle->getOdometer();
562 70243 : myTimeLoss = myVehicle->getTimeLoss();
563 : } else {
564 : // it probably got triggered by the person
565 2978 : myVehicleDistance = 0.;
566 2978 : myTimeLoss = 0;
567 : }
568 : }
569 73231 : }
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 251826 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
606 251826 : const MSEdge* stopEdge = stop.getEdge();
607 : bool canLeave = false;
608 251826 : if (t->getDestination() == stopEdge) {
609 : // if this is the last stage, we can use the arrivalPos of the person
610 156471 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
611 63868 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
612 156471 : const double arrivalPos = (unspecifiedArrivalPos()
613 156471 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
614 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
615 89039 : : getArrivalPos());
616 156471 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
617 : canLeave = true;
618 : }
619 : }
620 251826 : if (myDestinationStop != nullptr) {
621 171058 : if (!canLeave) {
622 : // check with more tolerance due to busStop size and also check
623 : // access edges
624 89086 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
625 89086 : if (accessPos >= 0) {
626 513 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
627 513 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
628 : // accessPos is in the middle of the stop
629 265 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
630 : }
631 513 : canLeave = stop.isInRange(accessPos, tolerance);
632 : }
633 : }
634 : }
635 251826 : 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 : /****************************************************************************/
|