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 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 268091 : 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 268091 : const std::string& routeID) :
67 : MSStageMoving(MSStageType::WALKING, route, routeID, toStop, speed, departPos, arrivalPos, departPosLat, departLane),
68 268091 : myWalkingTime(walkingTime),
69 268091 : myExitTimes(nullptr),
70 268091 : myInternalDistance(0) {
71 268091 : myDepartPos = SUMOVehicleParameter::interpretEdgePos(departPos, route.front()->getLength(), SUMO_ATTR_DEPARTPOS,
72 536182 : "person '" + personID + "' walking from edge '" + route.front()->getID() + "'");
73 268091 : myArrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, route.back()->getLength(), SUMO_ATTR_ARRIVALPOS,
74 268091 : "person '" + personID + "' walking to edge '" + route.back()->getID() + "'");
75 268091 : if (walkingTime > 0) {
76 111 : mySpeed = computeAverageSpeed();
77 : }
78 268091 : }
79 :
80 :
81 536054 : MSStageWalking::~MSStageWalking() {
82 268027 : delete myExitTimes;
83 536054 : }
84 :
85 :
86 : MSStage*
87 26254 : MSStageWalking::clone() const {
88 26254 : std::vector<const MSEdge*> route = myRoute;
89 26254 : double departPos = myDepartPos;
90 26254 : double arrivalPos = myArrivalPos;
91 26254 : int departLane = myDepartLane;
92 26254 : 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 26254 : MSStage* clon = new MSStageWalking("dummyID", route, myDestinationStop, myWalkingTime, mySpeed, departPos, arrivalPos, myDepartPosLat, departLane, myRouteID);
108 26254 : clon->setParameters(*this);
109 26254 : return clon;
110 26254 : }
111 :
112 :
113 : void
114 267190 : MSStageWalking::proceed(MSNet* net, MSTransportable* person, SUMOTime now, MSStage* previous) {
115 267190 : myDeparted = now;
116 267190 : myRouteStep = myRoute.begin();
117 267190 : myLastEdgeEntryTime = now;
118 267190 : if (myWalkingTime == 0) {
119 0 : if (!person->proceed(net, now)) {
120 0 : MSNet::getInstance()->getPersonControl().erase(person);
121 : }
122 0 : return;
123 : }
124 267190 : const OptionsCont& oc = OptionsCont::getOptions();
125 267190 : 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 266493 : myDepartPos = previous->getEdgePos(now);
128 532986 : if (oc.getString("pedestrian.model") == "jupedsim") {
129 0 : myDepartPosLat = previous->getEdgePosLat(now);
130 : }
131 266493 : if (myWalkingTime > 0) {
132 93 : mySpeed = computeAverageSpeed();
133 : }
134 : }
135 267190 : MSTransportableControl& pControl = net->getPersonControl();
136 267190 : myPState = pControl.getMovementModel()->add(person, this, now);
137 267186 : if (myPState == nullptr) {
138 8 : pControl.erase(person);
139 8 : return;
140 : }
141 267178 : 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 265667 : activateEntryReminders(person, true);
144 : }
145 534356 : if (oc.getBool("vehroute-output.exit-times")) {
146 126 : myExitTimes = new std::vector<SUMOTime>();
147 : }
148 267178 : (*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 19 : MSStageWalking::setSpeed(double speed) {
160 19 : mySpeed = speed;
161 19 : }
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 1121895 : MSPerson::isJammed() const {
172 1121895 : MSStageWalking* stage = dynamic_cast<MSStageWalking*>(getCurrentStage());
173 1121895 : if (stage != nullptr) {
174 1121895 : return stage->getPState()->isJammed();
175 : }
176 : return false;
177 : }
178 :
179 :
180 : double
181 274719 : MSStageWalking::walkDistance(bool partial) const {
182 : double length = 0;
183 274719 : auto endIt = partial && myArrived < 0 ? myRouteStep + 1 : myRoute.end();
184 745032 : for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt; ++i) {
185 470313 : length += (*i)->getLength();
186 : }
187 274719 : if (myRoute.size() > 1 && MSNet::getInstance()->getPersonControl().getMovementModel()->usingInternalLanes()) {
188 120341 : if (myInternalDistance > 0) {
189 108255 : length += myInternalDistance;
190 : } else {
191 : // use lower bound for distance to pass the intersection
192 48189 : 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 274719 : int dummy = 0;
221 274719 : const int departFwdArrivalDir = MSPModel::canTraverse(MSPModel::FORWARD, myRoute, dummy);
222 274719 : const int departBwdArrivalDir = MSPModel::canTraverse(MSPModel::BACKWARD, myRoute, dummy);
223 274719 : const bool mayStartForward = departFwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
224 274719 : const bool mayStartBackward = departBwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
225 274719 : const double arrivalPos = partial && myArrived < 0 ? getEdgePos(SIMSTEP) : myArrivalPos;
226 274719 : const double lengthFwd = (length - myDepartPos - (
227 : departFwdArrivalDir == MSPModel::BACKWARD
228 274719 : ? arrivalPos
229 274719 : : myRoute.back()->getLength() - arrivalPos));
230 274719 : const double lengthBwd = (length - (myRoute.front()->getLength() - myDepartPos) - (
231 : departBwdArrivalDir == MSPModel::BACKWARD
232 274719 : ? arrivalPos
233 274719 : : myRoute.back()->getLength() - arrivalPos));
234 : //std::cout << " length=" << length << " lengthFwd=" << lengthFwd << " lengthBwd=" << lengthBwd << " mayStartForward=" << mayStartForward << " mayStartBackward=" << mayStartBackward << "\n";
235 :
236 274719 : if (myRoute.size() == 1) {
237 134187 : if (myDepartPos > myArrivalPos) {
238 : length = lengthBwd;
239 : } else {
240 : length = lengthFwd;
241 : }
242 : } else {
243 140532 : if (mayStartForward && mayStartBackward) {
244 10945 : length = lengthFwd < lengthBwd ? lengthFwd : lengthBwd;
245 129587 : } else if (mayStartForward) {
246 : length = lengthFwd;
247 48074 : } 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 274719 : return MAX2(POSITION_EPS, length);
262 : }
263 :
264 :
265 : SUMOTime
266 110336 : MSStageWalking::getTimeLoss(const MSTransportable* transportable) const {
267 110336 : SUMOTime timeLoss = myArrived == -1 ? 0 : getDuration() - TIME2STEPS(walkDistance(true) / getMaxSpeed(transportable));
268 110336 : if (timeLoss < 0 && timeLoss > TIME2STEPS(-0.1)) {
269 : // avoid negative timeLoss due to rounding errors
270 : timeLoss = 0;
271 : }
272 110336 : return timeLoss;
273 : }
274 :
275 :
276 : void
277 55168 : MSStageWalking::tripInfoOutput(OutputDevice& os, const MSTransportable* const person) const {
278 55168 : 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 55168 : const double distance = walkDistance(true);
283 55168 : const double maxSpeed = getMaxSpeed(person);
284 55168 : const SUMOTime duration = myArrived - myDeparted;
285 55168 : const SUMOTime timeLoss = getTimeLoss(person);
286 55168 : MSDevice_Tripinfo::addPedestrianData(distance, duration, timeLoss);
287 55168 : os.openTag("walk");
288 110336 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
289 55168 : os.writeAttr("departPos", myDepartPos);
290 110336 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
291 110336 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(myArrivalPos) : "-1");
292 165245 : os.writeAttr("duration", myDeparted < 0 ? "-1" :
293 54909 : time2string(myArrived >= 0 ? duration : MSNet::getInstance()->getCurrentTimeStep() - myDeparted));
294 110336 : os.writeAttr("routeLength", myArrived >= 0 ? toString(distance) : "-1");
295 110336 : os.writeAttr("timeLoss", time2string(timeLoss));
296 55168 : os.writeAttr("maxSpeed", maxSpeed);
297 110336 : os.writeAttr("waitingTime", time2string(getTotalWaitingTime()));
298 55168 : os.closeTag();
299 55168 : }
300 :
301 :
302 : void
303 2361 : MSStageWalking::routeOutput(const bool /* isPerson */, OutputDevice& os, const bool withRouteLength, const MSStage* const /* previous */) const {
304 2361 : os.openTag("walk").writeAttr(SUMO_ATTR_EDGES, myRoute);
305 2361 : std::string comment = "";
306 2361 : if (myDestinationStop != nullptr) {
307 431 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
308 431 : if (myDestinationStop->getMyName() != "") {
309 222 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
310 : }
311 1930 : } else if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
312 168 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
313 : }
314 2361 : if (myWalkingTime > 0) {
315 0 : os.writeAttr(SUMO_ATTR_DURATION, time2string(myWalkingTime));
316 2361 : } else if (mySpeed > 0) {
317 24 : os.writeAttr(SUMO_ATTR_SPEED, mySpeed);
318 : }
319 2361 : if (withRouteLength) {
320 36 : if (myDeparted >= 0) {
321 72 : os.writeAttr("routeLength", walkDistance(true));
322 : } else {
323 0 : os.writeAttr("routeLength", "-1");
324 : }
325 : }
326 2361 : if (myExitTimes != nullptr) {
327 : std::vector<std::string> exits;
328 444 : for (SUMOTime t : *myExitTimes) {
329 636 : exits.push_back(time2string(t));
330 : }
331 252 : std::vector<std::string> missing(MAX2(0, (int)myRoute.size() - (int)myExitTimes->size()), "-1");
332 126 : exits.insert(exits.end(), missing.begin(), missing.end());
333 126 : os.writeAttr("exitTimes", exits);
334 126 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
335 126 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
336 126 : }
337 4722 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
338 105 : os.writeAttr(SUMO_ATTR_COST, getCosts());
339 : }
340 2361 : os.closeTag(comment);
341 2361 : }
342 :
343 :
344 : bool
345 994309 : MSStageWalking::moveToNextEdge(MSTransportable* person, SUMOTime currentTime, int prevDir, MSEdge* nextInternal, const bool isReplay) {
346 994309 : ((MSEdge*)getEdge())->removeTransportable(person);
347 994309 : const MSLane* lane = getSidewalk<MSEdge, MSLane>(getEdge());
348 : const bool arrived = myRouteStep == myRoute.end() - 1;
349 994309 : if (lane != nullptr) {
350 974334 : const double tl = person->getVehicleType().getLength();
351 : const double lastPos = (arrived
352 974334 : ? (prevDir == MSPModel::FORWARD
353 284902 : ? getArrivalPos() + tl
354 41260 : : getArrivalPos() - tl)
355 730692 : : person->getPositionOnLane());
356 974334 : activateLeaveReminders(person, lane, lastPos, currentTime, arrived);
357 : }
358 994309 : if (myExitTimes != nullptr && nextInternal == nullptr) {
359 318 : myExitTimes->push_back(currentTime);
360 : }
361 : myMoveReminders.clear();
362 994309 : myLastEdgeEntryTime = currentTime;
363 : //std::cout << SIMTIME << " moveToNextEdge person=" << person->getID() << "\n";
364 994309 : if (myCurrentInternalEdge != nullptr) {
365 394664 : myInternalDistance += (myPState->getPathLength() == 0 ? myCurrentInternalEdge->getLength() : myPState->getPathLength());
366 : }
367 994309 : if (arrived) {
368 243668 : MSPerson* p = dynamic_cast<MSPerson*>(person);
369 243668 : if (!isReplay && p->hasInfluencer() && p->getInfluencer().isRemoteControlled()) {
370 0 : myCurrentInternalEdge = nextInternal;
371 0 : ((MSEdge*) getEdge())->addTransportable(person);
372 0 : return false;
373 : }
374 243668 : if (myDestinationStop != nullptr) {
375 32418 : myDestinationStop->addTransportable(person);
376 : }
377 243668 : if (isReplay) {
378 : // cannot do this in the replay device because the person might get deleted below
379 40 : MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
380 : }
381 243668 : if (!person->proceed(MSNet::getInstance(), currentTime)) {
382 237225 : MSNet::getInstance()->getPersonControl().erase(person);
383 : }
384 : //std::cout << " end walk. myRouteStep=" << (*myRouteStep)->getID() << "\n";
385 243668 : return true;
386 : } else {
387 750641 : if (nextInternal == nullptr) {
388 : ++myRouteStep;
389 : }
390 750641 : myCurrentInternalEdge = nextInternal;
391 750641 : ((MSEdge*) getEdge())->addTransportable(person);
392 750641 : return false;
393 : }
394 : }
395 :
396 :
397 : void
398 1015788 : MSStageWalking::activateEntryReminders(MSTransportable* person, const bool isDepart) {
399 1015788 : const MSLane* const nextLane = getSidewalk<MSEdge, MSLane>(getEdge());
400 1015788 : if (nextLane != nullptr) {
401 1963556 : for (MSMoveReminder* const rem : nextLane->getMoveReminders()) {
402 1554048 : if (rem->notifyEnter(*person, isDepart ? MSMoveReminder::NOTIFICATION_DEPARTED : MSMoveReminder::NOTIFICATION_JUNCTION, nextLane)) {
403 19044 : myMoveReminders.push_back(rem);
404 : }
405 : }
406 : }
407 2031576 : if (hasParameter("rerouter")) {
408 : double minDist = std::numeric_limits<double>::max();
409 : MSTriggeredRerouter* nearest = nullptr;
410 190 : for (MSMoveReminder* const rem : myMoveReminders) {
411 120 : MSTriggeredRerouter* rerouter = dynamic_cast<MSTriggeredRerouter*>(rem);
412 120 : if (rerouter != nullptr) {
413 70 : const double dist2 = rerouter->getPosition().distanceSquaredTo2D(person->getPosition());
414 70 : if (dist2 < minDist) {
415 : nearest = rerouter;
416 : minDist = dist2;
417 : }
418 : }
419 : }
420 70 : if (nearest != nullptr) {
421 70 : nearest->triggerRouting(*person, MSMoveReminder::NOTIFICATION_JUNCTION);
422 : }
423 : // TODO maybe removal of the reminders? Or can we rely on movetonextedge to clean everything up?
424 : }
425 1015788 : }
426 :
427 :
428 : void
429 0 : MSStageWalking::activateMoveReminders(MSTransportable* person, double oldPos, double newPos, double newSpeed) {
430 0 : for (std::vector<MSMoveReminder*>::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
431 0 : if ((*rem)->notifyMove(*person, oldPos, newPos, newSpeed)) {
432 : ++rem;
433 : } else {
434 0 : rem = myMoveReminders.erase(rem);
435 : }
436 : }
437 0 : }
438 :
439 :
440 : void
441 974334 : MSStageWalking::activateLeaveReminders(MSTransportable* person, const MSLane* lane, double lastPos, SUMOTime t, bool arrived) {
442 974334 : MSMoveReminder::Notification notification = arrived ? MSMoveReminder::NOTIFICATION_ARRIVED : MSMoveReminder::NOTIFICATION_JUNCTION;
443 992254 : for (MSMoveReminder* const rem : myMoveReminders) {
444 17920 : rem->updateDetector(*person, 0.0, lane->getLength(), myLastEdgeEntryTime, t, t, true);
445 17920 : rem->notifyLeave(*person, lastPos, notification);
446 : }
447 974334 : }
448 :
449 :
450 : int
451 448840 : MSStageWalking::getRoutePosition() const {
452 448840 : return (int)(myRouteStep - myRoute.begin());
453 : }
454 :
455 :
456 : double
457 15774480 : MSStageWalking::getMaxSpeed(const MSTransportable* const person) const {
458 15774480 : return mySpeed >= 0 ? mySpeed : person->getMaxSpeed();
459 : }
460 :
461 : std::string
462 0 : MSStageWalking::getStageSummary(const bool /* isPerson */) const {
463 0 : const std::string dest = (getDestinationStop() == nullptr ?
464 0 : " edge '" + getDestination()->getID() + "'" :
465 0 : " stop '" + getDestinationStop()->getID() + "'" + (
466 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
467 0 : return "walking to " + dest;
468 : }
469 :
470 :
471 : void
472 19 : MSStageWalking::saveState(std::ostringstream& out) {
473 38 : out << " " << myDeparted << " " << (myRouteStep - myRoute.begin()) << " " << myLastEdgeEntryTime;
474 19 : myPState->saveState(out);
475 19 : }
476 :
477 :
478 : void
479 24 : MSStageWalking::loadState(MSTransportable* transportable, std::istringstream& state) {
480 : int stepIdx;
481 24 : state >> myDeparted >> stepIdx >> myLastEdgeEntryTime;
482 24 : myRouteStep = myRoute.begin() + stepIdx;
483 24 : myPState = MSNet::getInstance()->getPersonControl().getMovementModel()->loadState(transportable, this, state);
484 24 : if (myPState->getLane() && !myPState->getLane()->isNormal()) {
485 1 : myCurrentInternalEdge = &myPState->getLane()->getEdge();
486 1 : myCurrentInternalEdge->addTransportable(transportable);
487 : } else {
488 23 : (*myRouteStep)->addTransportable(transportable);
489 : }
490 24 : }
491 :
492 :
493 : /****************************************************************************/
|