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