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 44214 : 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 44214 : const std::string& intendedVeh, SUMOTime intendedDepart) :
57 : MSStage(MSStageType::DRIVING, destination, toStop, arrivalPos, arrivalPosLat, group),
58 44214 : myOrigin(origin),
59 44214 : myLines(lines.begin(), lines.end()),
60 44214 : myVehicle(nullptr),
61 44214 : myVehicleID("NULL"),
62 44214 : myVehicleVClass(SVC_IGNORING),
63 44214 : myVehicleDistance(-1.),
64 44214 : myTimeLoss(-1),
65 44214 : myWaitingPos(-1),
66 44214 : myWaitingSince(-1),
67 44214 : myWaitingEdge(nullptr),
68 44214 : myStopWaitPos(Position::INVALID),
69 44214 : myOriginStop(nullptr),
70 44214 : myIntendedVehicleID(intendedVeh),
71 44214 : myIntendedDepart(intendedDepart),
72 44214 : myReservationCommand(nullptr) {
73 44214 : }
74 :
75 :
76 : MSStage*
77 32779 : MSStageDriving::clone() const {
78 32779 : MSStage* const clon = new MSStageDriving(myOrigin, myDestination, myDestinationStop, myArrivalPos, myArrivalPosLat,
79 65558 : std::vector<std::string>(myLines.begin(), myLines.end()),
80 32779 : myGroup, myIntendedVehicleID, myIntendedDepart);
81 32779 : clon->setParameters(*this);
82 32779 : return clon;
83 : }
84 :
85 :
86 132627 : MSStageDriving::~MSStageDriving() {}
87 :
88 :
89 : void
90 39069 : MSStageDriving::init(MSTransportable* transportable) {
91 78138 : if (hasParameter("earliestPickupTime")) {
92 78 : SUMOTime reservationTime = MSNet::getInstance()->getCurrentTimeStep();
93 156 : if (hasParameter("reservationTime")) {
94 144 : reservationTime = string2time(getParameter("reservationTime"));
95 : }
96 234 : SUMOTime earliestPickupTime = string2time(getParameter("earliestPickupTime"));
97 78 : if (transportable->getNextStage(1) == this) {
98 : // if the ride is the first stage use the departPos (there is a unvisible stop before)
99 60 : 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 78 : myReservationCommand = new BookReservation(transportable, earliestPickupTime, this);
105 78 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myReservationCommand, reservationTime);
106 : }
107 :
108 :
109 39069 : }
110 :
111 :
112 : const MSEdge*
113 108388 : MSStageDriving::getEdge() const {
114 108388 : if (myVehicle != nullptr) {
115 92220 : if (myVehicle->getLane() != nullptr) {
116 80014 : return &myVehicle->getLane()->getEdge();
117 : }
118 12206 : return myVehicle->getEdge();
119 16168 : } else if (myArrived >= 0) {
120 15866 : return myDestination;
121 : } else {
122 302 : return myWaitingEdge;
123 : }
124 : }
125 :
126 :
127 : const MSEdge*
128 3092 : MSStageDriving::getFromEdge() const {
129 3092 : return myWaitingEdge;
130 : }
131 :
132 :
133 : double
134 332051 : MSStageDriving::getEdgePos(SUMOTime /* now */) const {
135 332051 : if (isWaiting4Vehicle()) {
136 240429 : return myWaitingPos;
137 91622 : } else if (myArrived >= 0) {
138 3074 : return myArrivalPos;
139 : } else {
140 : // vehicle may already have passed the lane (check whether this is correct)
141 88548 : return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
142 : }
143 : }
144 :
145 : int
146 60 : MSStageDriving::getDirection() const {
147 60 : if (isWaiting4Vehicle()) {
148 0 : return MSPModel::UNDEFINED_DIRECTION;
149 60 : } else if (myArrived >= 0) {
150 0 : return MSPModel::UNDEFINED_DIRECTION;
151 : } else {
152 60 : return MSPModel::FORWARD;
153 : }
154 : }
155 :
156 : const MSLane*
157 76 : MSStageDriving::getLane() const {
158 76 : return myVehicle != nullptr ? myVehicle->getLane() : nullptr;
159 : }
160 :
161 :
162 : Position
163 404634 : MSStageDriving::getPosition(SUMOTime /* now */) const {
164 404634 : if (isWaiting4Vehicle()) {
165 : if (myStopWaitPos != Position::INVALID) {
166 140687 : return myStopWaitPos;
167 : }
168 214207 : return getEdgePosition(myWaitingEdge, myWaitingPos,
169 428414 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
170 49740 : } else if (myArrived >= 0) {
171 0 : return getEdgePosition(myDestination, myArrivalPos,
172 0 : ROADSIDE_OFFSET * (MSGlobals::gLefthand ? -1 : 1));
173 : } else {
174 49740 : return myVehicle->getPosition();
175 : }
176 : }
177 :
178 :
179 : double
180 405799 : MSStageDriving::getAngle(SUMOTime /* now */) const {
181 405799 : if (isWaiting4Vehicle()) {
182 710332 : return getEdgeAngle(myWaitingEdge, myWaitingPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
183 50625 : } else if (myArrived >= 0) {
184 0 : return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2. * (MSGlobals::gLefthand ? -1 : 1);
185 : } else {
186 50625 : MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
187 50625 : if (veh != nullptr) {
188 45020 : return veh->getAngle();
189 : } else {
190 : return 0;
191 : }
192 : }
193 : }
194 :
195 :
196 : double
197 7122 : MSStageDriving::getDistance() const {
198 7122 : if (myVehicle != nullptr) {
199 : // distance was previously set to driven distance upon embarking
200 487 : return myVehicle->getOdometer() - myVehicleDistance;
201 : }
202 6635 : return myVehicleDistance;
203 : }
204 :
205 :
206 : std::string
207 1723 : MSStageDriving::getStageDescription(const bool isPerson) const {
208 2677 : return isWaiting4Vehicle() ? "waiting for " + joinToString(myLines, ",") : (isPerson ? "driving" : "transport");
209 : }
210 :
211 :
212 : std::string
213 0 : MSStageDriving::getStageSummary(const bool isPerson) const {
214 : const std::string dest = (getDestinationStop() == nullptr ?
215 0 : " edge '" + getDestination()->getID() + "'" :
216 0 : " stop '" + getDestinationStop()->getID() + "'" + (
217 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
218 0 : const std::string intended = myIntendedVehicleID != "" ?
219 0 : " (vehicle " + myIntendedVehicleID + " at time=" + time2string(myIntendedDepart) + ")" :
220 0 : "";
221 0 : const std::string modeName = isPerson ? "driving" : "transported";
222 0 : return isWaiting4Vehicle() ?
223 0 : "waiting for " + joinToString(myLines, ",") + intended + " then " + modeName + " to " + dest :
224 0 : modeName + " to " + dest;
225 : }
226 :
227 :
228 : void
229 43876 : MSStageDriving::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, MSStage* previous) {
230 43876 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
231 43876 : ? previous->getOriginStop()
232 : : previous->getDestinationStop());
233 43876 : myWaitingSince = now;
234 43876 : const bool isPerson = transportable->isPerson();
235 43876 : if (transportable->getParameter().departProcedure == DepartDefinition::TRIGGERED
236 43876 : && transportable->getCurrentStageIndex() == 1) {
237 : // we are the first real stage (stage 0 is WAITING_FOR_DEPART)
238 : const std::string vehID = *myLines.begin();
239 1927 : SUMOVehicle* startVeh = net->getVehicleControl().getVehicle(vehID);
240 1927 : if (startVeh == nullptr && net->hasFlow(vehID)) {
241 408 : startVeh = net->getInsertionControl().getLastFlowVehicle(vehID);
242 : }
243 1927 : if (startVeh == nullptr) {
244 0 : throw ProcessError("Vehicle '" + vehID + "' not found for triggered departure of " +
245 0 : (isPerson ? "person" : "container") + " '" + transportable->getID() + "'.");
246 : }
247 1927 : myDeparted = now;
248 1927 : setVehicle(startVeh);
249 1927 : if (myOriginStop != nullptr) {
250 0 : myOriginStop->removeTransportable(transportable);
251 : }
252 1927 : myWaitingEdge = previous->getEdge();
253 1927 : myStopWaitPos = Position::INVALID;
254 1927 : myWaitingPos = previous->getEdgePos(now);
255 1927 : myVehicle->addTransportable(transportable);
256 : return;
257 : }
258 41949 : if (myOriginStop != nullptr) {
259 : // the arrival stop may have an access point
260 6520 : myWaitingEdge = &myOriginStop->getLane().getEdge();
261 6520 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
262 6520 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
263 : } else {
264 35429 : myWaitingEdge = previous->getEdge();
265 35429 : myStopWaitPos = Position::INVALID;
266 35429 : myWaitingPos = previous->getEdgePos(now);
267 : }
268 33912 : if (myOrigin != nullptr && myOrigin != myWaitingEdge
269 41972 : && (myOriginStop == nullptr || myOriginStop->getAccessPos(myOrigin) < 0)) {
270 : // transfer at junction (rather than access)
271 15 : myWaitingEdge = myOrigin;
272 15 : myWaitingPos = 0;
273 : }
274 41949 : SUMOVehicle* const availableVehicle = myWaitingEdge->getWaitingVehicle(transportable, myWaitingPos);
275 41949 : const bool triggered = availableVehicle != nullptr &&
276 4511 : ((isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED) ||
277 267 : (!isPerson && availableVehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED));
278 2018 : if (triggered && !availableVehicle->hasDeparted()) {
279 1990 : setVehicle(availableVehicle);
280 1990 : if (myOriginStop != nullptr) {
281 0 : myOriginStop->removeTransportable(transportable);
282 : }
283 1990 : myVehicle->addTransportable(transportable);
284 1990 : net->getInsertionControl().add(myVehicle);
285 1990 : net->getVehicleControl().handleTriggeredDepart(myVehicle, false);
286 : } else {
287 39959 : registerWaiting(transportable, now);
288 : }
289 : }
290 :
291 :
292 : void
293 39969 : MSStageDriving::registerWaiting(MSTransportable* transportable, SUMOTime now) {
294 : // check if the ride can be conducted and reserve it
295 39969 : if (MSDevice_Taxi::isReservation(getLines())) {
296 2964 : const MSEdge* to = getDestination();
297 2964 : double toPos = getArrivalPos();
298 2964 : if ((to->getPermissions() & SVC_TAXI) == 0 && getDestinationStop() != nullptr) {
299 : // try to find usable access edge
300 6 : for (const auto& access : getDestinationStop()->getAllAccessPos()) {
301 6 : const MSEdge* accessEdge = &access.lane->getEdge();
302 6 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
303 : to = accessEdge;
304 6 : toPos = access.endPos;
305 6 : break;
306 : }
307 : }
308 : }
309 2964 : if ((myWaitingEdge->getPermissions() & SVC_TAXI) == 0 && myOriginStop != nullptr) {
310 : // try to find usable access edge
311 11 : for (const auto& access : myOriginStop->getAllAccessPos()) {
312 11 : const MSEdge* accessEdge = &access.lane->getEdge();
313 11 : if ((accessEdge->getPermissions() & SVC_TAXI) != 0) {
314 11 : myWaitingEdge = accessEdge;
315 11 : myStopWaitPos = Position::INVALID;
316 11 : myWaitingPos = access.endPos;
317 11 : break;
318 : }
319 : }
320 : }
321 : // Create reservation only if not already created by previous reservationTime
322 2964 : if (myReservationCommand == nullptr) {
323 2886 : MSDevice_Taxi::addReservation(transportable, getLines(), now, now, -1, myWaitingEdge, myWaitingPos, myOriginStop, to, toPos, myDestinationStop, myGroup);
324 : } else {
325 : // update "fromPos" with current (new) value of myWaitingPos
326 78 : MSDevice_Taxi::updateReservationFromPos(transportable, getLines(), myWaitingEdge, myReservationCommand->myWaitingPos, to, toPos, myGroup, myWaitingPos);
327 : }
328 : }
329 39969 : if (transportable->isPerson()) {
330 14204 : MSNet::getInstance()->getPersonControl().addWaiting(myWaitingEdge, transportable);
331 : } else {
332 25765 : MSNet::getInstance()->getContainerControl().addWaiting(myWaitingEdge, transportable);
333 : }
334 39969 : myWaitingEdge->addTransportable(transportable);
335 39969 : }
336 :
337 :
338 : SUMOTime
339 13612 : MSStageDriving::getWaitingTime() const {
340 13612 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : SIMSTEP;
341 13612 : return myWaitingSince >= 0 ? departed - myWaitingSince : SUMOTime_MAX;
342 : }
343 :
344 :
345 : SUMOTime
346 13372 : MSStageDriving::getTimeLoss(const MSTransportable* /*transportable*/) const {
347 13372 : return myArrived >= 0 ? myTimeLoss : SUMOTime_MAX;
348 : }
349 :
350 : void
351 6806 : MSStageDriving::tripInfoOutput(OutputDevice& os, const MSTransportable* const transportable) const {
352 6806 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
353 : const SUMOTime departed = myDeparted >= 0 ? myDeparted : now;
354 6806 : const SUMOTime waitingTime = getWaitingTime();
355 6806 : const SUMOTime duration = myArrived - myDeparted;
356 6806 : MSDevice_Tripinfo::addRideTransportData(transportable->isPerson(), myVehicleDistance, duration, myVehicleVClass, myVehicleLine, waitingTime);
357 7293 : os.openTag(transportable->isPerson() ? "ride" : "transport");
358 13612 : os.writeAttr("waitingTime", waitingTime != SUMOTime_MAX ? time2string(waitingTime) : "-1");
359 6806 : os.writeAttr("vehicle", myVehicleID);
360 13612 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
361 13612 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
362 13612 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(getArrivalPos()) : "-1");
363 13852 : os.writeAttr("duration", myArrived >= 0 ? time2string(duration) :
364 240 : (myDeparted >= 0 ? time2string(now - myDeparted) : "-1"));
365 13612 : os.writeAttr("routeLength", myArrived >= 0 || myVehicle != nullptr ? toString(getDistance()) : "-1");
366 13612 : os.writeAttr("timeLoss", myArrived >= 0 ? time2string(getTimeLoss(transportable)) : "-1");
367 6806 : os.closeTag();
368 6806 : }
369 :
370 :
371 : void
372 1271 : MSStageDriving::routeOutput(const bool isPerson, OutputDevice& os, const bool withRouteLength, const MSStage* const previous) const {
373 1339 : os.openTag(isPerson ? SUMO_TAG_RIDE : SUMO_TAG_TRANSPORT);
374 1271 : if (getFromEdge() != nullptr) {
375 1259 : os.writeAttr(SUMO_ATTR_FROM, getFromEdge()->getID());
376 12 : } else if (previous != nullptr && previous->getStageType() == MSStageType::WAITING_FOR_DEPART) {
377 12 : os.writeAttr(SUMO_ATTR_FROM, previous->getEdge()->getID());
378 : }
379 1271 : os.writeAttr(SUMO_ATTR_TO, getDestination()->getID());
380 1271 : std::string comment = "";
381 1271 : if (myDestinationStop != nullptr) {
382 494 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
383 988 : if (myDestinationStop->getMyName() != "") {
384 72 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
385 : }
386 777 : } else if (!unspecifiedArrivalPos()) {
387 739 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
388 : }
389 1271 : os.writeAttr(SUMO_ATTR_LINES, myLines);
390 1271 : if (myIntendedVehicleID != "") {
391 : os.writeAttr(SUMO_ATTR_INTENDED, myIntendedVehicleID);
392 : }
393 1271 : if (myIntendedDepart >= 0) {
394 466 : os.writeAttr(SUMO_ATTR_DEPART, time2string(myIntendedDepart));
395 : }
396 1271 : if (withRouteLength) {
397 24 : os.writeAttr("routeLength", myVehicleDistance);
398 : }
399 2542 : if (OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
400 54 : os.writeAttr("vehicle", myVehicleID);
401 54 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
402 108 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
403 : }
404 2542 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
405 0 : os.writeAttr(SUMO_ATTR_COST, getCosts());
406 : }
407 1271 : os.closeTag(comment);
408 1271 : }
409 :
410 :
411 : bool
412 314275 : MSStageDriving::isWaitingFor(const SUMOVehicle* vehicle) const {
413 : assert(myLines.size() > 0);
414 : return (myLines.count(vehicle->getID()) > 0
415 295898 : || ((myLines.count(vehicle->getParameter().line) > 0
416 508516 : || myLines.count("ANY") > 0) &&
417 : // even if the line matches we still have to check for stops (#14526)
418 241691 : (myDestinationStop == nullptr
419 241691 : ? vehicle->stopsAtEdge(myDestination)
420 42839 : : vehicle->stopsAt(myDestinationStop)))
421 611829 : || MSDevice_Taxi::compatibleLine(vehicle->getParameter().line, *myLines.begin()));
422 : }
423 :
424 :
425 : bool
426 3004704 : MSStageDriving::isWaiting4Vehicle() const {
427 3004704 : return myVehicle == nullptr && myArrived < 0;
428 : }
429 :
430 :
431 : SUMOTime
432 0 : MSStageDriving::getWaitingTime(SUMOTime now) const {
433 0 : return isWaiting4Vehicle() ? now - myWaitingSince : 0;
434 : }
435 :
436 :
437 : double
438 76319 : MSStageDriving::getSpeed() const {
439 76319 : return myVehicle == nullptr ? 0 : myVehicle->getSpeed();
440 : }
441 :
442 :
443 : ConstMSEdgeVector
444 562 : MSStageDriving::getEdges() const {
445 : ConstMSEdgeVector result;
446 562 : result.push_back(getFromEdge());
447 562 : result.push_back(getDestination());
448 562 : return result;
449 : }
450 :
451 :
452 : double
453 35169 : MSStageDriving::getArrivalPos() const {
454 35169 : return unspecifiedArrivalPos() ? getDestination()->getLength() : myArrivalPos;
455 : }
456 :
457 :
458 : bool
459 179490 : MSStageDriving::unspecifiedArrivalPos() const {
460 179490 : return myArrivalPos == std::numeric_limits<double>::infinity();
461 : }
462 :
463 :
464 : const std::string
465 14151 : MSStageDriving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now, const bool vehicleArrived) {
466 14151 : MSStage::setArrived(net, transportable, now, vehicleArrived);
467 14151 : if (myVehicle != nullptr) {
468 : // distance was previously set to driven distance upon embarking
469 14016 : myVehicleDistance = myVehicle->getOdometer() - myVehicleDistance;
470 14016 : myTimeLoss = myVehicle->getTimeLoss() - myTimeLoss;
471 14016 : if (vehicleArrived) {
472 3723 : myArrivalPos = myVehicle->getArrivalPos();
473 : } else {
474 10293 : myArrivalPos = myVehicle->getPositionOnLane();
475 : }
476 : const MSStoppingPlace* const stop = getDestinationStop();
477 14016 : if (stop != nullptr) {
478 : bool useDoors = false;
479 7746 : for (const auto& access : stop->getAllAccessPos()) {
480 3271 : if (access.useDoors) {
481 : useDoors = true;
482 : break;
483 : }
484 : }
485 4925 : if (useDoors) {
486 450 : MSVehicle* train = dynamic_cast<MSVehicle*>(myVehicle);
487 450 : if (train != nullptr) {
488 336 : MSTrainHelper trainHelper = MSTrainHelper(train);
489 336 : const MSLane* const lane = myVehicle->getLane();
490 1008 : if (OptionsCont::getOptions().getString("pedestrian.model") != "jupedsim") {
491 336 : trainHelper.computeDoorPositions();
492 : const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
493 336 : const int randomCarriageIx = RandHelper::rand(trainHelper.getNumCarriages() - trainHelper.getFirstPassengerCarriage()) + trainHelper.getFirstPassengerCarriage();
494 336 : const MSTrainHelper::Carriage* randomCarriage = carriages[randomCarriageIx];
495 336 : const int randomDoorIx = RandHelper::rand(trainHelper.getCarriageDoors());
496 336 : Position randomDoor = randomCarriage->doorPositions[randomDoorIx];
497 : // Jitter the position before projection because of possible train curvature.
498 : Position direction = randomCarriage->front - randomCarriage->back;
499 336 : direction.norm2D();
500 336 : randomDoor.add(direction * RandHelper::rand(-0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH, 0.5 * MSTrainHelper::CARRIAGE_DOOR_WIDTH));
501 : // Project onto the lane.
502 336 : myArrivalPos = lane->getShape().nearest_offset_to_point2D(randomDoor);
503 336 : myArrivalPos = lane->interpolateGeometryPosToLanePos(myArrivalPos);
504 672 : myArrivalPos = MIN2(MAX2(0., myArrivalPos), myVehicle->getEdge()->getLength());
505 : } else {
506 0 : std::vector<Position>& unboardingPositions = static_cast<MSDevice_Transportable*>(train->getDevice(typeid(MSDevice_Transportable)))->getUnboardingPositions();
507 0 : if (unboardingPositions.empty()) {
508 0 : const MSVehicleType* defaultPedestrianType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
509 0 : const double defaultPassengerRadius = MAX2(defaultPedestrianType->getLength(), defaultPedestrianType->getWidth()) / 2.;
510 0 : trainHelper.computeUnboardingPositions(defaultPassengerRadius, unboardingPositions);
511 : }
512 : // Random shuffling of the positions has already been done in the train helper.
513 0 : const Position availableUnboardingPosition = unboardingPositions.back();
514 : unboardingPositions.pop_back();
515 0 : const Position arrivalPos = lane->getShape().transformToVectorCoordinates(availableUnboardingPosition);
516 0 : myArrivalPos = arrivalPos.x();
517 0 : myArrivalPosLat = arrivalPos.y();
518 : }
519 336 : }
520 : }
521 : }
522 : } else {
523 135 : myVehicleDistance = -1.;
524 135 : myTimeLoss = -1;
525 : }
526 14151 : myVehicle = nullptr; // avoid dangling pointer after vehicle arrival
527 14151 : return "";
528 : }
529 :
530 :
531 : void
532 14171 : MSStageDriving::setVehicle(SUMOVehicle* v) {
533 14171 : myVehicle = v;
534 14171 : if (myVehicle != nullptr) {
535 14161 : myVehicleID = v->getID();
536 14161 : myVehicleLine = v->getParameter().line;
537 14161 : myVehicleType = v->getVehicleType().getID();
538 14161 : myVehicleVClass = v->getVClass();
539 14161 : if (myVehicle->hasDeparted()) {
540 10644 : myVehicleDistance = myVehicle->getOdometer();
541 10644 : myTimeLoss = myVehicle->getTimeLoss();
542 : } else {
543 : // it probably got triggered by the person
544 3517 : myVehicleDistance = 0.;
545 3517 : myTimeLoss = 0;
546 : }
547 : }
548 14171 : }
549 :
550 : void
551 152 : MSStageDriving::abort(MSTransportable* t) {
552 152 : myDestinationStop = nullptr;
553 152 : if (myVehicle != nullptr) {
554 : // jumping out of a moving vehicle!
555 17 : myVehicle->removeTransportable(t);
556 31 : myDestination = myVehicle->getLane() == nullptr ? myVehicle->getEdge() : &myVehicle->getLane()->getEdge();
557 : // myVehicleDistance and myTimeLoss are updated in subsequent call to setArrived
558 : } else {
559 135 : MSTransportableControl& tc = (t->isPerson() ?
560 135 : MSNet::getInstance()->getPersonControl() :
561 0 : MSNet::getInstance()->getContainerControl());
562 135 : tc.abortWaitingForVehicle(t);
563 135 : MSDevice_Taxi::removeReservation(t, getLines(), myWaitingEdge, myWaitingPos, myDestination, getArrivalPos(), myGroup);
564 135 : myDestination = myWaitingEdge;
565 : }
566 152 : }
567 :
568 :
569 : std::string
570 29333 : MSStageDriving::getWaitingDescription() const {
571 87999 : return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
572 58666 : + " at " + (myDestinationStop == nullptr
573 62371 : ? ("edge '" + myWaitingEdge->getID() + "'")
574 36743 : : ("busStop '" + myDestinationStop->getID() + "'"))
575 87999 : ) : "";
576 : }
577 :
578 :
579 : bool
580 83816 : MSStageDriving::canLeaveVehicle(const MSTransportable* t, const SUMOVehicle& veh, const MSStop& stop) {
581 83816 : const MSEdge* stopEdge = stop.getEdge();
582 : bool canLeave = false;
583 83816 : if (t->getDestination() == stopEdge) {
584 : // if this is the last stage, we can use the arrivalPos of the person
585 71772 : const bool unspecifiedAP = unspecifiedArrivalPos() && (
586 53787 : t->getNumRemainingStages() > 1 || !t->getParameter().wasSet(VEHPARS_ARRIVALPOS_SET));
587 71772 : const double arrivalPos = (unspecifiedArrivalPos()
588 71772 : ? SUMOVehicleParameter::interpretEdgePos(t->getParameter().arrivalPos, stopEdge->getLength(),
589 : SUMO_ATTR_ARRIVALPOS, t->getID(), true)
590 13812 : : getArrivalPos());
591 71772 : if (unspecifiedAP || stop.isInRange(arrivalPos, veh.getLength() + MSGlobals::gStopTolerance)) {
592 : canLeave = true;
593 : }
594 : }
595 83816 : if (myDestinationStop != nullptr) {
596 12352 : if (!canLeave) {
597 : // check with more tolerance due to busStop size and also check
598 : // access edges
599 2018 : const double accessPos = myDestinationStop->getAccessPos(veh.getEdge());
600 2018 : if (accessPos >= 0) {
601 418 : double tolerance = veh.getLength() + MSGlobals::gStopTolerance;
602 418 : if (&myDestinationStop->getLane().getEdge() == veh.getEdge()) {
603 : // accessPos is in the middle of the stop
604 170 : tolerance += (myDestinationStop->getEndLanePosition() - myDestinationStop->getBeginLanePosition()) / 2;
605 : }
606 418 : canLeave = stop.isInRange(accessPos, tolerance);
607 : }
608 : }
609 : }
610 83816 : return canLeave;
611 : }
612 :
613 :
614 : void
615 24 : MSStageDriving::saveState(std::ostringstream& out) {
616 24 : const bool hasVehicle = myVehicle != nullptr;
617 96 : out << " " << myWaitingSince << " " << myTimeLoss << " " << myArrived << " " << hasVehicle;
618 24 : if (hasVehicle) {
619 42 : out << " " << myDeparted << " " << myVehicle->getID() << " " << myVehicleDistance;
620 : }
621 24 : }
622 :
623 :
624 : void
625 24 : MSStageDriving::loadState(MSTransportable* transportable, std::istringstream& state) {
626 : bool hasVehicle;
627 24 : state >> myWaitingSince >> myTimeLoss >> myArrived >> hasVehicle;
628 24 : if (hasVehicle) {
629 : std::string vehID;
630 14 : state >> myDeparted >> vehID;
631 14 : SUMOVehicle* startVeh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
632 14 : setVehicle(startVeh);
633 14 : myVehicle->addTransportable(transportable);
634 14 : state >> myVehicleDistance;
635 : } else {
636 : // there should always be at least one prior WAITING_FOR_DEPART stage
637 : MSStage* previous = transportable->getNextStage(-1);
638 10 : myOriginStop = (previous->getStageType() == MSStageType::TRIP
639 10 : ? previous->getOriginStop()
640 : : previous->getDestinationStop());
641 10 : if (myOriginStop != nullptr) {
642 : // the arrival stop may have an access point
643 3 : myOriginStop->addTransportable(transportable);
644 3 : myWaitingEdge = &myOriginStop->getLane().getEdge();
645 3 : myStopWaitPos = myOriginStop->getWaitPosition(transportable);
646 3 : myWaitingPos = myOriginStop->getWaitingPositionOnLane(transportable);
647 : } else {
648 7 : myWaitingEdge = previous->getEdge();
649 7 : myStopWaitPos = Position::INVALID;
650 7 : myWaitingPos = previous->getArrivalPos();
651 : }
652 10 : registerWaiting(transportable, SIMSTEP);
653 : }
654 24 : }
655 :
656 : // ---------------------------------------------------------------------------
657 : // MSStageDriving::BookReservation method definitions
658 : // ---------------------------------------------------------------------------
659 : SUMOTime
660 78 : MSStageDriving::BookReservation::execute(SUMOTime currentTime) {
661 234 : MSDevice_Taxi::addReservation(myTransportable, myStage->getLines(), currentTime, currentTime, myEarliestPickupTime,
662 78 : myStage->myOrigin, myStage->myWaitingPos, myStage->myOriginStop, myStage->getDestination(), myStage->getArrivalPos(), myStage->myDestinationStop, myStage->myGroup);
663 : // do not repeat if execution fails
664 78 : return 0;
665 : }
666 :
667 : /****************************************************************************/
|