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 MSStageWalking.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @date Mon, 9 Jul 2001
20 : ///
21 : // A stage performing walking on a sequence of edges.
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <vector>
27 : #include <utils/iodevices/OutputDevice.h>
28 : #include <utils/options/OptionsCont.h>
29 : #include <utils/common/ToString.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/geom/GeomHelper.h>
32 : #include <utils/router/IntermodalNetwork.h>
33 : #include <microsim/MSNet.h>
34 : #include <microsim/MSEdge.h>
35 : #include <microsim/MSLane.h>
36 : #include <microsim/transportables/MSTransportableControl.h>
37 : #include <microsim/MSInsertionControl.h>
38 : #include <microsim/MSEventControl.h>
39 : #include <microsim/MSVehicle.h>
40 : #include <microsim/MSVehicleControl.h>
41 : #include <microsim/MSStoppingPlace.h>
42 : #include <microsim/MSRouteHandler.h>
43 : #include <microsim/devices/MSDevice_Tripinfo.h>
44 : #include <microsim/devices/MSDevice_Taxi.h>
45 : #include <microsim/trigger/MSTriggeredRerouter.h>
46 : #include "MSPModel_Striping.h"
47 : #include "MSStageTrip.h"
48 : #include "MSPerson.h"
49 : #include "MSStageWalking.h"
50 :
51 :
52 : // ===========================================================================
53 : // static member definition
54 : // ===========================================================================
55 : bool MSStageWalking::myWarnedInvalidTripinfo = false;
56 :
57 :
58 : // ===========================================================================
59 : // method definitions
60 : // ===========================================================================
61 229446 : MSStageWalking::MSStageWalking(const std::string& personID,
62 : const ConstMSEdgeVector& route,
63 : MSStoppingPlace* toStop,
64 : SUMOTime walkingTime, double speed,
65 : double departPos, double arrivalPos, double departPosLat, int departLane,
66 229446 : const std::string& routeID) :
67 : MSStageMoving(MSStageType::WALKING, route, routeID, toStop, speed, departPos, arrivalPos, departPosLat, departLane),
68 229446 : myWalkingTime(walkingTime),
69 229446 : myExitTimes(nullptr),
70 229446 : myInternalDistance(0) {
71 229446 : myDepartPos = SUMOVehicleParameter::interpretEdgePos(departPos, route.front()->getLength(), SUMO_ATTR_DEPARTPOS,
72 458892 : "person '" + personID + "' walking from edge '" + route.front()->getID() + "'");
73 229446 : myArrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, route.back()->getLength(), SUMO_ATTR_ARRIVALPOS,
74 229446 : "person '" + personID + "' walking to edge '" + route.back()->getID() + "'");
75 229446 : if (walkingTime > 0) {
76 111 : mySpeed = computeAverageSpeed();
77 : }
78 229446 : }
79 :
80 :
81 458804 : MSStageWalking::~MSStageWalking() {
82 229402 : delete myExitTimes;
83 458804 : }
84 :
85 :
86 : MSStage*
87 26486 : MSStageWalking::clone() const {
88 26486 : std::vector<const MSEdge*> route = myRoute;
89 26486 : double departPos = myDepartPos;
90 26486 : double arrivalPos = myArrivalPos;
91 26486 : int departLane = myDepartLane;
92 26486 : if (myRouteID != "" && MSRoute::distDictionary(myRouteID) != nullptr) {
93 576 : route = MSRoute::dictionary(myRouteID, MSRouteHandler::getParsingRNG())->getEdges();
94 288 : if (departPos > route[0]->getLength()) {
95 0 : WRITE_WARNINGF(TL("Adjusting departPos for cloned walk with routeDistribution '%'"), myRouteID);
96 0 : departPos = route[0]->getLength();
97 : }
98 288 : if (arrivalPos > route.back()->getLength()) {
99 0 : WRITE_WARNINGF(TL("Adjusting arrivalPos for cloned walk with routeDistribution '%'"), myRouteID);
100 0 : arrivalPos = route.back()->getLength();
101 : }
102 288 : if (departLane >= route[0]->getNumLanes()) {
103 0 : WRITE_WARNINGF(TL("Adjusting departLane for cloned walk with routeDistribution '%'"), myRouteID);
104 0 : departLane = route[0]->getNumLanes() - 1;
105 : }
106 : }
107 26486 : MSStage* clon = new MSStageWalking("dummyID", route, myDestinationStop, myWalkingTime, mySpeed, departPos, arrivalPos, myDepartPosLat, departLane, myRouteID);
108 26486 : clon->setParameters(*this);
109 26486 : return clon;
110 26486 : }
111 :
112 :
113 : void
114 228510 : MSStageWalking::proceed(MSNet* net, MSTransportable* person, SUMOTime now, MSStage* previous) {
115 228510 : myDeparted = now;
116 228510 : myRouteStep = myRoute.begin();
117 228510 : myLastEdgeEntryTime = now;
118 228510 : if (myWalkingTime == 0) {
119 0 : if (!person->proceed(net, now)) {
120 0 : MSNet::getInstance()->getPersonControl().erase(person);
121 : }
122 0 : return;
123 : }
124 228510 : const OptionsCont& oc = OptionsCont::getOptions();
125 228510 : if (previous->getEdgePos(now) >= 0 && previous->getEdge() == *myRouteStep) {
126 : // we need to adapt to the arrival position of the vehicle unless we have an explicit access
127 227812 : myDepartPos = previous->getEdgePos(now);
128 455624 : if (oc.getString("pedestrian.model") == "jupedsim") {
129 0 : myDepartPosLat = previous->getEdgePosLat(now);
130 : }
131 227812 : if (myWalkingTime > 0) {
132 93 : mySpeed = computeAverageSpeed();
133 : }
134 : }
135 228510 : MSTransportableControl& pControl = net->getPersonControl();
136 228510 : myPState = pControl.getMovementModel()->add(person, this, now);
137 228506 : if (myPState == nullptr) {
138 8 : pControl.erase(person);
139 8 : return;
140 : }
141 228498 : if (previous->getStageType() != MSStageType::WALKING || previous->getEdge() != getEdge()) {
142 : // we only need new move reminders if we are walking a different edge (else it is probably a rerouting)
143 226987 : activateEntryReminders(person, true);
144 : }
145 456996 : if (oc.getBool("vehroute-output.exit-times")) {
146 144 : myExitTimes = new std::vector<SUMOTime>();
147 : }
148 228498 : (*myRouteStep)->addTransportable(person);
149 : }
150 :
151 :
152 : void
153 1696 : MSStageWalking::abort(MSTransportable*) {
154 1696 : MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
155 1696 : }
156 :
157 :
158 : void
159 18 : MSStageWalking::setSpeed(double speed) {
160 18 : mySpeed = speed;
161 18 : }
162 :
163 :
164 : double
165 204 : MSStageWalking::computeAverageSpeed() const {
166 204 : return walkDistance() / STEPS2TIME(myWalkingTime + 1); // avoid systematic rounding errors
167 : }
168 :
169 :
170 : bool
171 1155618 : MSPerson::isJammed() const {
172 1155618 : MSStageWalking* stage = dynamic_cast<MSStageWalking*>(getCurrentStage());
173 1155618 : if (stage != nullptr) {
174 1155618 : return stage->getPState()->isJammed();
175 : }
176 : return false;
177 : }
178 :
179 :
180 : double
181 276170 : MSStageWalking::walkDistance(bool partial) const {
182 : double length = 0;
183 276170 : auto endIt = partial && myArrived < 0 ? myRouteStep + 1 : myRoute.end();
184 750209 : for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt; ++i) {
185 474039 : length += (*i)->getLength();
186 : }
187 276170 : if (myRoute.size() > 1 && MSNet::getInstance()->getPersonControl().getMovementModel()->usingInternalLanes()) {
188 121462 : if (myInternalDistance > 0) {
189 109370 : length += myInternalDistance;
190 : } else {
191 : // use lower bound for distance to pass the intersection
192 48195 : for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt - 1; ++i) {
193 36103 : const MSEdge* fromEdge = *i;
194 36103 : const MSEdge* toEdge = *(i + 1);
195 36103 : const MSLane* from = getSidewalk<MSEdge, MSLane>(fromEdge);
196 36103 : const MSLane* to = getSidewalk<MSEdge, MSLane>(toEdge);
197 : Position fromPos;
198 : Position toPos;
199 36103 : if (from != nullptr && to != nullptr) {
200 36103 : if (fromEdge->getToJunction() == toEdge->getFromJunction()) {
201 36055 : fromPos = from->getShape().back();
202 36055 : toPos = to->getShape().front();
203 48 : } else if (fromEdge->getToJunction() == toEdge->getToJunction()) {
204 26 : fromPos = from->getShape().back();
205 26 : toPos = to->getShape().back();
206 22 : } else if (fromEdge->getFromJunction() == toEdge->getFromJunction()) {
207 10 : fromPos = from->getShape().front();
208 10 : toPos = to->getShape().front();
209 12 : } else if (fromEdge->getFromJunction() == toEdge->getToJunction()) {
210 12 : fromPos = from->getShape().front();
211 12 : toPos = to->getShape().back();
212 : }
213 : //std::cout << " from=" << from->getID() << " to=" << to->getID() << " junctionLength=" << fromPos.distanceTo2D(toPos) << "\n";
214 36103 : length += fromPos.distanceTo2D(toPos);
215 : }
216 : }
217 : }
218 : }
219 : // determine walking direction for depart and arrival
220 276170 : int dummy = 0;
221 276170 : const int departFwdArrivalDir = MSPModel::canTraverse(MSPModel::FORWARD, myRoute, dummy);
222 276170 : const int departBwdArrivalDir = MSPModel::canTraverse(MSPModel::BACKWARD, myRoute, dummy);
223 276170 : const bool mayStartForward = departFwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
224 276170 : const bool mayStartBackward = departBwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
225 276170 : const double arrivalPos = partial && myArrived < 0 ? getEdgePos(SIMSTEP) : myArrivalPos;
226 276170 : const double lengthFwd = (length - myDepartPos - (
227 : departFwdArrivalDir == MSPModel::BACKWARD
228 276170 : ? arrivalPos
229 276170 : : myRoute.back()->getLength() - arrivalPos));
230 276170 : const double lengthBwd = (length - (myRoute.front()->getLength() - myDepartPos) - (
231 : departBwdArrivalDir == MSPModel::BACKWARD
232 276170 : ? arrivalPos
233 276170 : : myRoute.back()->getLength() - arrivalPos));
234 : //std::cout << " length=" << length << " lengthFwd=" << lengthFwd << " lengthBwd=" << lengthBwd << " mayStartForward=" << mayStartForward << " mayStartBackward=" << mayStartBackward << "\n";
235 :
236 276170 : if (myRoute.size() == 1) {
237 134397 : if (myDepartPos > myArrivalPos) {
238 : length = lengthBwd;
239 : } else {
240 : length = lengthFwd;
241 : }
242 : } else {
243 141773 : if (mayStartForward && mayStartBackward) {
244 11035 : length = lengthFwd < lengthBwd ? lengthFwd : lengthBwd;
245 130738 : } else if (mayStartForward) {
246 : length = lengthFwd;
247 49114 : } else if (mayStartBackward) {
248 : length = lengthBwd;
249 : } else {
250 : length = lengthFwd;
251 : }
252 : }
253 : //std::cout << SIMTIME << " route=" << toString(myRoute)
254 : // << " depPos=" << myDepartPos << " arPos=" << myArrivalPos
255 : // << " dFwdADir=" << departFwdArrivalDir
256 : // << " dBwdADir=" << departBwdArrivalDir
257 : // << " lengthFwd=" << lengthFwd
258 : // << " lengthBwd=" << lengthBwd
259 : // << "\n";
260 :
261 276170 : return MAX2(POSITION_EPS, length);
262 : }
263 :
264 :
265 : SUMOTime
266 110926 : MSStageWalking::getTimeLoss(const MSTransportable* transportable) const {
267 110926 : SUMOTime timeLoss = myArrived == -1 ? 0 : getDuration() - TIME2STEPS(walkDistance(true) / getMaxSpeed(transportable));
268 110926 : if (timeLoss < 0 && timeLoss > TIME2STEPS(-0.1)) {
269 : // avoid negative timeLoss due to rounding errors
270 : timeLoss = 0;
271 : }
272 110926 : return timeLoss;
273 : }
274 :
275 :
276 : void
277 55463 : MSStageWalking::tripInfoOutput(OutputDevice& os, const MSTransportable* const person) const {
278 55463 : if (!myWarnedInvalidTripinfo && MSNet::getInstance()->getPersonControl().getMovementModel()->usingShortcuts()) {
279 0 : WRITE_WARNING(TL("The pedestrian model uses infrastructure which is not in the network, timeLoss and routeLength may be invalid."));
280 0 : myWarnedInvalidTripinfo = true;
281 : }
282 55463 : const double distance = walkDistance(true);
283 55463 : const double maxSpeed = getMaxSpeed(person);
284 55463 : const SUMOTime duration = myArrived - myDeparted;
285 55463 : const SUMOTime timeLoss = getTimeLoss(person);
286 55463 : MSDevice_Tripinfo::addPedestrianData(distance, duration, timeLoss);
287 55463 : os.openTag("walk");
288 55463 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
289 55463 : os.writeAttr("departPos", myDepartPos);
290 55463 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
291 55463 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(myArrivalPos) : "-1");
292 110661 : os.writeAttr("duration", myDeparted < 0 ? "-1" :
293 55198 : time2string(myArrived >= 0 ? duration : MSNet::getInstance()->getCurrentTimeStep() - myDeparted));
294 55463 : os.writeAttr("routeLength", myArrived >= 0 ? toString(distance) : "-1");
295 55463 : os.writeAttr("timeLoss", time2string(timeLoss));
296 55463 : os.writeAttr("maxSpeed", maxSpeed);
297 55463 : os.writeAttr("waitingTime", time2string(getTotalWaitingTime()));
298 55463 : os.closeTag();
299 55463 : }
300 :
301 :
302 : void
303 2426 : MSStageWalking::routeOutput(const bool /* isPerson */, OutputDevice& os, const bool withRouteLength, const MSStage* const /* previous */, const bool withTiming, const bool saveState) const {
304 2426 : os.openTag("walk").writeAttr(SUMO_ATTR_EDGES, myRoute);
305 2426 : std::string comment = "";
306 2426 : if (myDestinationStop != nullptr) {
307 453 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
308 453 : if (myDestinationStop->getMyName() != "") {
309 231 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
310 : }
311 1973 : } else if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
312 166 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
313 : }
314 2426 : if (myWalkingTime > 0) {
315 0 : os.writeAttr(SUMO_ATTR_DURATION, time2string(myWalkingTime));
316 2426 : } else if (mySpeed > 0) {
317 24 : os.writeAttr(SUMO_ATTR_SPEED, mySpeed);
318 : }
319 2426 : if (withRouteLength) {
320 36 : if (myDeparted >= 0) {
321 36 : os.writeAttr("routeLength", walkDistance(true));
322 : } else {
323 0 : os.writeAttr("routeLength", "-1");
324 : }
325 : }
326 2426 : if (myExitTimes != nullptr) {
327 : std::vector<std::string> exits;
328 562 : for (SUMOTime t : *myExitTimes) {
329 780 : exits.push_back(time2string(t));
330 : }
331 344 : std::vector<std::string> missing(MAX2(0, (int)myRoute.size() - (int)myExitTimes->size()), "-1");
332 172 : exits.insert(exits.end(), missing.begin(), missing.end());
333 172 : os.writeAttr("exitTimes", exits);
334 172 : }
335 2426 : if (withTiming) {
336 194 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
337 194 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
338 : }
339 4852 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
340 105 : os.writeAttr(SUMO_ATTR_COST, getCosts());
341 : }
342 2426 : if (saveState && getTotalWaitingTime() > 0) {
343 2 : os.writeAttr("waitingTime", time2string(getTotalWaitingTime()));
344 : }
345 2426 : os.closeTag(comment);
346 2426 : }
347 :
348 :
349 : bool
350 2631721 : MSStageWalking::moveToNextEdge(MSTransportable* person, SUMOTime currentTime, int prevDir, MSEdge* nextInternal, const bool isReplay) {
351 2631721 : ((MSEdge*)getEdge())->removeTransportable(person);
352 2631721 : const MSLane* lane = getSidewalk<MSEdge, MSLane>(getEdge());
353 : const bool arrived = myRouteStep == myRoute.end() - 1;
354 2631721 : if (lane != nullptr) {
355 2609842 : const double tl = person->getVehicleType().getLength();
356 : const double lastPos = (arrived
357 2609842 : ? (prevDir == MSPModel::FORWARD
358 3692877 : ? getArrivalPos() + tl
359 1758183 : : getArrivalPos() - tl)
360 675148 : : person->getPositionOnLane());
361 2609842 : activateLeaveReminders(person, lane, lastPos, currentTime, arrived);
362 : }
363 2631721 : if (myExitTimes != nullptr && nextInternal == nullptr) {
364 374 : myExitTimes->push_back(currentTime);
365 : }
366 : myMoveReminders.clear();
367 2631721 : myLastEdgeEntryTime = currentTime;
368 : //std::cout << SIMTIME << " moveToNextEdge person=" << person->getID() << "\n";
369 2631721 : if (myCurrentInternalEdge != nullptr) {
370 365420 : myInternalDistance += (myPState->getPathLength() == 0 ? myCurrentInternalEdge->getLength() : myPState->getPathLength());
371 : }
372 2631721 : if (arrived) {
373 1934720 : MSPerson* p = dynamic_cast<MSPerson*>(person);
374 1934720 : if (!isReplay && p->hasInfluencer() && p->getInfluencer().isRemoteControlled()) {
375 1716317 : myCurrentInternalEdge = nextInternal;
376 1716317 : ((MSEdge*) getEdge())->addTransportable(person);
377 1716317 : return false;
378 : }
379 218403 : if (myDestinationStop != nullptr) {
380 33583 : myDestinationStop->addTransportable(person);
381 : }
382 218403 : if (isReplay) {
383 : // cannot do this in the replay device because the person might get deleted below
384 40 : MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
385 : }
386 218403 : if (!person->proceed(MSNet::getInstance(), currentTime)) {
387 211882 : MSNet::getInstance()->getPersonControl().erase(person);
388 : }
389 : //std::cout << " end walk. myRouteStep=" << (*myRouteStep)->getID() << "\n";
390 218403 : return true;
391 : } else {
392 697001 : if (nextInternal == nullptr) {
393 : ++myRouteStep;
394 : }
395 697001 : myCurrentInternalEdge = nextInternal;
396 697001 : ((MSEdge*) getEdge())->addTransportable(person);
397 697001 : return false;
398 : }
399 : }
400 :
401 :
402 : void
403 2639883 : MSStageWalking::activateEntryReminders(MSTransportable* person, const bool isDepart) {
404 2639883 : const MSLane* const nextLane = getSidewalk<MSEdge, MSLane>(getEdge());
405 2639883 : if (nextLane != nullptr) {
406 3459659 : for (MSMoveReminder* const rem : nextLane->getMoveReminders()) {
407 1380735 : if (rem->notifyEnter(*person, isDepart ? MSMoveReminder::NOTIFICATION_DEPARTED : MSMoveReminder::NOTIFICATION_JUNCTION, nextLane)) {
408 18563 : myMoveReminders.push_back(rem);
409 : }
410 : }
411 : }
412 5279766 : if (hasParameter("rerouter")) {
413 : double minDist = std::numeric_limits<double>::max();
414 : MSTriggeredRerouter* nearest = nullptr;
415 190 : for (MSMoveReminder* const rem : myMoveReminders) {
416 120 : MSTriggeredRerouter* rerouter = dynamic_cast<MSTriggeredRerouter*>(rem);
417 120 : if (rerouter != nullptr) {
418 70 : const double dist2 = rerouter->getPosition().distanceSquaredTo2D(person->getPosition());
419 70 : if (dist2 < minDist) {
420 : nearest = rerouter;
421 : minDist = dist2;
422 : }
423 : }
424 : }
425 70 : if (nearest != nullptr) {
426 70 : nearest->triggerRouting(*person, MSMoveReminder::NOTIFICATION_JUNCTION);
427 : }
428 : // TODO maybe removal of the reminders? Or can we rely on movetonextedge to clean everything up?
429 : }
430 2639883 : }
431 :
432 :
433 : void
434 0 : MSStageWalking::activateMoveReminders(MSTransportable* person, double oldPos, double newPos, double newSpeed) {
435 0 : for (std::vector<MSMoveReminder*>::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
436 0 : if ((*rem)->notifyMove(*person, oldPos, newPos, newSpeed)) {
437 : ++rem;
438 : } else {
439 0 : rem = myMoveReminders.erase(rem);
440 : }
441 : }
442 0 : }
443 :
444 :
445 : void
446 2609842 : MSStageWalking::activateLeaveReminders(MSTransportable* person, const MSLane* lane, double lastPos, SUMOTime t, bool arrived) {
447 2609842 : MSMoveReminder::Notification notification = arrived ? MSMoveReminder::NOTIFICATION_ARRIVED : MSMoveReminder::NOTIFICATION_JUNCTION;
448 2627281 : for (MSMoveReminder* const rem : myMoveReminders) {
449 17439 : rem->updateDetector(*person, 0.0, lane->getLength(), myLastEdgeEntryTime, t, t, true);
450 17439 : rem->notifyLeave(*person, lastPos, notification);
451 : }
452 2609842 : }
453 :
454 :
455 : int
456 449238 : MSStageWalking::getRoutePosition() const {
457 449238 : return (int)(myRouteStep - myRoute.begin());
458 : }
459 :
460 :
461 : double
462 21690450 : MSStageWalking::getMaxSpeed(const MSTransportable* const person) const {
463 21690450 : return mySpeed >= 0 ? mySpeed : person->getMaxSpeed();
464 : }
465 :
466 : std::string
467 0 : MSStageWalking::getStageSummary(const bool /* isPerson */) const {
468 0 : const std::string dest = (getDestinationStop() == nullptr ?
469 0 : " edge '" + getDestination()->getID() + "'" :
470 0 : " stop '" + getDestinationStop()->getID() + "'" + (
471 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
472 0 : return "walking to " + dest;
473 : }
474 :
475 :
476 : void
477 32 : MSStageWalking::saveState(std::ostringstream& out, MSTransportable* /*transportable*/) {
478 64 : out << " " << myDeparted << " " << (myRouteStep - myRoute.begin()) << " " << myLastEdgeEntryTime;
479 32 : if (myExitTimes != nullptr) {
480 12 : out << " " << myExitTimes->size();
481 18 : for (SUMOTime t : *myExitTimes) {
482 : out << " " << t;
483 : }
484 : } else {
485 20 : out << " " << -1;
486 : }
487 32 : myPState->saveState(out);
488 32 : }
489 :
490 :
491 : void
492 36 : MSStageWalking::loadState(MSTransportable* transportable, std::istringstream& state) {
493 : int stepIdx;
494 36 : state >> myDeparted >> stepIdx >> myLastEdgeEntryTime;
495 : int exitTimesSize;
496 36 : state >> exitTimesSize;
497 36 : if (exitTimesSize >= 0) {
498 12 : myExitTimes = new std::vector<SUMOTime>();
499 : SUMOTime t;
500 18 : for (int i = 0; i < exitTimesSize; i++) {
501 : state >> t;
502 6 : myExitTimes->push_back(t);
503 : }
504 24 : if (!OptionsCont::getOptions().getBool("vehroute-output.exit-times")) {
505 0 : delete myExitTimes;
506 0 : myExitTimes = nullptr;
507 : }
508 : }
509 36 : myRouteStep = myRoute.begin() + stepIdx;
510 36 : myPState = MSNet::getInstance()->getPersonControl().getMovementModel()->loadState(transportable, this, state);
511 36 : if (myPState->getLane() && !myPState->getLane()->isNormal()) {
512 1 : myCurrentInternalEdge = &myPState->getLane()->getEdge();
513 1 : myCurrentInternalEdge->addTransportable(transportable);
514 : } else {
515 35 : (*myRouteStep)->addTransportable(transportable);
516 : }
517 36 : }
518 :
519 :
520 : /****************************************************************************/
|