Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 242244 : 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 242244 : const std::string& routeID) :
67 : MSStageMoving(MSStageType::WALKING, route, routeID, toStop, speed, departPos, arrivalPos, departPosLat, departLane),
68 242244 : myWalkingTime(walkingTime),
69 242244 : myExitTimes(nullptr),
70 242244 : myInternalDistance(0) {
71 242244 : myDepartPos = SUMOVehicleParameter::interpretEdgePos(departPos, route.front()->getLength(), SUMO_ATTR_DEPARTPOS,
72 484488 : "person '" + personID + "' walking from edge '" + route.front()->getID() + "'");
73 242244 : myArrivalPos = SUMOVehicleParameter::interpretEdgePos(arrivalPos, route.back()->getLength(), SUMO_ATTR_ARRIVALPOS,
74 242244 : "person '" + personID + "' walking to edge '" + route.back()->getID() + "'");
75 242244 : if (walkingTime > 0) {
76 103 : mySpeed = computeAverageSpeed();
77 : }
78 242244 : }
79 :
80 :
81 484356 : MSStageWalking::~MSStageWalking() {
82 242178 : delete myExitTimes;
83 484356 : }
84 :
85 :
86 : MSStage*
87 25638 : MSStageWalking::clone() const {
88 25638 : std::vector<const MSEdge*> route = myRoute;
89 25638 : double departPos = myDepartPos;
90 25638 : double arrivalPos = myArrivalPos;
91 25638 : int departLane = myDepartLane;
92 25638 : 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 25638 : MSStage* clon = new MSStageWalking("dummyID", route, myDestinationStop, myWalkingTime, mySpeed, departPos, arrivalPos, myDepartPosLat, departLane, myRouteID);
108 25638 : clon->setParameters(*this);
109 25638 : return clon;
110 25638 : }
111 :
112 :
113 : void
114 241609 : MSStageWalking::proceed(MSNet* net, MSTransportable* person, SUMOTime now, MSStage* previous) {
115 241609 : myDeparted = now;
116 241609 : myRouteStep = myRoute.begin();
117 241609 : myLastEdgeEntryTime = now;
118 241609 : if (myWalkingTime == 0) {
119 0 : if (!person->proceed(net, now)) {
120 0 : MSNet::getInstance()->getPersonControl().erase(person);
121 : }
122 0 : return;
123 : }
124 241609 : const OptionsCont& oc = OptionsCont::getOptions();
125 241609 : 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 240916 : myDepartPos = previous->getEdgePos(now);
128 481832 : if (oc.getString("pedestrian.model") == "jupedsim") {
129 0 : myDepartPosLat = previous->getEdgePosLat(now);
130 : }
131 240916 : if (myWalkingTime > 0) {
132 77 : mySpeed = computeAverageSpeed();
133 : }
134 : }
135 241609 : MSTransportableControl& pControl = net->getPersonControl();
136 241609 : myPState = pControl.getMovementModel()->add(person, this, now);
137 241605 : if (myPState == nullptr) {
138 8 : pControl.erase(person);
139 8 : return;
140 : }
141 241597 : 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 240086 : activateEntryReminders(person, true);
144 : }
145 483194 : if (oc.getBool("vehroute-output.exit-times")) {
146 126 : myExitTimes = new std::vector<SUMOTime>();
147 : }
148 241597 : (*myRouteStep)->addTransportable(person);
149 : }
150 :
151 :
152 : void
153 1572 : MSStageWalking::abort(MSTransportable*) {
154 1572 : MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
155 1572 : }
156 :
157 :
158 : void
159 19 : MSStageWalking::setSpeed(double speed) {
160 19 : mySpeed = speed;
161 19 : }
162 :
163 :
164 : double
165 180 : MSStageWalking::computeAverageSpeed() const {
166 180 : return walkDistance() / STEPS2TIME(myWalkingTime + 1); // avoid systematic rounding errors
167 : }
168 :
169 :
170 : bool
171 1095441 : MSPerson::isJammed() const {
172 1095441 : MSStageWalking* stage = dynamic_cast<MSStageWalking*>(getCurrentStage());
173 1095441 : if (stage != nullptr) {
174 1095441 : return stage->getPState()->isJammed();
175 : }
176 : return false;
177 : }
178 :
179 :
180 : double
181 272638 : MSStageWalking::walkDistance(bool partial) const {
182 : double length = 0;
183 272638 : auto endIt = partial && myArrived < 0 ? myRouteStep + 1 : myRoute.end();
184 738896 : for (ConstMSEdgeVector::const_iterator i = myRoute.begin(); i != endIt; ++i) {
185 466258 : length += (*i)->getLength();
186 : }
187 272638 : if (myRoute.size() > 1 && MSNet::getInstance()->getPersonControl().getMovementModel()->usingInternalLanes()) {
188 119005 : if (myInternalDistance > 0) {
189 106915 : length += myInternalDistance;
190 : } else {
191 : // use lower bound for distance to pass the intersection
192 48193 : 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 272638 : int dummy = 0;
221 272638 : const int departFwdArrivalDir = MSPModel::canTraverse(MSPModel::FORWARD, myRoute, dummy);
222 272638 : const int departBwdArrivalDir = MSPModel::canTraverse(MSPModel::BACKWARD, myRoute, dummy);
223 272638 : const bool mayStartForward = departFwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
224 272638 : const bool mayStartBackward = departBwdArrivalDir != MSPModel::UNDEFINED_DIRECTION;
225 272638 : const double arrivalPos = partial && myArrived < 0 ? getEdgePos(SIMSTEP) : myArrivalPos;
226 272638 : const double lengthFwd = (length - myDepartPos - (
227 : departFwdArrivalDir == MSPModel::BACKWARD
228 272638 : ? arrivalPos
229 272638 : : myRoute.back()->getLength() - arrivalPos));
230 272638 : const double lengthBwd = (length - (myRoute.front()->getLength() - myDepartPos) - (
231 : departBwdArrivalDir == MSPModel::BACKWARD
232 272638 : ? arrivalPos
233 272638 : : myRoute.back()->getLength() - arrivalPos));
234 : //std::cout << " length=" << length << " lengthFwd=" << lengthFwd << " lengthBwd=" << lengthBwd << " mayStartForward=" << mayStartForward << " mayStartBackward=" << mayStartBackward << "\n";
235 :
236 272638 : if (myRoute.size() == 1) {
237 134008 : if (myDepartPos > myArrivalPos) {
238 : length = lengthBwd;
239 : } else {
240 : length = lengthFwd;
241 : }
242 : } else {
243 138630 : if (mayStartForward && mayStartBackward) {
244 10915 : length = lengthFwd < lengthBwd ? lengthFwd : lengthBwd;
245 127715 : } else if (mayStartForward) {
246 : length = lengthFwd;
247 47808 : } 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 272638 : return MAX2(POSITION_EPS, length);
262 : }
263 :
264 :
265 : SUMOTime
266 108958 : MSStageWalking::getTimeLoss(const MSTransportable* transportable) const {
267 108958 : SUMOTime timeLoss = myArrived == -1 ? 0 : getDuration() - TIME2STEPS(walkDistance(true) / getMaxSpeed(transportable));
268 108958 : if (timeLoss < 0 && timeLoss > TIME2STEPS(-0.1)) {
269 : // avoid negative timeLoss due to rounding errors
270 : timeLoss = 0;
271 : }
272 108958 : return timeLoss;
273 : }
274 :
275 :
276 : void
277 54479 : MSStageWalking::tripInfoOutput(OutputDevice& os, const MSTransportable* const person) const {
278 54479 : 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 54479 : const double distance = walkDistance(true);
283 54479 : const double maxSpeed = getMaxSpeed(person);
284 54479 : const SUMOTime duration = myArrived - myDeparted;
285 54479 : const SUMOTime timeLoss = getTimeLoss(person);
286 54479 : MSDevice_Tripinfo::addPedestrianData(distance, duration, timeLoss);
287 54479 : os.openTag("walk");
288 108958 : os.writeAttr("depart", myDeparted >= 0 ? time2string(myDeparted) : "-1");
289 54479 : os.writeAttr("departPos", myDepartPos);
290 108958 : os.writeAttr("arrival", myArrived >= 0 ? time2string(myArrived) : "-1");
291 108958 : os.writeAttr("arrivalPos", myArrived >= 0 ? toString(myArrivalPos) : "-1");
292 163431 : os.writeAttr("duration", myDeparted < 0 ? "-1" :
293 54473 : time2string(myArrived >= 0 ? duration : MSNet::getInstance()->getCurrentTimeStep() - myDeparted));
294 108958 : os.writeAttr("routeLength", myArrived >= 0 ? toString(distance) : "-1");
295 108958 : os.writeAttr("timeLoss", time2string(timeLoss));
296 54479 : os.writeAttr("maxSpeed", maxSpeed);
297 54479 : os.closeTag();
298 54479 : }
299 :
300 :
301 : void
302 2136 : MSStageWalking::routeOutput(const bool /* isPerson */, OutputDevice& os, const bool withRouteLength, const MSStage* const /* previous */) const {
303 2136 : os.openTag("walk").writeAttr(SUMO_ATTR_EDGES, myRoute);
304 2136 : std::string comment = "";
305 2136 : if (myDestinationStop != nullptr) {
306 310 : os.writeAttr(toString(myDestinationStop->getElement()), myDestinationStop->getID());
307 310 : if (myDestinationStop->getMyName() != "") {
308 186 : comment = " <!-- " + StringUtils::escapeXML(myDestinationStop->getMyName(), true) + " -->";
309 : }
310 1826 : } else if (wasSet(VEHPARS_ARRIVALPOS_SET)) {
311 167 : os.writeAttr(SUMO_ATTR_ARRIVALPOS, myArrivalPos);
312 : }
313 2136 : if (myWalkingTime > 0) {
314 0 : os.writeAttr(SUMO_ATTR_DURATION, time2string(myWalkingTime));
315 2136 : } else if (mySpeed > 0) {
316 24 : os.writeAttr(SUMO_ATTR_SPEED, mySpeed);
317 : }
318 2136 : if (withRouteLength) {
319 36 : if (myDeparted >= 0) {
320 72 : os.writeAttr("routeLength", walkDistance(true));
321 : } else {
322 0 : os.writeAttr("routeLength", "-1");
323 : }
324 : }
325 2136 : if (myExitTimes != nullptr) {
326 : std::vector<std::string> exits;
327 444 : for (SUMOTime t : *myExitTimes) {
328 636 : exits.push_back(time2string(t));
329 : }
330 252 : std::vector<std::string> missing(MAX2(0, (int)myRoute.size() - (int)myExitTimes->size()), "-1");
331 126 : exits.insert(exits.end(), missing.begin(), missing.end());
332 126 : os.writeAttr("exitTimes", exits);
333 126 : os.writeAttr(SUMO_ATTR_STARTED, myDeparted >= 0 ? time2string(myDeparted) : "-1");
334 126 : os.writeAttr(SUMO_ATTR_ENDED, myArrived >= 0 ? time2string(myArrived) : "-1");
335 126 : }
336 4272 : if (OptionsCont::getOptions().getBool("vehroute-output.cost")) {
337 210 : os.writeAttr(SUMO_ATTR_COST, getCosts());
338 : }
339 2136 : os.closeTag(comment);
340 2136 : }
341 :
342 :
343 : bool
344 917301 : MSStageWalking::moveToNextEdge(MSTransportable* person, SUMOTime currentTime, int prevDir, MSEdge* nextInternal, const bool isReplay) {
345 917301 : ((MSEdge*)getEdge())->removeTransportable(person);
346 917301 : const MSLane* lane = getSidewalk<MSEdge, MSLane>(getEdge());
347 : const bool arrived = myRouteStep == myRoute.end() - 1;
348 917301 : if (lane != nullptr) {
349 893839 : const double tl = person->getVehicleType().getLength();
350 : const double lastPos = (arrived
351 893839 : ? (prevDir == MSPModel::FORWARD
352 259590 : ? getArrivalPos() + tl
353 39953 : : getArrivalPos() - tl)
354 674202 : : person->getPositionOnLane());
355 893839 : activateLeaveReminders(person, lane, lastPos, currentTime, arrived);
356 : }
357 917301 : if (myExitTimes != nullptr && nextInternal == nullptr) {
358 318 : myExitTimes->push_back(currentTime);
359 : }
360 : myMoveReminders.clear();
361 917301 : myLastEdgeEntryTime = currentTime;
362 : //std::cout << SIMTIME << " moveToNextEdge person=" << person->getID() << "\n";
363 917301 : if (myCurrentInternalEdge != nullptr) {
364 363392 : myInternalDistance += (myPState->getPathLength() == 0 ? myCurrentInternalEdge->getLength() : myPState->getPathLength());
365 : }
366 917301 : if (arrived) {
367 219663 : MSPerson* p = dynamic_cast<MSPerson*>(person);
368 219663 : if (!isReplay && p->hasInfluencer() && p->getInfluencer().isRemoteControlled()) {
369 0 : myCurrentInternalEdge = nextInternal;
370 0 : ((MSEdge*) getEdge())->addTransportable(person);
371 0 : return false;
372 : }
373 219663 : if (myDestinationStop != nullptr) {
374 31139 : myDestinationStop->addTransportable(person);
375 : }
376 219663 : if (isReplay) {
377 : // cannot do this in the replay device because the person might get deleted below
378 40 : MSNet::getInstance()->getPersonControl().getMovementModel()->remove(myPState);
379 : }
380 219663 : if (!person->proceed(MSNet::getInstance(), currentTime)) {
381 213298 : MSNet::getInstance()->getPersonControl().erase(person);
382 : }
383 : //std::cout << " end walk. myRouteStep=" << (*myRouteStep)->getID() << "\n";
384 219663 : return true;
385 : } else {
386 697638 : if (nextInternal == nullptr) {
387 : ++myRouteStep;
388 : }
389 697638 : myCurrentInternalEdge = nextInternal;
390 697638 : ((MSEdge*) getEdge())->addTransportable(person);
391 697638 : return false;
392 : }
393 : }
394 :
395 :
396 : void
397 893839 : MSStageWalking::activateLeaveReminders(MSTransportable* person, const MSLane* lane, double lastPos, SUMOTime t, bool arrived) {
398 893839 : MSMoveReminder::Notification notification = arrived ? MSMoveReminder::NOTIFICATION_ARRIVED : MSMoveReminder::NOTIFICATION_JUNCTION;
399 911567 : for (MSMoveReminder* const rem : myMoveReminders) {
400 17728 : rem->updateDetector(*person, 0.0, lane->getLength(), myLastEdgeEntryTime, t, t, true);
401 17728 : rem->notifyLeave(*person, lastPos, notification);
402 : }
403 893839 : }
404 :
405 :
406 : void
407 937285 : MSStageWalking::activateEntryReminders(MSTransportable* person, const bool isDepart) {
408 937285 : const MSLane* const nextLane = getSidewalk<MSEdge, MSLane>(getEdge());
409 937285 : if (nextLane != nullptr) {
410 936980 : for (MSMoveReminder* const rem : nextLane->getMoveReminders()) {
411 38187 : if (rem->notifyEnter(*person, isDepart ? MSMoveReminder::NOTIFICATION_DEPARTED : MSMoveReminder::NOTIFICATION_JUNCTION, nextLane)) {
412 18852 : myMoveReminders.push_back(rem);
413 : }
414 : }
415 : }
416 1874570 : if (hasParameter("rerouter")) {
417 : double minDist = std::numeric_limits<double>::max();
418 : MSTriggeredRerouter* nearest = nullptr;
419 190 : for (MSMoveReminder* const rem : myMoveReminders) {
420 120 : MSTriggeredRerouter* rerouter = dynamic_cast<MSTriggeredRerouter*>(rem);
421 120 : if (rerouter != nullptr) {
422 70 : const double dist2 = rerouter->getPosition().distanceSquaredTo2D(person->getPosition());
423 70 : if (dist2 < minDist) {
424 : nearest = rerouter;
425 : minDist = dist2;
426 : }
427 : }
428 : }
429 70 : if (nearest != nullptr) {
430 70 : nearest->triggerRouting(*person, MSMoveReminder::NOTIFICATION_JUNCTION);
431 : }
432 : // TODO maybe removal of the reminders? Or can we rely on movetonextedge to clean everything up?
433 : }
434 937285 : }
435 :
436 :
437 : int
438 448660 : MSStageWalking::getRoutePosition() const {
439 448660 : return (int)(myRouteStep - myRoute.begin());
440 : }
441 :
442 :
443 : double
444 60668706 : MSStageWalking::getMaxSpeed(const MSTransportable* const person) const {
445 60668706 : return mySpeed >= 0 ? mySpeed : person->getMaxSpeed();
446 : }
447 :
448 : std::string
449 0 : MSStageWalking::getStageSummary(const bool /* isPerson */) const {
450 0 : const std::string dest = (getDestinationStop() == nullptr ?
451 0 : " edge '" + getDestination()->getID() + "'" :
452 0 : " stop '" + getDestinationStop()->getID() + "'" + (
453 0 : getDestinationStop()->getMyName() != "" ? " (" + getDestinationStop()->getMyName() + ")" : ""));
454 0 : return "walking to " + dest;
455 : }
456 :
457 :
458 : void
459 19 : MSStageWalking::saveState(std::ostringstream& out) {
460 38 : out << " " << myDeparted << " " << (myRouteStep - myRoute.begin()) << " " << myLastEdgeEntryTime;
461 19 : myPState->saveState(out);
462 19 : }
463 :
464 :
465 : void
466 24 : MSStageWalking::loadState(MSTransportable* transportable, std::istringstream& state) {
467 : int stepIdx;
468 24 : state >> myDeparted >> stepIdx >> myLastEdgeEntryTime;
469 24 : myRouteStep = myRoute.begin() + stepIdx;
470 24 : myPState = MSNet::getInstance()->getPersonControl().getMovementModel()->loadState(transportable, this, state);
471 24 : if (myPState->getLane() && !myPState->getLane()->isNormal()) {
472 1 : myCurrentInternalEdge = &myPState->getLane()->getEdge();
473 1 : myCurrentInternalEdge->addTransportable(transportable);
474 : } else {
475 23 : (*myRouteStep)->addTransportable(transportable);
476 : }
477 24 : }
478 :
479 :
480 : /****************************************************************************/
|