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 MSTransportable.cpp
15 : /// @author Melanie Weber
16 : /// @author Andreas Kendziorra
17 : /// @author Michael Behrisch
18 : /// @date Thu, 12 Jun 2014
19 : ///
20 : // The common superclass for modelling transportable objects like persons and containers
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 <libsumo/TraCIConstants.h>
30 : #include <microsim/MSEdge.h>
31 : #include <microsim/MSLane.h>
32 : #include <microsim/MSNet.h>
33 : #include <microsim/MSEventControl.h>
34 : #include <microsim/MSStoppingPlace.h>
35 : #include <microsim/MSVehicleControl.h>
36 : #include <microsim/devices/MSTransportableDevice.h>
37 : #include <microsim/transportables/MSTransportableControl.h>
38 : #include <microsim/transportables/MSPerson.h>
39 : #include <microsim/transportables/MSStageDriving.h>
40 : #include <microsim/transportables/MSStageTrip.h>
41 : #include <microsim/transportables/MSStageWaiting.h>
42 : #include <microsim/transportables/MSTransportable.h>
43 :
44 : SUMOTrafficObject::NumericalID MSTransportable::myCurrentNumericalIndex = 0;
45 :
46 : //#define DEBUG_PARKING
47 :
48 : // ===========================================================================
49 : // method definitions
50 : // ===========================================================================
51 513415 : MSTransportable::MSTransportable(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportablePlan* plan, const bool isPerson) :
52 : SUMOTrafficObject(pars->id),
53 513415 : myParameter(pars), myVType(vtype), myPlan(plan),
54 513415 : myAmPerson(isPerson),
55 513415 : myNumericalID(myCurrentNumericalIndex++) {
56 513415 : myStep = myPlan->begin();
57 : // init devices
58 513415 : MSDevice::buildTransportableDevices(*this, myDevices);
59 1593270 : for (MSStage* const stage : * myPlan) {
60 1079855 : stage->init(this);
61 : }
62 513415 : }
63 :
64 :
65 712257 : MSTransportable::~MSTransportable() {
66 513364 : if (myStep != myPlan->end() && getCurrentStageType() == MSStageType::DRIVING) {
67 67152 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(*myStep);
68 67152 : if (stage->getVehicle() != nullptr) {
69 149 : stage->getVehicle()->removeTransportable(this);
70 67003 : } else if (stage->getOriginStop() != nullptr) {
71 18729 : stage->getOriginStop()->removeTransportable(this);
72 : }
73 : }
74 513364 : if (myPlan != nullptr) {
75 1810643 : for (MSTransportablePlan::const_iterator i = myPlan->begin(); i != myPlan->end(); ++i) {
76 1297279 : delete *i;
77 : }
78 513364 : delete myPlan;
79 513364 : myPlan = nullptr;
80 : }
81 515917 : for (MSTransportableDevice* dev : myDevices) {
82 2553 : delete dev;
83 : }
84 513364 : delete myParameter;
85 513364 : if (myVType->isVehicleSpecific()) {
86 179 : MSNet::getInstance()->getVehicleControl().removeVType(myVType);
87 : }
88 712257 : }
89 :
90 : SumoRNG*
91 56 : MSTransportable::getRNG() const {
92 56 : return getEdge()->getLanes()[0]->getRNG();
93 : }
94 :
95 : int
96 2358 : MSTransportable::getRNGIndex() const {
97 2358 : return getEdge()->getLanes()[0]->getRNGIndex();
98 : }
99 :
100 : bool
101 1147627 : MSTransportable::proceed(MSNet* net, SUMOTime time, const bool vehicleArrived) {
102 1147627 : MSStage* const prior = *myStep;
103 1147627 : const std::string& error = prior->setArrived(net, this, time, vehicleArrived);
104 : // must be done before increasing myStep to avoid invalid state for rendering
105 1147627 : prior->getEdge()->removeTransportable(this);
106 : myStep++;
107 1147627 : if (error != "") {
108 47 : throw ProcessError(error);
109 : }
110 : /* We need to check whether an access stage is needed (or maybe even two).
111 : The general scheme is: If the prior stage ended at a stop and the next stage
112 : starts at an edge which is not the one the stop is at, but the stop has an access to it
113 : we need an access stage. The same is true if prior ends at an edge, the next stage
114 : is allowed to start at any stop the edge has access to.
115 : If we start at a stop or end at a stop no access is needed.
116 : */
117 : bool accessToStop = false;
118 1147580 : if (prior->getStageType() == MSStageType::WALKING || prior->getStageType() == MSStageType::DRIVING) {
119 258971 : accessToStop = checkAccess(prior);
120 888609 : } else if (prior->getStageType() == MSStageType::WAITING_FOR_DEPART) {
121 486706 : for (MSTransportableDevice* const dev : myDevices) {
122 2105 : dev->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED, nullptr);
123 : }
124 : }
125 1147580 : if (!accessToStop && (myStep == myPlan->end()
126 752191 : || ((*myStep)->getStageType() != MSStageType::DRIVING
127 671448 : && (*myStep)->getStageType() != MSStageType::TRIP))) {
128 859264 : MSStoppingPlace* priorStop = prior->getStageType() == MSStageType::TRIP ? prior->getOriginStop() : prior->getDestinationStop();
129 : // a trip might resolve to DRIVING so we would have to stay at the stop
130 : // if a trip resolves to something else, this step will do stop removal
131 859264 : if (priorStop != nullptr) {
132 171671 : priorStop->removeTransportable(this);
133 : }
134 : }
135 1147580 : if (myStep != myPlan->end()) {
136 754258 : if ((*myStep)->getStageType() == MSStageType::WALKING && (prior->getStageType() != MSStageType::ACCESS || prior->getDestination() != (*myStep)->getFromEdge())) {
137 267190 : checkAccess(prior, false);
138 487068 : } else if ((*myStep)->getStageType() == MSStageType::WAITING && prior->getStageType() == MSStageType::WAITING && prior->getDestination() != (*myStep)->getFromEdge()) {
139 22 : checkAccess(prior, false);
140 : }
141 754258 : (*myStep)->proceed(net, this, time, prior);
142 : return true;
143 : } else {
144 393322 : MSNet::getInstance()->getPersonControl().addArrived();
145 393322 : return false;
146 : }
147 : }
148 :
149 :
150 : void
151 0 : MSTransportable::setID(const std::string& /*newID*/) {
152 0 : throw ProcessError(TL("Changing a transportable ID is not permitted"));
153 : }
154 :
155 : SUMOTime
156 0 : MSTransportable::getDesiredDepart() const {
157 0 : return myParameter->depart;
158 : }
159 :
160 : void
161 499839 : MSTransportable::setDeparted(SUMOTime now) {
162 499839 : (*myStep)->setDeparted(now);
163 499839 : }
164 :
165 : SUMOTime
166 122 : MSTransportable::getDeparture() const {
167 122 : for (const MSStage* const stage : *myPlan) {
168 122 : if (stage->getDeparted() >= 0) {
169 122 : return stage->getDeparted();
170 : }
171 : }
172 : return -1;
173 : }
174 :
175 :
176 : double
177 3489378 : MSTransportable::getEdgePos() const {
178 3489378 : return (*myStep)->getEdgePos(MSNet::getInstance()->getCurrentTimeStep());
179 : }
180 :
181 : double
182 3536 : MSTransportable::getBackPositionOnLane(const MSLane* /*lane*/) const {
183 3536 : return getEdgePos() - getVehicleType().getLength();
184 : }
185 :
186 : int
187 368116 : MSTransportable::getDirection() const {
188 368116 : return (*myStep)->getDirection();
189 : }
190 :
191 : Position
192 5376103 : MSTransportable::getPosition() const {
193 5376103 : return (*myStep)->getPosition(MSNet::getInstance()->getCurrentTimeStep());
194 : }
195 :
196 : double
197 3249554 : MSTransportable::getAngle() const {
198 3249554 : return (*myStep)->getAngle(MSNet::getInstance()->getCurrentTimeStep());
199 : }
200 :
201 : double
202 612 : MSTransportable::getWaitingSeconds() const {
203 612 : return STEPS2TIME((*myStep)->getWaitingTime());
204 : }
205 :
206 : double
207 841068 : MSTransportable::getSpeed() const {
208 841068 : return (*myStep)->getSpeed();
209 : }
210 :
211 :
212 : void
213 56675 : MSTransportable::tripInfoOutput(OutputDevice& os) const {
214 56675 : SUMOTime departure = myPlan->front()->getDeparted();
215 114202 : os.openTag(isPerson() ? "personinfo" : "containerinfo");
216 56675 : os.writeAttr(SUMO_ATTR_ID, getID());
217 56675 : os.writeAttr(SUMO_ATTR_DEPART, departure >= 0 ? time2string(departure) : "-1");
218 56675 : os.writeAttr(SUMO_ATTR_TYPE, getVehicleType().getID());
219 56675 : if (isPerson()) {
220 55823 : os.writeAttr(SUMO_ATTR_SPEEDFACTOR, getChosenSpeedFactor());
221 : }
222 : SUMOTime duration = 0;
223 : SUMOTime waitingTime = 0;
224 : SUMOTime timeLoss = 0;
225 : SUMOTime travelTime = 0;
226 : bool durationOK = true;
227 : bool waitingTimeOK = true;
228 : bool timeLossOK = true;
229 : bool travelTimeOK = true;
230 189892 : for (MSStage* const i : *myPlan) {
231 133217 : SUMOTime t = i->getDuration();
232 133217 : if (t != SUMOTime_MAX) {
233 132589 : duration += t;
234 : } else {
235 : durationOK = false;
236 : }
237 133217 : t = i->getTotalWaitingTime();
238 133217 : if (t != SUMOTime_MAX) {
239 133213 : waitingTime += t;
240 : } else {
241 : waitingTimeOK = false;
242 : }
243 133217 : t = i->getTimeLoss(this);
244 133217 : if (t != SUMOTime_MAX) {
245 132952 : timeLoss += t;
246 : } else {
247 : timeLossOK = false;
248 : }
249 133217 : t = i->getTravelTime();
250 133217 : if (t != SUMOTime_MAX) {
251 132591 : travelTime += t;
252 : } else {
253 : travelTimeOK = false;
254 : }
255 : }
256 56675 : os.writeAttr(SUMO_ATTR_DURATION, durationOK ? time2string(duration) : "-1");
257 56675 : os.writeAttr(SUMO_ATTR_WAITINGTIME, waitingTimeOK ? time2string(waitingTime) : "-1");
258 56675 : os.writeAttr(SUMO_ATTR_TIMELOSS, timeLossOK ? time2string(timeLoss) : "-1");
259 56675 : os.writeAttr(SUMO_ATTR_TRAVELTIME, travelTimeOK ? time2string(travelTime) : "-1");
260 189892 : for (MSStage* const i : *myPlan) {
261 133217 : i->tripInfoOutput(os, this);
262 : }
263 56675 : os.closeTag();
264 56675 : }
265 :
266 :
267 : void
268 3015 : MSTransportable::routeOutput(OutputDevice& os, const bool withRouteLength) const {
269 : const std::string typeID = (
270 5954 : (isPerson() && getVehicleType().getID() == DEFAULT_PEDTYPE_ID)
271 5954 : || (isContainer() && getVehicleType().getID() == DEFAULT_CONTAINERTYPE_ID)) ? "" : getVehicleType().getID();
272 3091 : myParameter->write(os, OptionsCont::getOptions(), isPerson() ? SUMO_TAG_PERSON : SUMO_TAG_CONTAINER, typeID);
273 3015 : if (hasArrived()) {
274 5910 : os.writeAttr("arrival", time2string(MSNet::getInstance()->getCurrentTimeStep()));
275 : }
276 : const MSStage* previous = nullptr;
277 12135 : for (const MSStage* const stage : *myPlan) {
278 9120 : stage->routeOutput(myAmPerson, os, withRouteLength, previous);
279 : previous = stage;
280 : }
281 3015 : myParameter->writeParams(os);
282 3015 : os.closeTag();
283 3015 : os.lf();
284 3015 : }
285 :
286 :
287 : void
288 32 : MSTransportable::setAbortWaiting(const SUMOTime timeout) {
289 32 : if (timeout < 0 && myAbortCommand != nullptr) {
290 : myAbortCommand->deschedule();
291 16 : myAbortCommand = nullptr;
292 16 : return;
293 : }
294 16 : myAbortCommand = new WrappingCommand<MSTransportable>(this, &MSTransportable::abortStage);
295 16 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myAbortCommand, SIMSTEP + timeout);
296 : }
297 :
298 :
299 : SUMOTime
300 16 : MSTransportable::abortStage(SUMOTime step) {
301 48 : WRITE_WARNINGF(TL("Teleporting % '%'; waited too long, from edge '%', time=%."),
302 : isPerson() ? "person" : "container", getID(), (*myStep)->getEdge()->getID(), time2string(step));
303 16 : MSTransportableControl& tc = isPerson() ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl();
304 : tc.registerTeleportAbortWait();
305 16 : (*myStep)->abort(this);
306 16 : if (!proceed(MSNet::getInstance(), step)) {
307 8 : tc.erase(this);
308 : }
309 16 : return 0;
310 : }
311 :
312 :
313 : void
314 213383 : MSTransportable::appendStage(MSStage* stage, int next) {
315 : // myStep is invalidated upon modifying myPlan
316 213383 : const int stepIndex = (int)(myStep - myPlan->begin());
317 213383 : if (next < 0) {
318 392 : myPlan->push_back(stage);
319 : } else {
320 212991 : if (stepIndex + next > (int)myPlan->size()) {
321 0 : throw ProcessError("invalid index '" + toString(next) + "' for inserting new stage into plan of '" + getID() + "'");
322 : }
323 212991 : myPlan->insert(myPlan->begin() + stepIndex + next, stage);
324 : }
325 213383 : myStep = myPlan->begin() + stepIndex;
326 213383 : }
327 :
328 :
329 : void
330 1913 : MSTransportable::removeStage(int next, bool stayInSim) {
331 : assert(myStep + next < myPlan->end());
332 : assert(next >= 0);
333 1913 : if (next > 0) {
334 : // myStep is invalidated upon modifying myPlan
335 82 : int stepIndex = (int)(myStep - myPlan->begin());
336 82 : delete *(myStep + next);
337 82 : myPlan->erase(myStep + next);
338 82 : myStep = myPlan->begin() + stepIndex;
339 : } else {
340 1831 : if (myStep + 1 == myPlan->end() && stayInSim) {
341 : // stay in the simulation until the start of simStep to allow appending new stages (at the correct position)
342 166 : appendStage(new MSStageWaiting(getEdge(), nullptr, 0, 0, getEdgePos(), "last stage removed", false));
343 1748 : } else if (myStep + 1 != myPlan->end()) {
344 3122 : (*(myStep + 1))->setOrigin(getEdge(), getEdge() == getFromEdge() ? (*myStep)->getOriginStop() : nullptr, getEdgePos());
345 : }
346 1831 : (*myStep)->abort(this);
347 1831 : if (!proceed(MSNet::getInstance(), SIMSTEP)) {
348 187 : MSNet::getInstance()->getPersonControl().erase(this);
349 1644 : } else if (myPlan->front()->getDeparted() < 0) {
350 44 : myPlan->front()->setDeparted(SIMSTEP);
351 : }
352 : }
353 1913 : }
354 :
355 :
356 : void
357 14 : MSTransportable::setSpeed(double speed) {
358 37 : for (MSTransportablePlan::const_iterator i = myStep; i != myPlan->end(); ++i) {
359 23 : (*i)->setSpeed(speed);
360 : }
361 14 : getSingularType().setMaxSpeed(speed);
362 14 : }
363 :
364 :
365 : bool
366 0 : MSTransportable::replaceRoute(ConstMSRoutePtr newRoute, const std::string& /* info */, bool /* onInit */, int /* offset */, bool /* addRouteStops */, bool /* removeStops */, std::string* /* msgReturn */) {
367 0 : if (isPerson()) {
368 0 : static_cast<MSPerson*>(this)->replaceWalk(newRoute->getEdges(), getPositionOnLane(), 0, 1);
369 0 : return true;
370 : }
371 : return false;
372 : }
373 :
374 :
375 : bool
376 100 : MSTransportable::reroute(SUMOTime t, const std::string& /* info */, MSTransportableRouter& router, const bool /* onInit */, const bool /* withTaz */, const bool /* silent */, const MSEdge* /* sink */) {
377 : MSStageTrip* trip = getCurrentStage()->getTrip();
378 100 : if (trip == nullptr) {
379 : // TODO this should be possible after factoring out MSStageTrip::reroute
380 : return false;
381 : }
382 100 : if (getCurrentStage()->getVehicle() != nullptr) {
383 : // TODO rerouting during a ride still needs to be implemented
384 : return false;
385 : }
386 : // find the final stage of the trip
387 : int tripEndOffset = -1;
388 80 : for (int i = getNumRemainingStages() - 1; i >= 0; i--) {
389 80 : if (getNextStage(i)->getTrip() == trip) {
390 : tripEndOffset = i;
391 : break;
392 : }
393 : }
394 : std::vector<MSStage*> stages;
395 80 : MSStageWaiting start(getEdge(), getCurrentStage()->getOriginStop(), -1, t, getEdgePos(), "start", true);
396 80 : if (trip->reroute(t, router, this, &start, getEdge(), getRerouteDestination(), stages) == "") {
397 : // check whether the new plan actually differs
398 150 : while (tripEndOffset >= 0 && !stages.empty() && stages.back()->equals(*getNextStage(tripEndOffset))) {
399 70 : delete stages.back();
400 : stages.pop_back();
401 70 : tripEndOffset--;
402 : }
403 : bool abortCurrent = true;
404 : // check whether the future route of the current stage is identical to the route
405 80 : if (!stages.empty() && stages.front()->isWalk() && getCurrentStage()->isWalk()) {
406 : // TODO this check should be done for rides as well
407 : MSStageMoving* s = static_cast<MSStageMoving*>(getCurrentStage());
408 48 : int routeIndex = (int)(s->getRouteStep() - s->getRoute().begin());
409 48 : ConstMSEdgeVector oldEdges = s->getEdges();
410 : oldEdges.erase(oldEdges.begin(), oldEdges.begin() + routeIndex);
411 48 : ConstMSEdgeVector newEdges = stages.front()->getEdges();
412 48 : if (newEdges == oldEdges) {
413 48 : delete stages.front();
414 : stages.erase(stages.begin());
415 : abortCurrent = false;
416 : }
417 48 : }
418 80 : if (stages.empty()) {
419 : return false;
420 : }
421 : // remove future stages of the trip
422 12 : for (int i = tripEndOffset; i >= 1; i--) {
423 6 : removeStage(i);
424 : }
425 : // insert new stages of the rerouting
426 : int idx = 1;
427 12 : for (MSStage* stage : stages) {
428 6 : appendStage(stage, idx++);
429 : }
430 6 : if (abortCurrent) {
431 0 : removeStage(0);
432 : }
433 6 : return true;
434 : }
435 : return false;
436 80 : }
437 :
438 :
439 : void
440 196 : MSTransportable::replaceVehicleType(const MSVehicleType* type) {
441 196 : const SUMOVehicleClass oldVClass = myVType->getVehicleClass();
442 196 : if (myVType->isVehicleSpecific()) {
443 1 : MSNet::getInstance()->getVehicleControl().removeVType(myVType);
444 : }
445 196 : if (isPerson()
446 196 : && type->getVehicleClass() != oldVClass
447 10 : && type->getVehicleClass() != SVC_PEDESTRIAN
448 201 : && !type->getParameter().wasSet(VTYPEPARS_VEHICLECLASS_SET)) {
449 15 : WRITE_WARNINGF(TL("Person '%' receives type '%' which implicitly uses unsuitable vClass '%'."), getID(), type->getID(), toString(type->getVehicleClass()));
450 : }
451 196 : myVType = type;
452 196 : }
453 :
454 :
455 : MSVehicleType&
456 202 : MSTransportable::getSingularType() {
457 202 : if (myVType->isVehicleSpecific()) {
458 : return *const_cast<MSVehicleType*>(myVType);
459 : }
460 360 : MSVehicleType* type = myVType->buildSingularType(myVType->getID() + "@" + getID());
461 180 : replaceVehicleType(type);
462 180 : return *type;
463 : }
464 :
465 :
466 : PositionVector
467 1124141 : MSTransportable::getBoundingBox() const {
468 1124141 : PositionVector centerLine;
469 1124141 : const Position p = getPosition();
470 1124141 : const double angle = getAngle();
471 1124141 : const double length = getVehicleType().getLength();
472 1124141 : const Position back = p + Position(-cos(angle) * length, -sin(angle) * length);
473 1124141 : centerLine.push_back(p);
474 1124141 : centerLine.push_back(back);
475 1124141 : centerLine.move2side(0.5 * getVehicleType().getWidth());
476 : PositionVector result = centerLine;
477 1124141 : centerLine.move2side(-getVehicleType().getWidth());
478 1124141 : result.append(centerLine.reverse(), POSITION_EPS);
479 : //std::cout << " transp=" << getID() << " p=" << p << " angle=" << GeomHelper::naviDegree(angle) << " back=" << back << " result=" << result << "\n";
480 1124141 : return result;
481 1124141 : }
482 :
483 :
484 : std::string
485 0 : MSTransportable::getStageSummary(int stageIndex) const {
486 : assert(stageIndex < (int)myPlan->size());
487 : assert(stageIndex >= 0);
488 0 : return (*myPlan)[stageIndex]->getStageSummary(myAmPerson);
489 : }
490 :
491 :
492 : const std::set<SUMOTrafficObject::NumericalID>
493 0 : MSTransportable::getUpcomingEdgeIDs() const {
494 : std::set<SUMOTrafficObject::NumericalID> result;
495 0 : for (auto step = myStep; step != myPlan->end(); ++step) {
496 0 : for (const MSEdge* const e : (*step)->getEdges()) {
497 0 : result.insert(e->getNumericalID());
498 0 : }
499 : }
500 0 : return result;
501 : }
502 :
503 :
504 : bool
505 4348226 : MSTransportable::hasArrived() const {
506 4348226 : return myStep == myPlan->end();
507 : }
508 :
509 : bool
510 420380 : MSTransportable::hasDeparted() const {
511 420380 : return myPlan->size() > 0 && (myPlan->front()->getDeparted() >= 0 || myStep > myPlan->begin());
512 : }
513 :
514 :
515 : void
516 45 : MSTransportable::rerouteParkingArea(MSStoppingPlace* orig, MSStoppingPlace* replacement) {
517 : // check whether the transportable was riding to the orignal stop
518 : // @note: parkingArea can currently not be set as myDestinationStop so we
519 : // check for stops on the edge instead
520 : #ifdef DEBUG_PARKING
521 : std::cout << SIMTIME << " person=" << getID() << " rerouteParkingArea orig=" << orig->getID() << " replacement=" << replacement->getID() << "\n";
522 : #endif
523 : assert(getCurrentStageType() == MSStageType::DRIVING);
524 45 : if (!myAmPerson) {
525 0 : WRITE_WARNING(TL("parkingAreaReroute not supported for containers"));
526 0 : return;
527 : }
528 45 : if (getDestination() == &orig->getLane().getEdge()) {
529 45 : MSStageDriving* const stage = dynamic_cast<MSStageDriving*>(*myStep);
530 : assert(stage != 0);
531 : assert(stage->getVehicle() != 0);
532 : // adapt plan
533 45 : stage->setDestination(&replacement->getLane().getEdge(), replacement);
534 45 : stage->setArrivalPos((replacement->getBeginLanePosition() + replacement->getEndLanePosition()) / 2);
535 : #ifdef DEBUG_PARKING
536 : std::cout << " set ride destination\n";
537 : #endif
538 45 : if (myStep + 1 == myPlan->end()) {
539 : return;
540 : }
541 : // if the next step is a walk, adapt the route
542 45 : MSStage* nextStage = *(myStep + 1);
543 45 : if (nextStage->getStageType() == MSStageType::TRIP) {
544 35 : dynamic_cast<MSStageTrip*>(nextStage)->setOrigin(stage->getDestination(), stage->getDestinationStop(), stage->getArrivalPos());
545 : #ifdef DEBUG_PARKING
546 : std::cout << " set subsequent trip origin\n";
547 : #endif
548 10 : } else if (nextStage->getStageType() == MSStageType::WALKING) {
549 : #ifdef DEBUG_PARKING
550 : std::cout << " replace subsequent walk with a trip\n";
551 : #endif
552 : MSStageTrip* newStage = new MSStageTrip(stage->getDestination(), nullptr, nextStage->getDestination(),
553 5 : nextStage->getDestinationStop(), -1, 0, "", -1, 1, getID(), 0, true, nextStage->getArrivalPos());
554 5 : removeStage(1);
555 5 : appendStage(newStage, 1);
556 5 : } else if (nextStage->getStageType() == MSStageType::WAITING) {
557 : #ifdef DEBUG_PARKING
558 : std::cout << " add subsequent walk to reach stop\n";
559 : std::cout << " arrivalPos=" << nextStage->getArrivalPos() << "\n";
560 : #endif
561 : MSStageTrip* newStage = new MSStageTrip(stage->getDestination(), nullptr, nextStage->getDestination(),
562 5 : nextStage->getDestinationStop(), -1, 0, "", -1, 1, getID(), 0, true, nextStage->getArrivalPos());
563 5 : appendStage(newStage, 1);
564 : }
565 : // if the plan contains another ride with the same vehicle from the same
566 : // parking area, adapt the preceeding walk to end at the replacement
567 90 : for (auto it = myStep + 2; it != myPlan->end(); it++) {
568 55 : MSStage* const futureStage = *it;
569 55 : MSStage* const prevStage = *(it - 1);
570 55 : if (futureStage->getStageType() == MSStageType::DRIVING) {
571 : MSStageDriving* const ds = static_cast<MSStageDriving*>(futureStage);
572 : // ride origin is set implicitly from the walk destination
573 10 : ds->setOrigin(nullptr, nullptr, -1);
574 : if (ds->getLines() == stage->getLines()
575 10 : && prevStage->getDestination() == &orig->getLane().getEdge()) {
576 10 : if (prevStage->getStageType() == MSStageType::TRIP) {
577 5 : dynamic_cast<MSStageTrip*>(prevStage)->setDestination(stage->getDestination(), replacement);
578 : #ifdef DEBUG_PARKING
579 : std::cout << " replace later trip before ride (" << (it - myPlan->begin()) << ")\n";
580 : #endif
581 5 : } else if (prevStage->getStageType() == MSStageType::WALKING) {
582 : #ifdef DEBUG_PARKING
583 : std::cout << " replace later walk before ride (" << (it - myPlan->begin()) << ")\n";
584 : #endif
585 5 : MSStageTrip* newStage = new MSStageTrip(prevStage->getFromEdge(), nullptr, stage->getDestination(),
586 10 : replacement, -1, 0, "", -1, 1, getID(), 0, true, stage->getArrivalPos());
587 5 : int prevStageRelIndex = (int)(it - 1 - myStep);
588 5 : removeStage(prevStageRelIndex);
589 5 : appendStage(newStage, prevStageRelIndex);
590 : }
591 : break;
592 : }
593 : }
594 : }
595 : }
596 : }
597 :
598 :
599 : MSDevice*
600 658984 : MSTransportable::getDevice(const std::type_info& type) const {
601 871468 : for (MSTransportableDevice* const dev : myDevices) {
602 747457 : if (typeid(*dev) == type) {
603 : return dev;
604 : }
605 : }
606 : return nullptr;
607 : }
608 :
609 :
610 : void
611 10 : MSTransportable::setJunctionModelParameter(const std::string& key, const std::string& value) {
612 15 : if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
613 5 : getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
614 5 : const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
615 : // checked in MSLink::ignoreFoe
616 : } else {
617 15 : throw InvalidArgument(getObjectType() + " '" + getID() + "' does not support junctionModel parameter '" + key + "'");
618 : }
619 5 : }
620 :
621 :
622 : double
623 0 : MSTransportable::getSlope() const {
624 0 : const MSEdge* edge = getEdge();
625 0 : const double ep = getEdgePos();
626 0 : const double gp = edge->getLanes()[0]->interpolateLanePosToGeometryPos(ep);
627 0 : return edge->getLanes()[0]->getShape().slopeDegreeAtOffset(gp);
628 : }
629 :
630 :
631 : SUMOTime
632 8856 : MSTransportable::getWaitingTime(const bool /* accumulated */) const {
633 8856 : return (*myStep)->getWaitingTime();
634 : }
635 :
636 :
637 : double
638 135204677 : MSTransportable::getMaxSpeed() const {
639 135204677 : return MIN2(getVehicleType().getMaxSpeed(), getVehicleType().getDesiredMaxSpeed() * getChosenSpeedFactor());
640 : }
641 :
642 :
643 : SUMOVehicleClass
644 2644488 : MSTransportable::getVClass() const {
645 2644488 : return getVehicleType().getVehicleClass();
646 : }
647 :
648 :
649 : int
650 0 : MSTransportable::getRoutingMode() const {
651 : /// @todo: allow configuring routing mode
652 0 : return libsumo::ROUTING_MODE_DEFAULT;
653 : }
654 :
655 : void
656 43 : MSTransportable::saveState(OutputDevice& out) {
657 : // this saves lots of departParameters which are only needed for transportables that did not yet depart
658 : // the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
659 43 : const SUMOTime desiredDepart = myParameter->depart;
660 43 : if (myPlan->front()->getDeparted() >= 0) {
661 : // this is only relevant in the context of delayed departure (max-num-persons)
662 37 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = myPlan->front()->getDeparted();
663 : }
664 43 : myParameter->write(out, OptionsCont::getOptions(), myAmPerson ? SUMO_TAG_PERSON : SUMO_TAG_CONTAINER, getVehicleType().getID());
665 43 : const_cast<SUMOVehicleParameter*>(myParameter)->depart = desiredDepart;
666 43 : if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET) && getChosenSpeedFactor() != 1) {
667 41 : out.setPrecision(MAX2(gPrecisionRandom, gPrecision));
668 41 : out.writeAttr(SUMO_ATTR_SPEEDFACTOR, getChosenSpeedFactor());
669 41 : out.setPrecision(gPrecision);
670 : }
671 43 : int stepIdx = (int)(myStep - myPlan->begin());
672 101 : for (auto it = myPlan->begin(); it != myStep; ++it) {
673 58 : const MSStageType st = (*it)->getStageType();
674 58 : if (st == MSStageType::TRIP || st == MSStageType::ACCESS) {
675 19 : stepIdx--;
676 : }
677 : }
678 43 : std::ostringstream state;
679 86 : state << myParameter->parametersSet << " " << stepIdx;
680 43 : (*myStep)->saveState(state);
681 43 : out.writeAttr(SUMO_ATTR_STATE, state.str());
682 : const MSStage* previous = nullptr;
683 150 : for (const MSStage* const stage : *myPlan) {
684 107 : stage->routeOutput(myAmPerson, out, false, previous);
685 : previous = stage;
686 : }
687 43 : out.closeTag();
688 43 : }
689 :
690 :
691 : void
692 48 : MSTransportable::loadState(const std::string& state) {
693 48 : std::istringstream iss(state);
694 : int step;
695 48 : iss >> myParameter->parametersSet >> step;
696 48 : myPlan->front()->setDeparted(myParameter->depart);
697 48 : myStep = myPlan->begin() + step;
698 48 : (*myStep)->loadState(this, iss);
699 48 : }
700 :
701 :
702 : /****************************************************************************/
|