Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 79181 : 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 79181 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 79181 : myOrigin(origin),
59 79181 : myLines(lines.begin(), lines.end()),
60 79181 : myVehicle(nullptr),
61 79181 : myVehicleID("NULL"),
62 79181 : myVehicleVClass(SVC_IGNORING),
63 79181 : myVehicleDistance(-1.),
64 79181 : myTimeLoss(-1),
65 79181 : myWaitingPos(-1),
66 79181 : myWaitingSince(-1),
67 79181 : myWaitingEdge(nullptr),
68 79181 : myStopWaitPos(Position::INVALID),
69 79181 : myOriginStop(nullptr),
70 79181 : myIntendedVehicleID(intendedVeh),
71 79181 : myIntendedDepart(intendedDepart),
72 79181 : myReservationCommand(nullptr) {
73 79181 : }
74 :
75 :
76 : MSStage*
77 68962 : MSStageDriving::clone() const {
78 68962 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
79 137924 : std::vector<std::string>(myLines.begin(), myLines.end()),
80 68962 : myGroup, myIntendedVehicleID, myIntendedDepart);
81 68962 : clon->setParameters(*this);
82 68962 : return clon;
83 : }
84 :
85 :
86 237453 : MSStageDriving::~MSStageDriving() {}
87 :
88 :
89 : void
90 74552 : MSStageDriving::init(MSTransportable* transportable) {
91 149104 : 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 74552 : }
108 :
109 :
110 : const MSEdge*
111 114488 : MSStageDriving::getEdge() const {
112 114488 : if (myVehicle != nullptr) {
113 98297 : if (myVehicle->getLane() != nullptr) {
114 85959 : return &myVehicle->getLane()->getEdge();
115 : }
116 12338 : return myVehicle->getEdge();
117 16191 : } else if (myArrived >= 0) {
118 14369 : return myDestination;
119 : } else {
120 1822 : return myWaitingEdge;
121 : }
122 : }
123 :
124 :
125 : const MSEdge*
126 3073 : MSStageDriving::getFromEdge() const {
127 3073 : return myWaitingEdge;
128 : }
129 :
130 :
131 : double
132 343977 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
133 343977 : if (isWaiting4Vehicle()) {
134 247149 : return myWaitingPos;
135 96828 : } else if (myArrived >= 0) {
136 2512 : return myArrivalPos;
137 : } else {
138 : // vehicle may already have passed the lane (check whether this is correct)
139 94316 : return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
140 : }
141 : }
142 :
143 : int
144 60 : MSStageDriving::getDirection() const {
145 60 : if (isWaiting4Vehicle()) {
146 0 : return MSPModel::UNDEFINED_DIRECTION;
147 60 : } else if (myArrived >= 0) {
148 0 : return MSPModel::UNDEFINED_DIRECTION;
149 : } else {
150 60 : 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 409453 : MSStageDriving::getPosition(SUMOTime /* now */) const {
162 409453 : if (isWaiting4Vehicle()) {
163 : if (myStopWaitPos != Position::INVALID) {
164 142567 : return myStopWaitPos;
165 : }
166 214226 : return getEdgePosition(myWaitingEdge, myWaitingPos,
167 428452 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
168 52660 : } else if (myArrived >= 0) {
169 0 : return getEdgePosition(myDestination, myArrivalPos,
170 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
171 : } else {
172 52660 : return myVehicle->getPosition();
173 : }
174 : }
175 :
176 :
177 : double
178 410618 : MSStageDriving::getAngle(SUMOTime /* now */) const {
179 410618 : if (isWaiting4Vehicle()) {
180 714129 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
181 53545 : } else if (myArrived >= 0) {
182 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
183 : } else {
184 53545 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
185 53545 : if (veh != nullptr) {
186 47939 : return veh->getAngle();
187 : } else {
188 : return 0;
189 : }
190 : }
191 : }
192 :
193 :
194 : double
195 6625 : MSStageDriving::getDistance() const {
196 6625 : if (myVehicle != nullptr) {
197 : // distance was previously set to driven distance upon embarking
198 481 : return myVehicle->getOdometer() - myVehicleDistance;
199 : }
200 6144 : return myVehicleDistance;
201 : }
202 :
203 :
204 : std::string
205 1698 : MSStageDriving::getStageDescription(const bool isPerson) const {
206 2940 : return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
207 : }
208 :
209 :
210 : std::string
211 0 : MSStageDriving::getStageSummary(const bool isPerson) const {
212 0 : const std::string dest = (getDestinationStop() == nullptr ?
213 0 : " edge '" + getDestination()->getID() + "'" :
214 0 : " stop '" + getDestinationStop()->getID() + "'" + (
215 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
216 0 : const std::string intended = myIntendedVehicleID != "" ?
217 0 : " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
218 0 : "";
219 0 : const std::string modeName = isPerson ? "driving" : "transported";
220 0 : return isWaiting4Vehicle() ?
221 0 : "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
222 0 : modeName + " to " + dest;
223 : }
224 :
225 :
226 : void
227 78628 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
228 78628 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
229 78628 : ? previous->getOriginStop()
230 : : previous->getDestinationStop());
231 78628 : myWaitingSince = now;
232 78628 : const bool isPerson = transportable->isPerson();
233 78628 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
234 78628 : && transportable->getCurrentStageIndex() == 1) {
235 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
236 : const std::string vehID = *myLines.begin();
237 1458 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
238 1458 : if (startVeh == nullptr && net->hasFlow(vehID)) {
239 568 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
240 : }
241 1458 : if (startVeh == nullptr) {
242 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
243 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
244 : }
245 1458 : if (transportable->isPerson()) {
246 1436 : const int pCap = startVeh->getVehicleType().getParameter().personCapacity;
247 1436 : if (startVeh->getPersonNumber() >= pCap) {
248 312 : WRITE_WARNING(TLF("Vehicle '%' exceeds personCapacity % when placing triggered person '%', time=%",
249 : startVeh->getID(), pCap, transportable->getID(), time2string(SIMSTEP)));
250 : }
251 : } else {
252 22 : const int cCap = startVeh->getVehicleType().getParameter().containerCapacity;
253 22 : if (startVeh->getContainerNumber() >= cCap) {
254 48 : WRITE_WARNING(TLF("Vehicle '%' exceeds containerCapacity % when placing triggered container '%', time=%",
255 : startVeh->getID(), cCap, transportable->getID(), time2string(SIMSTEP)));
256 : }
257 : }
258 1458 : myDeparted = now;
259 1458 : setVehicle(startVeh);
260 1458 : if (myOriginStop != nullptr) {
261 0 : myOriginStop->removeTransportable(transportable);
262 : }
263 1458 : myWaitingEdge = previous->getEdge();
264 1458 : myStopWaitPos = Position::INVALID;
265 1458 : myWaitingPos = previous->getEdgePos(now);
266 1458 : myVehicle->addTransportable(transportable);
267 : return;
268 : }
269 77170 : if (myOriginStop != nullptr) {
270 : // the arrival stop may have an access point
271 23379 : myWaitingEdge = &myOriginStop->getLane().getEdge();
272 23379 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
273 23379 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
274 : } else {
275 53791 : myWaitingEdge = previous->getEdge();
276 53791 : myStopWaitPos = Position::INVALID;
277 53791 : myWaitingPos = previous->getEdgePos(now);
278 : }
279 51824 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
280 77193 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
281 : // transfer at junction (rather than access)
282 15 : myWaitingEdge = myOrigin;
283 15 : myWaitingPos = 0;
284 : }
285 77170 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
286 77170 : const bool triggered = availableVehicle != nullptr &&
287 4470 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
288 311 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
289 2034 : if (triggered && !availableVehicle->hasDeparted()) {
290 2006 : setVehicle(availableVehicle);
291 2006 : if (myOriginStop != nullptr) {
292 0 : myOriginStop->removeTransportable(transportable);
293 : }
294 2006 : myVehicle->addTransportable(transportable);
295 2006 : net->getInsertionControl().add(myVehicle);
296 2006 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
297 : } else {
298 75164 : registerWaiting(transportable, now);
299 : }
300 : }
301 :
302 :
303 : void
304 75171 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
305 : // check if the ride can be conducted and reserve it
306 75171 : if (MSDevice_Taxi::isReservation(getLines())) {
307 2384 : const MSEdge* to = getDestination();
308 2384 : double toPos = getArrivalPos();
309 2384 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
310 : // try to find usable access edge
311 6 : for (const auto& access : getDestinationStop()->getAllAccessPos()) {
312 6 : const MSEdge* accessEdge = &access.lane->getEdge();
313 6 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
314 : to = accessEdge;
315 6 : toPos = access.endPos;
316 6 : break;
317 : }
318 : }
319 : }
320 2384 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
321 : // try to find usable access edge
322 11 : for (const auto& access : myOriginStop->getAllAccessPos()) {
323 11 : const MSEdge* accessEdge = &access.lane->getEdge();
324 11 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
325 11 : myWaitingEdge = accessEdge;
326 11 : myStopWaitPos = Position::INVALID;
327 11 : myWaitingPos = access.endPos;
328 11 : break;
329 : }
330 : }
331 : }
332 : // Create reservation only if not already created by previous reservationTime
333 2384 : if (myReservationCommand == nullptr) {
334 2222 : MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
335 : } else {
336 : // update "fromPos" with current (new) value of myWaitingPos
337 162 : MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationCommand->myWaitingPos, to, toPos, myGroup, myWaitingPos);
338 : }
339 : }
340 75171 : if (transportable->isPerson()) {
341 20880 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
342 : } else {
343 54291 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
344 : }
345 75171 : myWaitingEdge->addTransportable(transportable);
346 75171 : }
347 :
348 : SUMOTime
349 6361 : MSStageDriving::getDuration() const {
350 6361 : return myArrived >= 0 ? myArrived - myWaitingSince : SUMOTime_MAX;
351 : }
352 :
353 :
354 : SUMOTime
355 6361 : MSStageDriving::getTravelTime() const {
356 6361 : return myArrived >= 0 ? myArrived - myDeparted : SUMOTime_MAX;
357 : }
358 :
359 :
360 : SUMOTime
361 12722 : MSStageDriving::getWaitingTime() const {
362 12722 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
363 12722 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
364 : }
365 :
366 :
367 : SUMOTime
368 12455 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
369 12455 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
370 : }
371 :
372 : void
373 6361 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
374 6361 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
375 6361 : const SUMOTime waitingTime = getWaitingTime();
376 6361 : const SUMOTime duration = myArrived - myDeparted;
377 6361 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
378 6996 : os.openTag(transportable->isPerson() ? "ride" : "transport");
379 12722 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
380 6361 : os.writeAttr("vehicle", myVehicleID);
381 12722 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
382 12722 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
383 12722 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
384 12989 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
385 267 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
386 12722 : os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
387 12722 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
388 6361 : os.closeTag();
389 6361 : }
390 :
391 :
392 : void
393 1273 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
394 1357 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
395 1273 : if (getFromEdge() != nullptr) {
396 1265 : os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
397 8 : } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
398 8 : os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
399 : }
400 1273 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
401 1273 : std::string comment = "";
402 1273 : if (myDestinationStop != nullptr) {
403 539 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
404 539 : if (myDestinationStop->getMyName() != "") {
405 132 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
406 : }
407 734 : } else if (!unspecifiedArrivalPos()) {
408 703 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
409 : }
410 1273 : os.writeAttr(SUMO_ATTR_LINES, myLines);
411 1273 : if (myIntendedVehicleID != "") {
412 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
413 : }
414 1273 : if (myIntendedDepart >= 0) {
415 482 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
416 : }
417 1273 : if (withRouteLength) {
418 24 : os.writeAttr("routeLength", myVehicleDistance);
419 : }
420 2546 : if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
421 54 : os.writeAttr("vehicle", myVehicleID);
422 54 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
423 108 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
424 : }
425 2546 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
426 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
427 : }
428 1273 : os.closeTag(comment);
429 1273 : }
430 :
431 :
432 : bool
433 369250 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
434 : assert(myLines.size() > 0);
435 : return (myLines.count(vehicle->getID()) > 0
436 350676 : || ((myLines.count(vehicle->getParameter().line) > 0
437 562445 : || myLines.count("ANY") > 0) &&
438 : // even if the line matches we still have to check for stops (#14526)
439 297579 : (myDestinationStop == nullptr
440 297579 : ? vehicle->stopsAtEdge(myDestination)
441 112744 : : vehicle->stopsAt(myDestinationStop)))
442 795056 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
443 : }
444 :
445 :
446 : bool
447 2997219 : MSStageDriving::isWaiting4Vehicle() const {
448 2997219 : return myVehicle == nullptr && myArrived < 0;
449 : }
450 :
451 :
452 : SUMOTime
453 0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
454 0 : return isWaiting4Vehicle() ? now - myWaitingSince : 0;
455 : }
456 :
457 :
458 : double
459 80726 : MSStageDriving::getSpeed() const {
460 80726 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
461 : }
462 :
463 :
464 : ConstMSEdgeVector
465 535 : MSStageDriving::getEdges() const {
466 : ConstMSEdgeVector result;
467 535 : result.push_back(getFromEdge());
468 535 : result.push_back(getDestination());
469 535 : return result;
470 0 : }
471 :
472 :
473 : double
474 36992 : MSStageDriving::getArrivalPos() const {
475 36992 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
476 : }
477 :
478 :
479 : bool
480 176582 : MSStageDriving::unspecifiedArrivalPos() const {
481 176582 : return myArrivalPos == std::numeric_limits<double>::infinity();
482 : }
483 :
484 :
485 : const std::string
486 12858 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
487 12858 : MSStage::setArrived(net, transportable, now, vehicleArrived);
488 12858 : if (myVehicle != nullptr) {
489 : // distance was previously set to driven distance upon embarking
490 12780 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
491 12780 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
492 12780 : if (vehicleArrived) {
493 3929 : myArrivalPos = myVehicle->getArrivalPos();
494 : } else {
495 8851 : myArrivalPos = myVehicle->getPositionOnLane();
496 : }
497 : const MSStoppingPlace* const stop = getDestinationStop();
498 12780 : if (stop != nullptr) {
499 : MSStoppingPlace::AccessExit exit = MSStoppingPlace::AccessExit::PLATFORM;
500 6883 : for (const auto& access : stop->getAllAccessPos()) {
501 2570 : if (access.exit != exit) {
502 : exit = access.exit;
503 : break;
504 : }
505 : }
506 4763 : if (exit != MSStoppingPlace::AccessExit::PLATFORM) {
507 450 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
508 450 : if (train != nullptr) {
509 336 : MSTrainHelper trainHelper = MSTrainHelper(train);
510 336 : const MSLane* const lane = myVehicle->getLane();
511 672 : if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
512 336 : trainHelper.computeDoorPositions();
513 : const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
514 336 : const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
515 336 : const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
516 336 : const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
517 336 : Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
518 : // Jitter the position before projection because of possible train curvature.
519 : Position direction = randomCarriage->front - randomCarriage->back;
520 336 : direction.norm2D();
521 336 : randomDoor.add(direction * RandHelper::rand(-0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH, 0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH));
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 78 : myVehicleDistance = -1.;
545 78 : myTimeLoss = -1;
546 : }
547 12858 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
548 12858 : return "";
549 : }
550 :
551 :
552 : void
553 12925 : MSStageDriving::setVehicle(SUMOVehicle* v) {
554 12925 : myVehicle = v;
555 12925 : if (myVehicle != nullptr) {
556 12915 : myVehicleID = v->getID();
557 12915 : myVehicleLine = v->getParameter().line;
558 12915 : myVehicleType = v->getVehicleType().getID();
559 12915 : myVehicleVClass = v->getVClass();
560 12915 : if (myVehicle->hasDeparted()) {
561 10012 : myVehicleDistance = myVehicle->getOdometer();
562 10012 : myTimeLoss = myVehicle->getTimeLoss();
563 : } else {
564 : // it probably got triggered by the person
565 2903 : myVehicleDistance = 0.;
566 2903 : myTimeLoss = 0;
567 : }
568 : }
569 12925 : }
570 :
571 :
572 : void
573 91 : MSStageDriving::abort(MSTransportable* t) {
574 91 : myDestinationStop = nullptr;
575 91 : if (myVehicle != nullptr) {
576 : // jumping out of a moving vehicle!
577 13 : myVehicle->removeTransportable(t);
578 23 : myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
579 : // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
580 : } else {
581 78 : MSTransportableControl& tc = (t->isPerson() ?
582 78 : MSNet::getInstance()->getPersonControl() :
583 0 : MSNet::getInstance()->getContainerControl());
584 78 : tc.abortWaitingForVehicle(t);
585 78 : MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
586 78 : myDestination = myWaitingEdge;
587 78 : myDestinationStop = myOriginStop;
588 : }
589 91 : }
590 :
591 :
592 : std::string
593 605 : MSStageDriving::getWaitingDescription() const {
594 1815 : return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
595 605 : + " at " + (myOriginStop == nullptr
596 1210 : ? ("edge '" + myWaitingEdge->getID() + "'")
597 1689 : : (toString(myOriginStop->getElement()) + " '" + myOriginStop->getID() + "'"))
598 1210 : ) : "";
599 : }
600 :
601 :
602 : bool
603 76558 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
604 76558 : const MSEdge* stopEdge = stop.getEdge();
605 : bool canLeave = false;
606 76558 : if (t->getDestination() == stopEdge) {
607 : // if this is the last stage, we can use the arrivalPos of the person
608 69428 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
609 46984 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
610 69428 : const double arrivalPos = (unspecifiedArrivalPos()
611 69428 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
612 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
613 18915 : : getArrivalPos());
614 69428 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
615 : canLeave = true;
616 : }
617 : }
618 76558 : if (myDestinationStop != nullptr) {
619 16640 : if (!canLeave) {
620 : // check with more tolerance due to busStop size and also check
621 : // access edges
622 1777 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
623 1777 : if (accessPos >= 0) {
624 523 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
625 523 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
626 : // accessPos is in the middle of the stop
627 275 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
628 : }
629 523 : canLeave = stop.isInRange(accessPos, tolerance);
630 : }
631 : }
632 : }
633 76558 : return canLeave;
634 : }
635 :
636 :
637 : void
638 16 : MSStageDriving::saveState(std::ostringstream& out) {
639 16 : const bool hasVehicle = myVehicle != nullptr;
640 48 : out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
641 16 : if (hasVehicle) {
642 27 : out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
643 : }
644 16 : }
645 :
646 :
647 : void
648 16 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
649 : bool hasVehicle;
650 16 : state >> myWaitingSince >> myTimeLoss >> myArrived >> hasVehicle;
651 16 : if (hasVehicle) {
652 : std::string vehID;
653 9 : state >> myDeparted >> vehID;
654 9 : SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
655 9 : setVehicle(startVeh);
656 9 : myVehicle->addTransportable(transportable);
657 9 : state >> myVehicleDistance;
658 : } else {
659 : // there should always be at least one prior WAITING_FOR_DEPART stage
660 : MSStage* previous = transportable->getNextStage(-1);
661 7 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
662 7 : ? previous->getOriginStop()
663 : : previous->getDestinationStop());
664 7 : if (myOriginStop != nullptr) {
665 : // the arrival stop may have an access point
666 2 : myOriginStop->addTransportable(transportable);
667 2 : myWaitingEdge = &myOriginStop->getLane().getEdge();
668 2 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
669 2 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
670 : } else {
671 5 : myWaitingEdge = previous->getEdge();
672 5 : myStopWaitPos = Position::INVALID;
673 5 : myWaitingPos = previous->getArrivalPos();
674 : }
675 7 : registerWaiting(transportable, SIMSTEP);
676 : }
677 16 : }
678 :
679 : // ---------------------------------------------------------------------------
680 : // MSStageDriving::BookReservation method definitions
681 : // ---------------------------------------------------------------------------
682 : SUMOTime
683 162 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
684 486 : MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
685 162 : myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
686 : // do not repeat if execution fails
687 162 : return 0;
688 : }
689 :
690 : /****************************************************************************/
|