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