Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSPModel_Striping.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2014-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/****************************************************************************/
19// The pedestrian following model (prototype)
20/****************************************************************************/
21#include <config.h>
22
23#include <cmath>
24#include <algorithm>
29#include <microsim/MSNet.h>
30#include <microsim/MSEdge.h>
32#include <microsim/MSLane.h>
33#include <microsim/MSLink.h>
34#include <microsim/MSJunction.h>
37#include <microsim/MSGlobals.h>
40#include "MSPModel_Striping.h"
41
42
43// ===========================================================================
44// DEBUGGING HELPERS
45// ===========================================================================
46//
47#define DEBUGID1 ""
48#define DEBUGID2 ""
49//#define DEBUGCOND(PED) (false)
50//#define DEBUGCOND(PED) ((PED).getPerson()->getID() == DEBUGID1 || (PED).getPerson()->getID() == DEBUGID2)
51#define DEBUGCOND(PED) ((PED).getPerson()->isSelected())
52#define DEBUGCOND2(LANE) ((LANE)->isSelected())
53//#define LOG_ALL 1
54//#define DEBUG_MOVETOXY
55
57 for (int i = 0; i < (int)obs.size(); ++i) {
58 std::cout
59 << "(" << obs[i].description
60 << " x=(" << obs[i].xBack << "," << obs[i].xFwd
61 << ") s=" << obs[i].speed
62 << ") ";
63 }
64 std::cout << "\n";
65}
66
67// ===========================================================================
68// named (internal) constants
69// ===========================================================================
70
71// distances are comparable with lower values being "more important"
72const double MSPModel_Striping::DIST_FAR_AWAY(10000);
73const double MSPModel_Striping::DIST_BEHIND(1000);
74const double MSPModel_Striping::DIST_OVERLAP(-1);
75
76// ===========================================================================
77// static members
78// ===========================================================================
79
81std::map<const MSEdge*, std::vector<const MSLane*> > MSPModel_Striping::myWalkingAreaFoes;
83
84// model parameters (static to simplify access from class PState
94const double MSPModel_Striping::LOOKAHEAD_SAMEDIR(4.0); // seconds
95const double MSPModel_Striping::LOOKAHEAD_ONCOMING(10.0); // seconds
96const double MSPModel_Striping::LOOKAHEAD_ONCOMING_DIST(10.0); // m
97const double MSPModel_Striping::LOOKAROUND_VEHICLES(60.0); // meters
98const double MSPModel_Striping::LATERAL_PENALTY(-1.); // meters
99const double MSPModel_Striping::OBSTRUCTED_PENALTY(-300000.); // meters
100const double MSPModel_Striping::INAPPROPRIATE_PENALTY(-20000.); // meters
101const double MSPModel_Striping::ONCOMING_CONFLICT_PENALTY(-1000.); // meters
102const double MSPModel_Striping::OBSTRUCTION_THRESHOLD(MSPModel_Striping::OBSTRUCTED_PENALTY * 0.5); // despite obstruction, additional utility may have been added
103const double MSPModel_Striping::SQUEEZE(0.7);
107const double MSPModel_Striping::MAX_WAIT_TOLERANCE(120.); // seconds
109const double MSPModel_Striping::MIN_STARTUP_DIST(0.4); // meters
110
111
112// ===========================================================================
113// MSPModel_Striping method definitions
114// ===========================================================================
115
117 myWalkingAreaDetail = oc.getInt("pedestrian.striping.walkingarea-detail");
119 // configurable parameters
120 stripeWidth = oc.getFloat("pedestrian.striping.stripe-width");
122 if (defaultPedType != nullptr && defaultPedType->getWidth() > stripeWidth) {
123 WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."),
124 DEFAULT_PEDTYPE_ID, defaultPedType->getWidth());
125 }
126
127 dawdling = oc.getFloat("pedestrian.striping.dawdling");
128 minGapToVehicle = oc.getFloat("pedestrian.striping.mingap-to-vehicle");
129 RESERVE_FOR_ONCOMING_FACTOR = oc.getFloat("pedestrian.striping.reserve-oncoming");
130 RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS = oc.getFloat("pedestrian.striping.reserve-oncoming.junctions");
131 RESERVE_FOR_ONCOMING_MAX = oc.getFloat("pedestrian.striping.reserve-oncoming.max");
132
133 jamTime = string2time(oc.getString("pedestrian.striping.jamtime"));
134 if (jamTime <= 0) {
136 }
137 jamTimeCrossing = string2time(oc.getString("pedestrian.striping.jamtime.crossing"));
138 if (jamTimeCrossing <= 0) {
140 }
141 jamTimeNarrow = string2time(oc.getString("pedestrian.striping.jamtime.narrow"));
142 if (jamTimeNarrow <= 0) {
144 }
145 jamFactor = oc.getFloat("pedestrian.striping.jamfactor");
146 myLegacyPosLat = oc.getBool("pedestrian.striping.legacy-departposlat");
147}
148
149
151 myWalkingAreaPaths.clear(); // need to recompute when lane pointers change
152 myWalkingAreaFoes.clear();
153 myMinNextLengths.clear();
154}
155
156
159 if (!transportable->isPerson()) {
160 // containers are not supported (TODO add a warning here?)
161 return nullptr;
162 }
163 MSPerson* person = static_cast<MSPerson*>(transportable);
164 MSNet* net = MSNet::getInstance();
165 if (!myAmActive) {
167 myAmActive = true;
168 }
169 assert(person->getCurrentStageType() == MSStageType::WALKING);
170 const MSLane* lane = stage->checkDepartLane(person->getEdge(), person->getVClass(), stage->getDepartLane(), person->getID());
171 if (lane == nullptr) {
172 const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
173 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
174 WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep()));
175 return nullptr;
176 } else {
177 throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep())));
178 }
179 }
180 PState* ped = new PState(person, stage, lane);
181 myActiveLanes[lane].push_back(ped);
183 return ped;
184}
185
186
188MSPModel_Striping::loadState(MSTransportable* transportable, MSStageMoving* stage, std::istringstream& in) {
189 MSPerson* person = static_cast<MSPerson*>(transportable);
190 MSNet* net = MSNet::getInstance();
191 if (!myAmActive) {
193 myAmActive = true;
194 }
195 PState* ped = new PState(person, stage, &in);
196 myActiveLanes[ped->getLane()].push_back(ped);
198 return ped;
199}
200
201
202int
204 return MAX2(1, (int)floor(lane->getWidth() / stripeWidth));
205}
206
207
208int
210 if (from == nullptr || to == nullptr) {
211 return UNDEFINED_DIRECTION;
212 } else if (from->getLinkTo(to) != nullptr) {
213 return FORWARD;
214 } else if (to->getLinkTo(from) != nullptr) {
215 return BACKWARD;
216 } else {
217 return UNDEFINED_DIRECTION;
218 }
219}
220
221
222void
224 if (myWalkingAreaPaths.size() > 0) {
225 return;
226 }
227 // collect vehicle lanes that cross walkingareas
228 for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
229 const MSEdge* edge = *i;
230 if (!edge->isWalkingArea() && !edge->isCrossing()) {
231 for (MSLane* lane : edge->getLanes()) {
232 for (MSLink* link : lane->getLinkCont()) {
233 if (link->getWalkingAreaFoe() != nullptr) {
234 // link is an exit link
235 myWalkingAreaFoes[&link->getWalkingAreaFoe()->getEdge()].push_back(link->getLaneBefore());
236 //std::cout << " wa=" << link->getWalkingAreaFoe()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
237 }
238 if (link->getWalkingAreaFoeExit() != nullptr) {
239 // link is an exit link
240 myWalkingAreaFoes[&link->getWalkingAreaFoeExit()->getEdge()].push_back(link->getLaneBefore());
241 //std::cout << " wa=" << link->getWalkingAreaFoeExit()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
242 }
243 }
244 }
245 }
246 }
247
248 // build walkingareaPaths
249 for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
251 }
252}
253
254
255void
257 if (edge->isWalkingArea()) {
258 const MSLane* walkingArea = getSidewalk<MSEdge, MSLane>(edge);
259 myMinNextLengths[walkingArea] = walkingArea->getLength();
260 // build all possible paths across this walkingArea
261 // gather all incident lanes
262 std::vector<const MSLane*> lanes;
263 for (const MSEdge* in : edge->getPredecessors()) {
264 if (!in->isTazConnector()) {
265 lanes.push_back(getSidewalk<MSEdge, MSLane>(in));
266 if (lanes.back() == nullptr) {
267 throw ProcessError("Invalid connection from edge '" + in->getID() + "' to walkingarea edge '" + edge->getID() + "'");
268 }
269 }
270 }
271 for (const MSEdge* out : edge->getSuccessors()) {
272 if (!out->isTazConnector()) {
273 lanes.push_back(getSidewalk<MSEdge, MSLane>(out));
274 if (lanes.back() == nullptr) {
275 throw ProcessError("Invalid connection from walkingarea edge '" + edge->getID() + "' to edge '" + out->getID() + "'");
276 }
277 }
278 }
279 // build all combinations
280 for (int j = 0; j < (int)lanes.size(); ++j) {
281 for (int k = 0; k < (int)lanes.size(); ++k) {
282 if (j != k) {
283 // build the walkingArea
284 const MSLane* const from = lanes[j];
285 const MSLane* const to = lanes[k];
286 const int fromDir = from->getLinkTo(walkingArea) != nullptr ? FORWARD : BACKWARD;
287 const int toDir = walkingArea->getLinkTo(to) != nullptr ? FORWARD : BACKWARD;
288 PositionVector shape;
289 Position fromPos = from->getShape()[fromDir == FORWARD ? -1 : 0];
290 Position toPos = to->getShape()[toDir == FORWARD ? 0 : -1];
291 const double maxExtent = fromPos.distanceTo2D(toPos) / 4; // prevent sharp corners
292 const double extrapolateBy = MIN2(maxExtent, walkingArea->getWidth() / 2);
293 // assemble shape
294 shape.push_back(fromPos);
295 if (extrapolateBy > POSITION_EPS) {
296 PositionVector fromShp = from->getShape();
297 fromShp.extrapolate(extrapolateBy);
298 shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
299 PositionVector nextShp = to->getShape();
300 nextShp.extrapolate(extrapolateBy);
301 shape.push_back_noDoublePos(toDir == FORWARD ? nextShp.front() : nextShp.back());
302 }
303 shape.push_back_noDoublePos(toPos);
304 if (shape.size() < 2) {
305 PositionVector fromShp = from->getShape();
306 fromShp.extrapolate(1.5 * POSITION_EPS); // noDoublePos requires a difference of POSITION_EPS in at least one coordinate
307 shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
308 assert(shape.size() == 2);
309 } else if (myWalkingAreaDetail > 4) {
310 shape = shape.bezier(myWalkingAreaDetail);
311 }
312 double angleOverride = INVALID_DOUBLE;
313 if (shape.size() >= 4 && shape.length() < walkingArea->getWidth()) {
314 const double aStart = shape.angleAt2D(0);
315 const double aEnd = shape.angleAt2D((int)shape.size() - 2);
316 if (fabs(aStart - aEnd) < DEG2RAD(10)) {
317 angleOverride = (aStart + aEnd) / 2;
318 }
319 }
320 if (fromDir == BACKWARD) {
321 // will be walking backward on walkingArea
322 shape = shape.reverse();
323 }
324 WalkingAreaPath wap = WalkingAreaPath(from, walkingArea, to, shape, fromDir, angleOverride);
325 into.insert(std::make_pair(std::make_pair(from, to), wap));
326 myMinNextLengths[walkingArea] = MIN2(myMinNextLengths[walkingArea], wap.length);
327 }
328 }
329 }
330 }
331}
332
333
336 assert(walkingArea->isWalkingArea());
337 std::vector<const MSLane*> lanes;
338 for (const MSEdge* const pred : walkingArea->getPredecessors()) {
339 lanes.push_back(getSidewalk<MSEdge, MSLane>(pred));
340 }
341 for (const MSEdge* const succ : walkingArea->getSuccessors()) {
342 lanes.push_back(getSidewalk<MSEdge, MSLane>(succ));
343 }
344 if (lanes.size() < 1) {
345 throw ProcessError(TLF("Invalid walkingarea '%' does not allow continuation.", walkingArea->getID()));
346 }
347 return &myWalkingAreaPaths.find(std::make_pair(lanes.front(), lanes.back()))->second;
348}
349
351MSPModel_Striping::guessPath(const MSEdge* walkingArea, const MSEdge* before, const MSEdge* after) {
352 assert(walkingArea->isWalkingArea());
353 const MSLane* swBefore = getSidewalk<MSEdge, MSLane>(before);
354 const MSLane* swAfter = getSidewalk<MSEdge, MSLane>(after);
355 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(swBefore, swAfter));
356 if (pathIt != myWalkingAreaPaths.end()) {
357 return &pathIt->second;
358 }
359 const MSEdgeVector& preds = walkingArea->getPredecessors();
360 const MSEdgeVector& succs = walkingArea->getSuccessors();
361 bool useBefore = swBefore != nullptr && std::find(preds.begin(), preds.end(), before) != preds.end();
362 bool useAfter = swAfter != nullptr && std::find(succs.begin(), succs.end(), after) != succs.end();
363 if (useBefore) {
364 if (useAfter) {
365 return getWalkingAreaPath(walkingArea, swBefore, swAfter);
366 } else if (succs.size() > 0) {
367 // could also try to exploit direction
368 return getWalkingAreaPath(walkingArea, swBefore, getSidewalk<MSEdge, MSLane>(succs.front()));
369 }
370 } else if (useAfter && preds.size() > 0) {
371 // could also try to exploit direction
372 return getWalkingAreaPath(walkingArea, getSidewalk<MSEdge, MSLane>(preds.front()), swAfter);
373 }
374 return getArbitraryPath(walkingArea);
375}
376
377
379MSPModel_Striping::getWalkingAreaPath(const MSEdge* walkingArea, const MSLane* before, const MSLane* after) {
380 assert(walkingArea->isWalkingArea());
381 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(before, after));
382 if (pathIt != myWalkingAreaPaths.end()) {
383 return &pathIt->second;
384 } else {
385 // this can happen in case of moveToXY where before can point anywhere
386 const MSEdgeVector& preds = walkingArea->getPredecessors();
387 if (preds.size() > 0) {
388 const MSEdge* const pred = walkingArea->getPredecessors().front();
389 const auto pathIt2 = myWalkingAreaPaths.find(std::make_pair(getSidewalk<MSEdge, MSLane>(pred), after));
390 assert(pathIt2 != myWalkingAreaPaths.end());
391 return &pathIt2->second;
392 } else {
393 return getArbitraryPath(walkingArea);
394 }
395 }
396}
397
398
399
401MSPModel_Striping::getNextLane(const PState& ped, const MSLane* currentLane, const MSLane* prevLane) {
402 const MSEdge* currentEdge = &currentLane->getEdge();
403 const MSJunction* junction = ped.getDirection() == FORWARD ? currentEdge->getToJunction() : currentEdge->getFromJunction();
404 const MSEdge* nextRouteEdge = ped.getStage()->getNextRouteEdge();
405 const MSLane* nextRouteLane = getSidewalk<MSEdge, MSLane>(nextRouteEdge, ped.getPerson()->getVClass());
406 // result values
407 const MSLane* nextLane = nextRouteLane;
408 const MSLink* link = nullptr;
409 int nextDir = UNDEFINED_DIRECTION;
410
411 //if DEBUGCOND(ped) {
412 // std::cout << " nextRouteLane=" << Named::getIDSecure(nextRouteLane) << " junction=" << junction->getID() << "\n";
413 //}
414 if (nextRouteLane == nullptr && nextRouteEdge != nullptr) {
415 std::string error = "Person '" + ped.getPerson()->getID() + "' could not find sidewalk on edge '" + nextRouteEdge->getID() + "', time="
416 + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".";
417 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
418 WRITE_WARNING(error);
419 nextRouteLane = nextRouteEdge->getLanes().front();
420 } else {
421 throw ProcessError(error);
422 }
423 }
424
425 if (nextRouteLane != nullptr) {
426 if (currentEdge->isInternal()) {
427 assert(junction == currentEdge->getFromJunction());
428 nextDir = junction == nextRouteEdge->getFromJunction() ? FORWARD : BACKWARD;
429 if (nextDir == FORWARD) {
430 nextLane = currentLane->getLinkCont()[0]->getViaLaneOrLane();
431 } else {
432 nextLane = currentLane->getLogicalPredecessorLane();
433 }
434 if DEBUGCOND(ped) {
435 std::cout << " internal\n";
436 }
437 } else if (currentEdge->isCrossing()) {
438 nextDir = ped.getDirection();
439 if (nextDir == FORWARD) {
440 nextLane = currentLane->getLinkCont()[0]->getLane();
441 } else {
442 nextLane = currentLane->getLogicalPredecessorLane();
443 }
444 if DEBUGCOND(ped) {
445 std::cout << " crossing\n";
446 }
447 unregisterCrossingApproach(ped, currentLane);
448 } else if (currentEdge->isWalkingArea()) {
449 ConstMSEdgeVector crossingRoute;
450 // departPos can be 0 because the direction of the walkingArea does not matter
451 // for the arrivalPos, we need to make sure that the route does not deviate across other junctions
452 const int nextRouteEdgeDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
453 const double arrivalPos = (nextRouteEdge == ped.getStage()->getRoute().back()
454 ? ped.getStage()->getArrivalPos()
455 : (nextRouteEdgeDir == FORWARD ? 0 : nextRouteEdge->getLength()));
456 MSEdgeVector prohibited;
457 if (prevLane != nullptr) {
458 prohibited.push_back(&prevLane->getEdge());
459 }
460 MSNet::getInstance()->getPedestrianRouter(0, prohibited).compute(currentEdge, nextRouteEdge, 0, arrivalPos, ped.getStage()->getMaxSpeed(ped.getPerson()), 0, junction, crossingRoute, true);
461 if DEBUGCOND(ped) {
462 std::cout
463 << " nre=" << nextRouteEdge->getID()
464 << " nreDir=" << nextRouteEdgeDir
465 << " aPos=" << arrivalPos
466 << " crossingRoute=" << toString(crossingRoute)
467 << "\n";
468 }
469 if (crossingRoute.size() > 1) {
470 const MSEdge* nextEdge = crossingRoute[1];
471 nextLane = getSidewalk<MSEdge, MSLane>(crossingRoute[1], ped.getPerson()->getVClass());
472 assert((nextEdge->getFromJunction() == junction || nextEdge->getToJunction() == junction));
473 assert(nextLane != prevLane);
474 nextDir = connectedDirection(currentLane, nextLane);
475 if DEBUGCOND(ped) {
476 std::cout << " nextDir=" << nextDir << "\n";
477 }
478 assert(nextDir != UNDEFINED_DIRECTION);
479 if (nextDir == FORWARD) {
480 link = currentLane->getLinkTo(nextLane);
481 } else {
482 link = nextLane->getLinkTo(currentLane);
483 if (nextEdge->isCrossing() && link->getTLLogic() == nullptr) {
484 const MSLane* oppositeWalkingArea = nextLane->getLogicalPredecessorLane();
485 link = oppositeWalkingArea->getLinkTo(nextLane);
486 }
487 }
488 assert(link != nullptr);
489 if (nextLane->isCrossing()) {
490 registerCrossingApproach(ped, nextLane, prevLane);
491 }
492 } else {
493 if DEBUGCOND(ped) {
494 std::cout << SIMTIME
495 << " no route from '" << (currentEdge == nullptr ? "NULL" : currentEdge->getID())
496 << "' to '" << (nextRouteEdge == nullptr ? "NULL" : nextRouteEdge->getID())
497 << "\n";
498 }
499 // check if a direct connection exists (moving onto the walkingarea was the wrong choice)
500 if (ped.getDirection() == FORWARD) {
501 link = prevLane->getLinkTo(nextRouteLane);
502 } else {
503 link = nextRouteLane->getLinkTo(prevLane);
504 }
505 if (link != nullptr) {
506 // leave direction as UNDEFINED_DIRECTION to signal that currentLane must be changed
507 nextLane = link->getViaLaneOrLane();
508 } else {
509 WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
510 + "' from walkingArea '" + currentEdge->getID()
511 + "' to edge '" + nextRouteEdge->getID() + "', time=" +
512 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
513 // error indicated by nextDir == UNDEFINED_DIRECTION
514 nextLane = nextRouteLane;
515 }
516 }
517 } else if (currentEdge == nextRouteEdge) {
518 // strange loop in this route. No need to use walkingArea
519 nextDir = -ped.getDirection();
520 } else {
521 // normal edge. by default use next / previous walking area
522 nextDir = ped.getDirection();
523 nextLane = getNextWalkingArea(currentLane, ped.getDirection(), link);
524 if (nextLane != nullptr) {
525 // walking area found
526 if DEBUGCOND(ped) {
527 std::cout << " next walkingArea " << (nextDir == FORWARD ? "forward" : "backward") << "\n";
528 }
529 } else {
530 // walk forward by default
531 if (junction == nextRouteEdge->getToJunction()) {
532 nextDir = BACKWARD;
533 } else if (junction == nextRouteEdge->getFromJunction()) {
534 nextDir = FORWARD;
535 } else {
536 // topological disconnect, find a direction that makes sense
537 // for the future part of the route
538 ConstMSEdgeVector futureRoute = ped.getStage()->getRoute();
539 futureRoute.erase(futureRoute.begin(), futureRoute.begin() + ped.getStage()->getRoutePosition() + 1);
540 int passedFwd = 0;
541 int passedBwd = 0;
542 canTraverse(FORWARD, futureRoute, passedFwd);
543 canTraverse(BACKWARD, futureRoute, passedBwd);
544 nextDir = (passedFwd >= passedBwd) ? FORWARD : BACKWARD;
545 if DEBUGCOND(ped) {
546 std::cout << " nextEdge=" << nextRouteEdge->getID() << " passedFwd=" << passedFwd << " passedBwd=" << passedBwd << " futureRoute=" << toString(futureRoute) << " nextDir=" << nextDir << "\n";
547 }
548 }
549 // try to use a direct link as fallback
550 // direct links only exist if built explicitly. They are used to model tl-controlled links if there are no crossings
551 if (ped.getDirection() == FORWARD) {
552 link = currentLane->getLinkTo(nextRouteLane);
553 if (link != nullptr) {
554 if DEBUGCOND(ped) {
555 std::cout << " direct forward\n";
556 }
557 nextLane = currentLane->getInternalFollowingLane(nextRouteLane);
558 }
559 } else {
560 link = nextRouteLane->getLinkTo(currentLane);
561 if (link != nullptr) {
562 if DEBUGCOND(ped) {
563 std::cout << " direct backward\n";
564 }
565 nextLane = nextRouteLane->getInternalFollowingLane(currentLane);
566 if (nextLane != nullptr) {
567 // advance to the end of consecutive internal lanes
568 while (nextLane->getLinkCont()[0]->getViaLaneOrLane()->isInternal()) {
569 nextLane = nextLane->getLinkCont()[0]->getViaLaneOrLane();
570 }
571 }
572 }
573 }
574 }
575 if (nextLane == nullptr) {
576 // no internal lane found
577 nextLane = nextRouteLane;
578 if DEBUGCOND(ped) {
579 std::cout << SIMTIME << " no next lane found for " << currentLane->getID() << " dir=" << ped.getDirection() << "\n";
580 }
581 if (usingInternalLanesStatic() && currentLane->getLinkCont().size() > 0) {
582 WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
583 + "' from edge '" + currentEdge->getID()
584 + "' to edge '" + nextRouteEdge->getID() + "', time=" +
585 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
586 }
587 } else if (nextLane->getLength() <= POSITION_EPS) {
588 // internal lane too short
589 // most often this is due to a zero-size junction. However, if
590 // the person needs to pass a crossing we cannot skip ahead
591 if ((nextLane->getCanonicalSuccessorLane() == nullptr
592 || !nextLane->getCanonicalSuccessorLane()->getEdge().isCrossing())
593 && (nextLane->getLogicalPredecessorLane() == nullptr ||
594 !nextLane->getLogicalPredecessorLane()->getEdge().isCrossing())) {
595 //WRITE_WARNING("Person '" + ped.getID()
596 // + "' skips short lane '" + nextLane->getID()
597 // + "' length=" + toString(nextLane->getLength())
598 // + " time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
599 nextLane = nextRouteLane;
600 nextDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
601 }
602 }
603 }
604 }
605 if DEBUGCOND(ped) {
606 std::cout << SIMTIME
607 << " p=" << ped.getPerson()->getID()
608 << " l=" << currentLane->getID()
609 << " nl=" << (nextLane == nullptr ? "NULL" : nextLane->getID())
610 << " nrl=" << (nextRouteLane == nullptr ? "NULL" : nextRouteLane->getID())
611 << " d=" << nextDir
612 << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
613 << " pedDir=" << ped.getDirection()
614 << "\n";
615 }
616 assert(nextLane != 0 || nextRouteLane == 0);
617 return NextLaneInfo(nextLane, link, nextDir);
618}
619
620
621const MSLane*
622MSPModel_Striping::getNextWalkingArea(const MSLane* currentLane, const int dir, const MSLink*& link) {
623 if (dir == FORWARD) {
624 for (const MSLink* const l : currentLane->getLinkCont()) {
625 if (l->getLane()->getEdge().isWalkingArea()) {
626 link = l;
627 return l->getLane();
628 }
629 }
630 } else {
631 const std::vector<MSLane::IncomingLaneInfo>& laneInfos = currentLane->getIncomingLanes();
632 for (std::vector<MSLane::IncomingLaneInfo>::const_iterator it = laneInfos.begin(); it != laneInfos.end(); ++it) {
633 if ((*it).lane->getEdge().isWalkingArea()) {
634 link = (*it).viaLink;
635 return (*it).lane;
636 }
637 }
638 }
639 return nullptr;
640}
641
642
644MSPModel_Striping::getNeighboringObstacles(const Pedestrians& pedestrians, int egoIndex, int stripes) {
645 const PState& ego = *static_cast<PState*>(pedestrians[egoIndex]);
646 const int egoStripe = ego.stripe();
647 Obstacles obs(stripes, Obstacle(ego.getDirection()));
648 std::vector<bool> haveBlocker(stripes, false);
649 for (int index = egoIndex + 1; index < (int)pedestrians.size(); index++) {
650 const PState& p = *static_cast<PState*>(pedestrians[index]);
651 if DEBUGCOND(ego) {
652 std::cout << SIMTIME << " ped=" << ego.getID() << " cur=" << egoStripe << " checking neighbor " << p.getID()
653 << " nCur=" << p.stripe() << " nOth=" << p.otherStripe();
654 }
655 if (!p.isWaitingToEnter() && !p.isJammed()) {
656 const Obstacle o(p);
657 if DEBUGCOND(ego) {
658 std::cout << " dist=" << ego.distanceTo(o) << std::endl;
659 }
660 if (ego.distanceTo(o) == DIST_BEHIND) {
661 break;
662 }
663 if (ego.distanceTo(o) == DIST_OVERLAP) {
664 if (p.stripe() != egoStripe || p.getDirection() != ego.getDirection()) {
665 obs[p.stripe()] = o;
666 haveBlocker[p.stripe()] = true;
667 } else {
668 //std::cout << SIMTIME << " ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe=" << egoStripe << "\n";
669 }
670 if (p.otherStripe() != egoStripe || p.getDirection() != ego.getDirection()) {
671 obs[p.otherStripe()] = o;
672 haveBlocker[p.otherStripe()] = true;
673 } else {
674 //std::cout << SIMTIME << " ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe2=" << egoStripe << "\n";
675 }
676 } else {
677 if (!haveBlocker[p.stripe()]) {
678 obs[p.stripe()] = o;
679 }
680 if (!haveBlocker[p.otherStripe()]) {
681 obs[p.otherStripe()] = o;
682 }
683 }
684 }
685 }
686 if DEBUGCOND(ego) {
687 std::cout << SIMTIME << " ped=" << ego.getPerson()->getID() << " neighObs=";
688 DEBUG_PRINT(obs);
689 }
690 return obs;
691}
692
693
694int
695MSPModel_Striping::getStripeOffset(int origStripes, int destStripes, bool addRemainder) {
696 int offset = (destStripes - origStripes) / 2;
697 if (addRemainder) {
698 offset += (destStripes - origStripes) % 2;
699 }
700 return offset;
701}
702
703
706 MSLane* lane, const MSLane* nextLane, int stripes, int nextDir,
707 double currentLength, int currentDir) {
708 if (nextLanesObs.count(nextLane) == 0) {
709 const double nextLength = nextLane->getEdge().isWalkingArea() ? myMinNextLengths[nextLane] : nextLane->getLength();
710 // figure out the which pedestrians are ahead on the next lane
711 const int nextStripes = numStripes(nextLane);
712 // do not move past the end of the next lane in a single step
713 Obstacles obs(stripes, Obstacle(nextDir == FORWARD ? nextLength : 0, 0, OBSTACLE_NEXTEND, "nextEnd", 0));
714
715 const int offset = getStripeOffset(nextStripes, stripes, currentDir != nextDir && nextStripes > stripes);
716 //std::cout << SIMTIME << " getNextLaneObstacles"
717 // << " nextLane=" << nextLane->getID()
718 // << " nextLength=" << nextLength
719 // << " nextDir=" << nextDir
720 // << " currentLength=" << currentLength
721 // << " currentDir=" << currentDir
722 // << " stripes=" << stripes
723 // << " nextStripes=" << nextStripes
724 // << " offset=" << offset
725 // << "\n";
726 if (nextStripes < stripes) {
727 // some stripes do not continue
728 for (int ii = 0; ii < stripes; ++ii) {
729 if (ii < offset || ii >= nextStripes + offset) {
730 obs[ii] = Obstacle(nextDir == FORWARD ? 0 : nextLength, 0, OBSTACLE_END, "stripeEnd", 0);
731 }
732 }
733 }
734 Pedestrians& pedestrians = getPedestrians(nextLane);
735 if (nextLane->getEdge().isWalkingArea()) {
736 transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
737 // complex transformation into the coordinate system of the current lane
738 // (pedestrians on next lane may walk at arbitrary angles relative to the current lane)
739 double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
740 if ((stripes - nextStripes) % 2 != 0) {
741 lateral_offset += 0.5 * stripeWidth;
742 }
743 nextDir = currentDir;
744 // transform pedestrians into the current coordinate system
745 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
746 const PState& p = *static_cast<PState*>(pedestrians[ii]);
747 if (p.isWaitingToEnter() || p.isJammed()) {
748 continue;
749 }
750 Position pPos = p.getPosition(*p.getStage(), -1);
751 Position relPos = lane->getShape().transformToVectorCoordinates(pPos, true);
752 if (relPos == Position::INVALID) {
753 WRITE_WARNINGF("Could not map position % onto lane '%'", pPos, lane->getID());
754 }
755 const double newY = relPos.y() + lateral_offset;
756 //if (p.getPerson()->getID() == "ped200") std::cout << " ped=" << p.getPerson()->getID() << " relX=" << relPos.x() << " relY=" << newY << " latOff=" << lateral_offset << " s=" << p.stripe(newY) << " os=" << p.otherStripe(newY) << "\n";
757 if ((currentDir == FORWARD && relPos.x() >= lane->getLength()) || (currentDir == BACKWARD && relPos.x() < 0)) {
758 addCloserObstacle(obs, relPos.x(), p.stripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
759 addCloserObstacle(obs, relPos.x(), p.otherStripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
760 }
761 }
762 } else {
763 // simple transformation into the coordinate system of the current lane
764 // (only need to worry about currentDir and nextDir)
765 // XXX consider waitingToEnter on nextLane
766 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(nextDir));
767 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
768 const PState& p = *static_cast<PState*>(pedestrians[ii]);
769 if (p.isWaitingToEnter() || p.isJammed()) {
770 continue;
771 }
772 double newY = p.getPosLat();
773 Obstacle pObs(p);
774 if (nextDir != currentDir) {
775 newY = (nextStripes - 1) * stripeWidth - newY;
776 pObs.speed *= -1;
777 }
778 newY += offset * stripeWidth;
779 const int stripe = p.stripe(newY);
780 if (stripe >= 0 && stripe < stripes) {
781 obs[stripe] = pObs;
782 }
783 const int otherStripe = p.otherStripe(newY);
784 if (otherStripe >= 0 && otherStripe < stripes) {
785 obs[otherStripe] = pObs;
786 }
787 }
788 if (nextLane->getEdge().isCrossing()) {
789 // add vehicle obstacles
790 const MSLink* crossingEntryLink = nextLane->getIncomingLanes().front().viaLink;
791 const bool prio = crossingEntryLink->havePriority() || crossingEntryLink->getTLLogic() != nullptr;
792 addCrossingVehs(nextLane, stripes, offset, nextDir, obs, prio);
793 }
794 if (nextLane->getVehicleNumberWithPartials() > 0) {
795 Obstacles vehObs = getVehicleObstacles(nextLane, nextDir);
796 PState::mergeObstacles(obs, vehObs, nextDir, offset);
797 }
798 transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
799 }
800 nextLanesObs[nextLane] = obs;
801 }
802 return nextLanesObs[nextLane];
803}
804
805void
806MSPModel_Striping::transformToCurrentLanePositions(Obstacles& obs, int currentDir, int nextDir, double currentLength, double nextLength) {
807 for (Obstacle& o : obs) {
808 if (currentDir == FORWARD) {
809 if (nextDir == FORWARD) {
810 o.xFwd += currentLength;
811 o.xBack += currentLength;
812 } else {
813 const double tmp = o.xFwd;
814 o.xFwd = currentLength + nextLength - o.xBack;
815 o.xBack = currentLength + nextLength - tmp;
816 }
817 } else {
818 if (nextDir == FORWARD) {
819 const double tmp = o.xFwd;
820 o.xFwd = -o.xBack;
821 o.xBack = -tmp;
822 } else {
823 o.xFwd -= nextLength;
824 o.xBack -= nextLength;
825 }
826 }
827 }
828}
829
830
831void
832MSPModel_Striping::addCloserObstacle(Obstacles& obs, double x, int stripe, int numStripes, const std::string& id, double width, int dir, ObstacleType type) {
833 if (stripe >= 0 && stripe < numStripes) {
834 if ((dir == FORWARD && x - width / 2. < obs[stripe].xBack) || (dir == BACKWARD && x + width / 2. > obs[stripe].xFwd)) {
835 obs[stripe] = Obstacle(x, 0, type, id, width);
836 }
837 }
838}
839
840void
841MSPModel_Striping::moveInDirection(SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
842 for (ActiveLanes::iterator it_lane = myActiveLanes.begin(); it_lane != myActiveLanes.end(); ++it_lane) {
843 const MSLane* lane = it_lane->first;
844 Pedestrians& pedestrians = it_lane->second;
845 if (pedestrians.size() == 0) {
846 continue;
847 }
848 //std::cout << SIMTIME << ">>> lane=" << lane->getID() << " numPeds=" << pedestrians.size() << "\n";
849 if (lane->getEdge().isWalkingArea()) {
850 const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
851 const double minY = stripeWidth * - 0.5 + NUMERICAL_EPS;
852 const double maxY = stripeWidth * (numStripes(lane) - 0.5) - NUMERICAL_EPS;
853 const WalkingAreaPath* debugPath = nullptr;
854 // need to handle each walkingAreaPath separately and transform
855 // coordinates beforehand
856 std::set<const WalkingAreaPath*, walkingarea_path_sorter> paths;
857 for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
858 const PState* p = static_cast<PState*>(*it);
859 assert(p->myWalkingAreaPath != 0);
860 if (p->getDirection() == dir) {
861 paths.insert(p->myWalkingAreaPath);
862 if DEBUGCOND(*p) {
863 debugPath = p->myWalkingAreaPath;
864 std::cout << SIMTIME << " debugging WalkingAreaPath from=" << debugPath->from->getID() << " to=" << debugPath->to->getID() << " minY=" << minY << " maxY=" << maxY << " latOffset=" << lateral_offset << "\n";
865 }
866 }
867 }
868 const double usableWidth = (numStripes(lane) - 1) * stripeWidth;
869 for (std::set<const WalkingAreaPath*, walkingarea_path_sorter>::iterator it = paths.begin(); it != paths.end(); ++it) {
870 const WalkingAreaPath* path = *it;
871 Pedestrians toDelete;
872 Pedestrians transformedPeds;
873 transformedPeds.reserve(pedestrians.size());
874 for (Pedestrians::iterator it_p = pedestrians.begin(); it_p != pedestrians.end(); ++it_p) {
875 PState* p = static_cast<PState*>(*it_p);
876 if (p->myWalkingAreaPath == path) {
877 transformedPeds.push_back(p);
878 if (path == debugPath) std::cout << " ped=" << p->getPerson()->getID() << " relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
879 << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
880 } else if (p->myWalkingAreaPath->from == path->to && p->myWalkingAreaPath->to == path->from) {
881 if (p->myWalkingAreaPath->dir != path->dir) {
882 // opposite direction is already in the correct coordinate system
883 transformedPeds.push_back(p);
884 if (path == debugPath) std::cout << " ped=" << p->getPerson()->getID() << " relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
885 << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
886 } else {
887 // x position must be reversed
888 PState* tp = new PState(*p);
889 tp->reverse(path->length, usableWidth);
890 toDelete.push_back(tp);
891 transformedPeds.push_back(tp);
892 if (path == debugPath) std::cout << " ped=" << p->getPerson()->getID() << " relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (semi-transformed), vecCoord="
893 << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
894 }
895 } else {
896 const Position relPos = path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1));
897 const double newY = relPos.y() + lateral_offset;
898 if (relPos != Position::INVALID && newY >= minY && newY <= maxY) {
899 PState* tp = new PState(*p);
900 tp->reset(relPos.x(), newY);
901 toDelete.push_back(tp);
902 transformedPeds.push_back(tp);
903 if (path == debugPath) {
904 std::cout << " ped=" << p->getPerson()->getID() << " relX=" << relPos.x() << " relY=" << newY << " (transformed), vecCoord=" << relPos << "\n";
905 }
906 } else {
907 if (path == debugPath) {
908 std::cout << " ped=" << p->getPerson()->getID() << " relX=" << relPos.x() << " relY=" << newY << " (invalid), vecCoord=" << relPos << "\n";
909 }
910 }
911 }
912 }
913 auto itFoe = myWalkingAreaFoes.find(&lane->getEdge());
914 if (itFoe != myWalkingAreaFoes.end()) {
915 // add vehicle foes on paths which cross this walkingarea
916 // translate the vehicle into a number of dummy-pedestrians
917 // that occupy the same space
918 for (const MSLane* foeLane : itFoe->second) {
919 for (auto itVeh = foeLane->anyVehiclesBegin(); itVeh != foeLane->anyVehiclesEnd(); ++itVeh) {
920 const MSVehicle* veh = *itVeh;
921 const double vehWidth = veh->getVehicleType().getWidth();
922 Boundary relCorners;
923 Position relFront = path->shape.transformToVectorCoordinates(veh->getPosition(), true);
924 Position relBack = path->shape.transformToVectorCoordinates(veh->getBackPosition(), true);
925 if (relFront == Position::INVALID) {
926 WRITE_WARNINGF("Could not vehicle '%' front position % onto walkingarea '%' path=%, time=%.",
927 veh->getID(), veh->getPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
928 }
929 if (relBack == Position::INVALID) {
930 WRITE_WARNINGF("Could not vehicle '%' back position % onto walkingarea '%' path=%, time=%.",
931 veh->getID(), veh->getBackPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
932 }
933 PositionVector relCenter;
934 relCenter.push_back(relFront);
935 relCenter.push_back(relBack);
936 relCenter.move2side(vehWidth / 2);
937 relCorners.add(relCenter[0]);
938 relCorners.add(relCenter[1]);
939 relCenter.move2side(-vehWidth);
940 relCorners.add(relCenter[0]);
941 relCorners.add(relCenter[1]);
942 // persons should require less gap than the vehicles to prevent getting stuck
943 // when a vehicles moves towards them
944 relCorners.growWidth(SAFETY_GAP / 2);
945 const double xWidth = relCorners.getWidth();
946 const double vehYmin = MAX2(minY - lateral_offset, relCorners.ymin());
947 const double vehYmax = MIN2(maxY - lateral_offset, relCorners.ymax());
948 const double xCenter = relCorners.getCenter().x();
949 Position yMinPos(xCenter, vehYmin);
950 Position yMaxPos(xCenter, vehYmax);
951 const bool addFront = addVehicleFoe(veh, lane, yMinPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
952 const bool addBack = addVehicleFoe(veh, lane, yMaxPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
953 if (path == debugPath) {
954 std::cout << " veh=" << veh->getID()
955 << " corners=" << relCorners
956 << " xWidth=" << xWidth
957 << " ymin=" << relCorners.ymin()
958 << " ymax=" << relCorners.ymax()
959 << " vehYmin=" << vehYmin
960 << " vehYmax=" << vehYmax
961 << "\n";
962 }
963 if (addFront && addBack) {
964 // add in-between positions
965 const double yDist = vehYmax - vehYmin;
966 for (double dist = stripeWidth; dist < yDist; dist += stripeWidth) {
967 const double relDist = dist / yDist;
968 Position between = (yMinPos * relDist) + (yMaxPos * (1 - relDist));
969 if (path == debugPath) {
970 std::cout << " vehBetween=" << veh->getID() << " pos=" << between << "\n";
971 }
972 addVehicleFoe(veh, lane, between, dir * xWidth, stripeWidth, lateral_offset, minY, maxY, toDelete, transformedPeds);
973 }
974 }
975 }
976 }
977 }
978 moveInDirectionOnLane(transformedPeds, lane, currentTime, changedLane, dir, path == debugPath);
979 arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
980 // clean up
981 for (Pedestrians::iterator it_p = toDelete.begin(); it_p != toDelete.end(); ++it_p) {
982 delete *it_p;
983 }
984 }
985 } else {
986 moveInDirectionOnLane(pedestrians, lane, currentTime, changedLane, dir, false);
987 arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
988 }
989 }
990}
991
992
993bool
994MSPModel_Striping::addVehicleFoe(const MSVehicle* veh, const MSLane* walkingarea, const Position& relPos, double xWidth, double yWidth, double lateral_offset,
995 double minY, double maxY, Pedestrians& toDelete, Pedestrians& transformedPeds) {
996 if (relPos != Position::INVALID) {
997 const double newY = relPos.y() + lateral_offset;
998 if (newY >= minY && newY <= maxY) {
999 PState* tp = new PStateVehicle(veh, walkingarea, relPos.x(), newY, xWidth, yWidth);
1000 //std::cout << SIMTIME << " addVehicleFoe=" << veh->getID() << " rx=" << relPos.x() << " ry=" << newY << " s=" << tp->stripe() << " o=" << tp->otherStripe() << "\n";
1001 toDelete.push_back(tp);
1002 transformedPeds.push_back(tp);
1003 }
1004 return true;
1005 } else {
1006 return false;
1007 }
1008}
1009
1010void
1011MSPModel_Striping::arriveAndAdvance(Pedestrians& pedestrians, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
1012 // advance to the next lane / arrive at destination
1013 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
1014 // can't use iterators because we do concurrent modification
1015 for (int i = 0; i < (int)pedestrians.size(); i++) {
1016 PState* const p = static_cast<PState*>(pedestrians[i]);
1017 if (p->isRemoteControlled()) {
1018 continue;
1019 }
1020 if (p->getDirection() == dir && p->distToLaneEnd() < 0) {
1021 // moveToNextLane may trigger re-insertion (for consecutive
1022 // walks) so erase must be called first
1023 pedestrians.erase(pedestrians.begin() + i);
1024 i--;
1025 p->moveToNextLane(currentTime);
1026 if (p->getLane() != nullptr) {
1027 changedLane.insert(p->getPerson());
1028 myActiveLanes[p->getLane()].push_back(p);
1029 } else {
1030 // end walking stage and destroy PState
1031 p->getStage()->moveToNextEdge(p->getPerson(), currentTime, dir);
1033 }
1034 }
1035 }
1036}
1037
1038
1039void
1040MSPModel_Striping::moveInDirectionOnLane(Pedestrians& pedestrians, const MSLane* lane, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir, bool debug) {
1041 const int stripes = numStripes(lane);
1042 //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
1043 Obstacles obs(stripes, Obstacle(dir)); // continuously updated
1044 NextLanesObstacles nextLanesObs; // continuously updated
1045 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
1046
1047 Obstacles crossingVehs(stripes, Obstacle(dir));
1048 bool hasCrossingVehObs = false;
1049 if (lane->getEdge().isCrossing()) {
1050 // assume that vehicles will brake when already on the crossing
1051 hasCrossingVehObs = addCrossingVehs(lane, stripes, 0, dir, crossingVehs, true);
1052 }
1053
1054 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
1055 PState& p = *static_cast<PState*>(pedestrians[ii]);
1056 UNUSED_PARAMETER(debug);
1057 //if (debug) {
1058 // std::cout << SIMTIME << " CHECKING d=" << dir << " p=" << p.getID() << " relX=" << p.myRelX << " xmin=" << p.getMinX() << " xmax=" << p.getMaxX() << " pdir=" << p.getDirection() << "\n";
1059 //}
1060 Obstacles currentObs = obs;
1061 if (p.getDirection() != dir || changedLane.count(p.getPerson()) != 0 || p.getRemotePosition() != Position::INVALID) {
1062 if (!p.isWaitingToEnter() && !p.isJammed()) {
1063 //if DEBUGCOND(p) {
1064 // std::cout << " obs=" << p.getPerson()->getID() << " y=" << p.getPosLat() << " stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
1065 //}
1066 Obstacle o(p);
1067 if (p.getDirection() != dir && p.getSpeed(*p.getStage()) == 0.) {
1068 // ensure recognition of oncoming
1069 o.speed = (p.getDirection() == FORWARD ? 0.1 : -0.1);
1070 }
1071 if (o.closer(obs[p.stripe()], dir)) {
1072 obs[p.stripe()] = o;
1073 }
1074 if (o.closer(obs[p.otherStripe()], dir)) {
1075 obs[p.otherStripe()] = o;
1076 }
1077 }
1078 continue;
1079 }
1080 if DEBUGCOND(p) {
1081 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " currentObs=";
1082 gDebugFlag1 = true;
1083 DEBUG_PRINT(currentObs);
1084 }
1085 const MSLane* nextLane = p.myNLI.lane;
1086 const MSLink* link = p.myNLI.link;
1087 const double dist = p.distToLaneEnd();
1088 const double speed = p.getStage()->getMaxSpeed(p.getPerson());
1089 if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING_DIST) {
1090 const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
1091 const Obstacles& nextObs = getNextLaneObstacles(
1092 nextLanesObs, lane, nextLane, stripes,
1093 p.myNLI.dir, currentLength, dir);
1094
1095 if DEBUGCOND(p) {
1096 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " nextObs=";
1097 DEBUG_PRINT(nextObs);
1098 }
1099 p.mergeObstacles(currentObs, nextObs);
1100 }
1101 if DEBUGCOND(p) {
1102 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithNext=";
1103 DEBUG_PRINT(currentObs);
1104 }
1105 p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
1106 if DEBUGCOND(p) {
1107 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithNeigh=";
1108 DEBUG_PRINT(currentObs);
1109 }
1110 // time gap to pass the intersection ahead of a vehicle.
1111 const double passingClearanceTime = p.getPerson()->getFloatParam("pedestrian.timegap-crossing");
1112 const double passingLength = p.getLength() + passingClearanceTime * speed;
1113 // check link state
1114 if DEBUGCOND(p) {
1115 gDebugFlag1 = true; // get debug output from MSLink
1116 std::cout << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
1117 << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
1118 }
1119 if (link != nullptr
1120 // only check close before junction, @todo we should take deceleration into account here
1121 && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
1122 // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
1123 && !link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(currentTime), speed, 0, 0, nullptr, p.ignoreRed(link), p.getPerson())) {
1124 // prevent movement passed a closed link
1125 Obstacles closedLink(stripes, Obstacle(p.getEdgePos(0) + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
1126 p.mergeObstacles(currentObs, closedLink);
1127 if DEBUGCOND(p) {
1128 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithTLS=";
1129 DEBUG_PRINT(currentObs);
1130 }
1131 // consider rerouting over another crossing
1132 if (p.myWalkingAreaPath != nullptr) {
1133 // @todo actually another path would be needed starting at the current position
1134 const MSLane* oldNext = p.myNLI.lane;
1136 if (p.myNLI.lane != oldNext) {
1137 unregisterCrossingApproach(p, oldNext);
1138 }
1139 }
1140 }
1141 if DEBUGCOND(p) {
1142 gDebugFlag1 = false;
1143 }
1144 if (&lane->getEdge() == p.getStage()->getDestination() && p.getStage()->getDestinationStop() != nullptr) {
1145 Obstacles arrival;
1147 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
1148 } else {
1149 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
1150 }
1151 p.mergeObstacles(currentObs, arrival);
1152 }
1153
1154 if (lane->getVehicleNumberWithPartials() > 0) {
1155 // react to vehicles on the same lane
1156 // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
1157 Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
1158 p.mergeObstacles(currentObs, vehObs);
1159 if DEBUGCOND(p) {
1160 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs=";
1161 DEBUG_PRINT(currentObs);
1162 }
1163 }
1164 if (hasCrossingVehObs) {
1165 p.mergeObstacles(currentObs, crossingVehs);
1166 if DEBUGCOND(p) {
1167 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs2=";
1168 DEBUG_PRINT(currentObs);
1169 }
1170 }
1171
1172 // walk, taking into account all obstacles
1173 p.walk(currentObs, currentTime);
1174 gDebugFlag1 = false;
1175 if (!p.isWaitingToEnter() && !p.isJammed()) {
1176 Obstacle o(p);
1177 if (o.closer(obs[p.stripe()], dir)) {
1178 obs[p.stripe()] = o;
1179 }
1180 if (o.closer(obs[p.otherStripe()], dir)) {
1181 obs[p.otherStripe()] = o;
1182 }
1183 if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.isJammed()) {
1184 for (int coll = 0; coll < ii; ++coll) {
1185 PState& c = *static_cast<PState*>(pedestrians[coll]);
1186 if (!c.isWaitingToEnter() && c.myWalkingAreaPath == nullptr && !c.isJammed()) {
1187 if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
1188 Obstacle cObs(c);
1189 // we check only for real collisions, no min gap violations
1190 if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
1191 WRITE_WARNING("Collision of person '" + p.getPerson()->getID() + "' and person '" + c.getPerson()->getID()
1192 + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
1193 }
1194 }
1195 }
1196 }
1197 }
1198 }
1199 //std::cout << SIMTIME << p.getPerson()->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
1200 }
1201}
1202
1203
1204void
1205MSPModel_Striping::registerCrossingApproach(const PState& ped, const MSLane* crossing, const MSLane* beforeWA) {
1206 // person has entered the walkingarea
1207 SUMOTime arrivalTime = SIMSTEP;
1208 assert(ped.getLane()->isWalkingArea());
1209 const WalkingAreaPath* wa = getWalkingAreaPath(&ped.getLane()->getEdge(), beforeWA, crossing);
1210 const double speed = ped.getStage()->getMaxSpeed(ped.getPerson()) * (1 - dawdling / 2);
1211 arrivalTime += TIME2STEPS(wa->length / speed);
1212 SUMOTime leavingTime = arrivalTime + TIME2STEPS(crossing->getLength() / speed);
1213 crossing->getIncomingLanes()[0].viaLink->setApproachingPerson(ped.getPerson(), arrivalTime, leavingTime);
1214 if DEBUGCOND(ped) {
1215 std::cout << SIMTIME << " register " << ped.getPerson()->getID() << " at crossing " << crossing->getID() << "\n";
1216 }
1217}
1218
1219
1220bool
1221MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio) {
1222 bool hasCrossingVehObs = false;
1223 const MSLink* crossingExitLink = crossing->getLinkCont().front();
1224 gDebugFlag1 = DEBUGCOND2(crossing);
1225 const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
1226 gDebugFlag1 = false;
1227 if (linkLeaders.size() > 0) {
1228 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
1229 // the vehicle to enter the junction first has priority
1230 const MSVehicle* veh = (*it).vehAndGap.first;
1231 if (veh != nullptr) {
1232 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
1233 // block entry to the crossing in walking direction but allow leaving it
1234 Obstacle voBlock = vo;
1235 if (dir == FORWARD) {
1236 voBlock.xBack = NUMERICAL_EPS;
1237 } else {
1238 voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
1239 }
1240 // when approaching a priority crossings, vehicles must be able
1241 // to brake, otherwise the person must be able to cross in time
1242 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
1243 const double bGap = (prio
1245 : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
1246 double vehYmin;
1247 double vehYmax;
1248 // relY increases from left to right (the other way around from vehicles)
1249 if ((*it).fromLeft()) {
1250 vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
1251 vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
1252 vehYmin -= minGapToVehicle;
1253 } else {
1254 vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
1255 vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
1256 vehYmax += minGapToVehicle;
1257
1258 }
1259 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
1260 if ((dir == FORWARD && obs[s].xBack > vo.xBack)
1261 || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
1262 if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
1263 // do not enter the crossing
1264 obs[s] = voBlock;
1265 } else {
1266 obs[s] = vo;
1267 }
1268 hasCrossingVehObs = true;
1269 }
1270 }
1271 if (DEBUGCOND2(crossing)) {
1272 std::cout << SIMTIME
1273 << " crossingVeh=" << veh->getID()
1274 << " lane=" << crossing->getID()
1275 << " prio=" << prio
1276 << " latOffset=" << lateral_offset
1277 << " dir=" << dir
1278 << " stripes=" << stripes
1279 << " dist=" << (*it).distToCrossing
1280 << " gap=" << (*it).vehAndGap.second
1281 << " brakeGap=" << bGap
1282 << " fromLeft=" << (*it).fromLeft()
1283 << " distToCrossBefore=" << distToCrossBeforeVeh
1284 << " ymin=" << vehYmin
1285 << " ymax=" << vehYmax
1286 << " smin=" << PState::stripe(vehYmin)
1287 << " smax=" << PState::stripe(vehYmax)
1288 << "\n";
1289 DEBUG_PRINT(obs);
1290 }
1291 }
1292 }
1293 if (hasCrossingVehObs) {
1294 // check whether the crossing is fully blocked
1295 const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
1296 bool allBlocked = true;
1297
1298 for (int i = 0; i < (int)obs.size(); i++) {
1299 const Obstacle& o = obs[i];
1300 if (o.type != OBSTACLE_VEHICLE && (
1301 (dir == FORWARD && i >= reserved) ||
1302 (dir == BACKWARD && i < (int)obs.size() - reserved))) {
1303 allBlocked = false;
1304 break;
1305 }
1306 }
1307 if (allBlocked) {
1308 if (DEBUGCOND2(crossing)) {
1309 std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
1310 }
1311 for (Obstacle& o : obs) {
1312 if (dir == FORWARD) {
1313 o.xBack = NUMERICAL_EPS;
1314 } else {
1315 o.xFwd = crossing->getLength() - NUMERICAL_EPS;
1316 }
1317 }
1318 }
1319 }
1320 }
1321 return hasCrossingVehObs;
1322}
1323
1324
1327 const int stripes = numStripes(lane);
1328 Obstacles vehObs(stripes, Obstacle(dir));
1329 int current = -1;
1330 double minX = 0.;
1331 double maxX = 0.;
1332 double pRelY = -1.;
1333 double pWidth = 0.;
1334 std::string pID;
1335 bool debug = DEBUGCOND2(lane);
1336 if (ped != nullptr) {
1337 current = ped->stripe();
1338 minX = ped->getMinX();
1339 maxX = ped->getMaxX();
1340 pRelY = ped->getPosLat();
1341 pWidth = ped->getPerson()->getVehicleType().getWidth();
1342 pID = ped->getPerson()->getID();
1343 debug = DEBUGCOND(*ped);
1344 } else if (dir == BACKWARD) {
1345 // checking vehicles on the next lane. Use entry point as reference
1346 minX = lane->getLength();
1347 maxX = lane->getLength();
1348 }
1351 for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
1352 const MSVehicle* veh = *it;
1353 const bool bidi = veh->getLane() == lane->getBidiLane();
1354 const double vehBack = veh->getBackPositionOnLane(lane);
1355 double vehFront = vehBack + veh->getVehicleType().getLength();
1356 // ensure that vehicles are not blocked
1357 const double vehNextSpeed = veh->getWaitingTime() > DELTA_T ? 0 : MAX2(veh->getSpeed(), 1.0);
1358 const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
1359 // boundaries for range checking
1360 double vehXMax;
1361 double vehXMin;
1362 double vehXMaxCheck;
1363 double vehXMinCheck;
1364 if (bidi) {
1365 vehFront = vehBack - veh->getVehicleType().getLength();
1366 vehXMax = vehBack + SAFETY_GAP;
1367 vehXMin = vehFront - clearance;
1368 if (dir == FORWARD) {
1369 vehXMaxCheck = vehBack + NUMERICAL_EPS;
1370 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
1371 } else {
1372 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
1373 vehXMinCheck = vehFront - clearance;
1374 }
1375 } else {
1376 vehXMax = vehFront + clearance;
1377 vehXMin = vehBack - SAFETY_GAP;
1378 if (dir == FORWARD) {
1379 vehXMaxCheck = vehFront + clearance;
1380 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
1381 } else {
1382 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
1383 vehXMinCheck = vehBack - NUMERICAL_EPS;
1384 }
1385 }
1386 if (debug) {
1387 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
1388 << "\n"
1389 << " vehXMin=" << vehXMin
1390 << " vehXMax=" << vehXMax
1391 << " vehXMinC=" << vehXMinCheck
1392 << " vehXMaxC=" << vehXMaxCheck
1393 << " minX=" << minX
1394 << " maxX=" << maxX
1395 << " bidi=" << bidi
1396 << " vFront=" << vehFront
1397 << " vBack=" << vehBack
1398 << "\n";
1399 }
1400 if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
1401 Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
1402 // moving vehicles block space along their path
1403 vo.xFwd = vehXMax;
1404 vo.xBack = vehXMin;
1405 // relY increases from left to right (the other way around from vehicles)
1406 // XXX lateral offset for partial vehicles
1407 const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
1408 const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
1409 const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
1410 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
1411 Obstacle prior = vehObs[s];
1412 vehObs[s] = vo;
1413 if (s == current && vehFront + SAFETY_GAP < minX) {
1414 // ignore if already overlapping while vehicle is still behind
1415 if (pRelY - pWidth < vehYmax &&
1416 pRelY + pWidth > vehYmin && dir == FORWARD) {
1417 if (debug) {
1418 std::cout << " ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
1419 }
1420 if (dir == FORWARD) {
1421 vehObs[s] = prior;
1422 } else {
1423 vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
1424 }
1425 }
1426 }
1427 }
1428 if (debug) {
1429 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
1430 << "\n"
1431 << " ymin=" << vehYmin
1432 << " ymax=" << vehYmax
1433 << " smin=" << PState::stripe(vehYmin)
1434 << " smax=" << PState::stripe(vehYmax)
1435 << " relY=" << pRelY
1436 << " current=" << current
1437 << " vo.xFwd=" << vo.xFwd
1438 << " vo.xBack=" << vo.xBack
1439 << " vFront=" << vehFront
1440 << " vBack=" << vehBack
1441 << "\n";
1442 }
1443 }
1444 }
1445 return vehObs;
1446}
1447
1448
1449// ===========================================================================
1450// MSPModel_Striping::Obstacle method definitions
1451// ===========================================================================
1453 xFwd(dir * dist), // by default, far away when seen in dir
1454 xBack(dir * dist), // by default, far away when seen in dir
1455 speed(0),
1456 type(OBSTACLE_NONE),
1457 description("") {
1458}
1459
1460
1462 xFwd(ped.getMaxX()),
1463 xBack(ped.getMinX()),
1464 speed(ped.getDirection() * ped.getSpeed(*ped.getStage())),
1465 type(ped.getOType()),
1466 description(ped.getID()) {
1467 assert(!ped.isWaitingToEnter());
1468 if (type == OBSTACLE_VEHICLE) {
1469 vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
1470 }
1471}
1472
1473
1474bool
1476 if (dir == FORWARD) {
1477 return xBack <= o.xBack;
1478 } else {
1479 return xFwd >= o.xFwd;
1480 }
1481}
1482
1483
1484// ===========================================================================
1485// MSPModel_Striping::PState method definitions
1486// ===========================================================================
1488 MSPModel_InteractingState(person, stage, lane),
1489 myWalkingAreaPath(nullptr) {
1490 const MSEdge* currentEdge = &lane->getEdge();
1491 const ConstMSEdgeVector& route = myStage->getRoute();
1492 assert(!route.empty());
1493 myDir = FORWARD;
1494 if (route.size() == 1) {
1495 // only a single edge, move towards end pos
1497 } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
1498 // start on an intersection
1499 if (route.front()->isWalkingArea()) {
1500 myWalkingAreaPath = getArbitraryPath(route.front());
1501 }
1502 } else {
1503 int passedFwd = 0;
1504 int passedBwd = 0;
1505 const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
1506 const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
1507 if DEBUGCOND(*this) {
1508 std::cout << " initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
1509 }
1510 if (mayStartForward && mayStartBackward) {
1511 // figure out the best direction via routing
1512 ConstMSEdgeVector crossingRoute;
1513 MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myEdgePos, myStage->getArrivalPos(), myStage->getMaxSpeed(person), 0, nullptr, crossingRoute, true);
1514 if (crossingRoute.size() > 1) {
1515 // route found
1516 const MSEdge* nextEdge = crossingRoute[1];
1517 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
1518 myDir = BACKWARD;
1519 }
1520 }
1521 if DEBUGCOND(*this) {
1522 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
1523 }
1524 } else if (!mayStartForward && !mayStartBackward) {
1525 int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
1526 std::string dLoc;
1527 if (route.size() > 2) {
1528 dLoc = TLF(" between edge '%' and edge '%'", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID());
1529 }
1530 WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%, time=%."),
1531 myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc, SIMTIME);
1532 myDir = passedFwd >= passedBwd ? FORWARD : BACKWARD;
1533 } else {
1534 myDir = !mayStartBackward ? FORWARD : BACKWARD;
1535 }
1536 }
1539 myPosLat = 0;
1540 }
1541 if (lane->getVehicleNumberWithPartials() > 0 && myPosLat == 0) {
1542 // better start next to the road if nothing was specified
1544 }
1545 if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
1546 // start at the right side of the sidewalk on shared roads
1547 myPosLat = stripeWidth * (numStripes(lane) - 1) - myPosLat;
1548 }
1549 } else if (myPosLat == RANDOM_POS_LAT) {
1550 myPosLat = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
1551 } else {
1552 // vehicle to striping coordinate system
1554 }
1555 if DEBUGCOND(*this) {
1556 std::cout << " added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myEdgePos=" << myEdgePos << " myPosLat=" << myPosLat << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
1557 }
1558
1559 myNLI = getNextLane(*this, lane, nullptr);
1560}
1561
1562
1563MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in) :
1564 MSPModel_InteractingState(person, stage, nullptr),
1565 myWalkingAreaPath(nullptr) {
1566 if (in != nullptr) {
1567 std::string laneID;
1568 std::string wapLaneFrom;
1569 std::string wapLaneTo;
1570 std::string nextLaneID;
1571 std::string nextLinkFrom;
1572 std::string nextLinkTo;
1573 int nextDir;
1574
1575 (*in) >> laneID
1577 >> wapLaneFrom >> wapLaneTo
1578 >> myAmJammed
1579 >> nextLaneID
1580 >> nextLinkFrom
1581 >> nextLinkTo
1582 >> nextDir;
1583
1584
1585 myLane = MSLane::dictionary(laneID);
1586 if (myLane == nullptr) {
1587 throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1588 }
1589
1590 MSLane* nextLane = nullptr;
1591 if (nextLaneID != "null") {
1592 nextLane = MSLane::dictionary(nextLaneID);
1593 if (nextLane == nullptr) {
1594 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1595 }
1596 }
1597 const MSLink* link = nullptr;
1598 if (nextLinkFrom != "null") {
1599 MSLane* from = MSLane::dictionary(nextLinkFrom);
1600 MSLane* to = MSLane::dictionary(nextLinkTo);
1601 if (from == nullptr) {
1602 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1603 }
1604 if (to == nullptr) {
1605 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1606 }
1607 link = from->getLinkTo(to);
1608 }
1609 myNLI = NextLaneInfo(nextLane, link, nextDir);
1610
1611 if (wapLaneFrom != "null") {
1612 MSLane* from = MSLane::dictionary(wapLaneFrom);
1613 MSLane* to = MSLane::dictionary(wapLaneTo);
1614 if (from == nullptr) {
1615 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1616 }
1617 if (to == nullptr) {
1618 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1619 }
1620 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
1621 if (pathIt != myWalkingAreaPaths.end()) {
1622 myWalkingAreaPath = &pathIt->second;
1623 } else {
1624 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1625 }
1626 }
1627 }
1628}
1629
1630
1633
1634
1635void
1637 std::string wapLaneFrom = "null";
1638 std::string wapLaneTo = "null";
1639 if (myWalkingAreaPath != nullptr) {
1640 wapLaneFrom = myWalkingAreaPath->from->getID();
1641 wapLaneTo = myWalkingAreaPath->to->getID();
1642 }
1643 std::string nextLaneID = "null";
1644 std::string nextLinkFrom = "null";
1645 std::string nextLinkTo = "null";
1646 if (myNLI.lane != nullptr) {
1647 nextLaneID = myNLI.lane->getID();
1648 }
1649 if (myNLI.link != nullptr) {
1650 nextLinkFrom = myNLI.link->getLaneBefore()->getID();
1651 nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
1652 }
1653 out << " " << myLane->getID()
1654 << " " << myEdgePos
1655 << " " << myPosLat
1656 << " " << myDir
1657 << " " << mySpeed
1658 << " " << mySpeedLat
1659 << " " << myWaitingToEnter
1660 << " " << myWaitingTime
1661 << " " << wapLaneFrom
1662 << " " << wapLaneTo
1663 << " " << myAmJammed
1664 << " " << nextLaneID
1665 << " " << nextLinkFrom
1666 << " " << nextLinkTo
1667 << " " << myNLI.dir;
1668}
1669
1670double
1671MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
1672 // @todo speed should have an influence here because faster persons need more space
1673 if (myDir == FORWARD) {
1674 return myEdgePos - getLength();
1675 }
1676 return myEdgePos - (includeMinGap ? getMinGap() : 0.);
1677}
1678
1679
1680double
1681MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
1682 // @todo speed should have an influence here because faster persons need more space
1683 if (myDir == FORWARD) {
1684 return myEdgePos + (includeMinGap ? getMinGap() : 0.);
1685 }
1686 return myEdgePos + getLength();
1687}
1688
1689
1690double
1692 return myPerson->getVehicleType().getLength();
1693}
1694
1695
1696double
1698 return myPerson->getVehicleType().getMinGap();
1699}
1700
1701
1702int
1704 return (int)floor(relY / stripeWidth + 0.5);
1705}
1706
1707
1708int
1710 const int s = stripe(relY);
1711 const double offset = relY - s * stripeWidth;
1712 const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
1713 int result;
1714 if (offset > threshold) {
1715 result = s + 1;
1716 } else if (offset < -threshold) {
1717 result = s - 1;
1718 } else {
1719 result = s;
1720 }
1721 //std::cout.setf(std::ios::fixed , std::ios::floatfield);
1722 //std::cout << std::setprecision(5);
1723 //if DEBUGCOND(*this) std::cout << " otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
1724 return result;
1725}
1726
1727int
1729 return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
1730}
1731
1732
1733int
1735 return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
1736}
1737
1738
1739double
1741 if (myStage->getNextRouteEdge() == nullptr) {
1742 return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
1743 (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
1744 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
1745 ? getMinGap() : 0);
1746 } else {
1747 const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
1748 return myDir == FORWARD ? length - myEdgePos : myEdgePos;
1749 }
1750}
1751
1752
1753bool
1755 double dist = distToLaneEnd();
1756 if (DEBUGCOND(*this)) {
1757 std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
1758 }
1759 if (dist <= 0) {
1760 //if (ped.getPerson()->getID() == DEBUG1) {
1761 // std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
1762 //}
1763 //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
1764 //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
1765 const int oldDir = myDir;
1766 const MSLane* oldLane = myLane;
1767 myLane = myNLI.lane;
1768 myDir = myNLI.dir;
1769 const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
1770 if DEBUGCOND(*this) {
1771 std::cout << SIMTIME
1772 << " ped=" << myPerson->getID()
1773 << " moveToNextLane old=" << oldLane->getID()
1774 << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
1775 << " oldDir=" << oldDir
1776 << " newDir=" << myDir
1777 << " myEdgePos=" << myEdgePos
1778 << " dist=" << dist
1779 << "\n";
1780 }
1781 if (myLane == nullptr) {
1782 myEdgePos = myStage->getArrivalPos();
1783 }
1784 // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
1785 if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
1786 myLane = nullptr;
1787 } else {
1788 const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
1789 UNUSED_PARAMETER(arrived);
1790 assert(!arrived);
1791 assert(myDir != UNDEFINED_DIRECTION);
1792 myNLI = getNextLane(*this, myLane, oldLane);
1793 // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
1794 myStage->activateEntryReminders(myPerson);
1795 assert(myNLI.lane != oldLane); // do not turn around
1796 if DEBUGCOND(*this) {
1797 std::cout << " nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
1798 }
1799 if (myLane->getEdge().isWalkingArea()) {
1800 if (myNLI.dir != UNDEFINED_DIRECTION) {
1801 myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
1802 assert(myWalkingAreaPath->shape.size() >= 2);
1803 if DEBUGCOND(*this) {
1804 std::cout << " mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
1805 }
1806 } else if (myNLI.link != nullptr) {
1807 // using direct connection (instead of using walkingarea)
1808 myLane = myNLI.lane;
1809 assert(!myLane->getEdge().isWalkingArea());
1810 myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
1811 myWalkingAreaPath = nullptr;
1812 myNLI = getNextLane(*this, myLane, oldLane);
1813 } else {
1814 // disconnected route. move to the next edge
1815 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
1816 // try to determine direction from topology, otherwise maintain current direction
1817 const MSEdge* currRouteEdge = *myStage->getRouteStep();
1818 const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
1819 if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
1820 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
1821 myDir = BACKWARD;
1822 } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
1823 || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
1824 myDir = FORWARD;
1825 }
1826 myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
1827 myLane = myNLI.lane;
1828 assert(myLane != 0);
1829 assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
1830 myNLI = getNextLane(*this, myLane, oldLane);
1831 myWalkingAreaPath = nullptr;
1832 } else {
1833 throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
1834 }
1835 }
1836 } else {
1837 myWalkingAreaPath = nullptr;
1838 }
1839 // adapt x to fit onto the new lane
1840 // (make sure we do not move past the end of the new lane since that
1841 // lane was not checked for obstacles)
1842 const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
1843 if (-dist > newLength) {
1844 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
1845 // should not happen because the end of myLane should have been an obstacle as well
1846 // (only when the route is broken)
1847 dist = -newLength;
1848 }
1849 if (myDir == BACKWARD) {
1850 myEdgePos = newLength + dist;
1851 } else {
1852 myEdgePos = -dist;
1853 }
1854 if DEBUGCOND(*this) {
1855 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
1856 << " newLength=" << newLength
1857 << " dist=" << dist
1858 << " myEdgePos=" << myEdgePos
1859 << "\n";
1860 }
1861 // adjust to change in direction
1862 if (myDir != oldDir) {
1863 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
1864 }
1865 // adjust to differences in sidewalk width
1866 const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
1867 myPosLat += offset * stripeWidth;
1868 if DEBUGCOND(*this) {
1869 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
1870 << " newLane=" << Named::getIDSecure(myLane)
1871 << " newY=" << myPosLat
1872 << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
1873 << " od=" << oldDir << " nd=" << myDir
1874 << " offset=" << offset << "\n";
1875 }
1876 }
1877 myAngle = std::numeric_limits<double>::max(); // see #9014
1878 return true;
1879 } else {
1880 return false;
1881 }
1882}
1883
1884
1885int
1886MSPModel_Striping::getReserved(int stripes, double factor) {
1887 return MIN2(
1888 (int)floor(stripes * factor),
1890}
1891
1892void
1894 const int stripes = (int)obs.size();
1895 const int sMax = stripes - 1;
1896 assert(stripes == numStripes(myLane));
1897 // account stage-specific max speed but also for normal lane speed limit
1898 // (speed limits on crossings and walkingareas ignored due to #11527)
1899 const double vMax = (myStage->getConfiguredSpeed() >= 0
1900 ? myStage->getConfiguredSpeed()
1901 : (myLane->isNormal() || myLane->isInternal()
1902 ? myLane->getVehicleMaxSpeed(myPerson)
1903 : myStage->getMaxSpeed(myPerson)));
1904 // ultimate goal is to choose the preferred stripe (chosen)
1905 const int current = stripe();
1906 const int other = otherStripe();
1907 // compute distances
1908 std::vector<double> distance(stripes);
1909 for (int i = 0; i < stripes; ++i) {
1910 distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
1911 }
1912 // compute utility for all stripes
1913 std::vector<double> utility(stripes, 0);
1914 // forbid stripes which are blocked and also all stripes behind them
1915 for (int i = 0; i < stripes; ++i) {
1916 if (distance[i] == DIST_OVERLAP) {
1917 if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
1918 utility[i] += OBSTRUCTED_PENALTY;
1919 }
1920 if (i < current) {
1921 for (int j = 0; j <= i; ++j) {
1922 utility[j] += OBSTRUCTED_PENALTY;
1923 }
1924 }
1925 if (i > current) {
1926 for (int j = i; j < stripes; ++j) {
1927 utility[j] += OBSTRUCTED_PENALTY;
1928 }
1929 }
1930 }
1931 }
1932 // forbid a portion of the leftmost stripes (in walking direction).
1933 // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
1934 // may still deadlock in heavy pedestrian traffic
1935 const bool onJunction = myLane->getEdge().isWalkingArea() || myLane->getEdge().isCrossing();
1936 const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
1937 if (myDir == FORWARD) {
1938 for (int i = 0; i < reserved; ++i) {
1939 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1940 }
1941 } else {
1942 for (int i = sMax; i > sMax - reserved; --i) {
1943 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1944 }
1945 }
1946 // adapt utility based on obstacles
1947 for (int i = 0; i < stripes; ++i) {
1948 if (obs[i].speed * myDir < 0) {
1949 // penalize evasion to the left unless the obstacle is a vehicle
1950 if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
1951 utility[i - 1] -= 0.5;
1952 } else if (myDir == BACKWARD && i < sMax) {
1953 utility[i + 1] -= 0.5;
1954 }
1955 }
1956 // compute expected distance achievable by staying on this stripe for a time horizon
1957 const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
1958 const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
1959 const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
1960 if (expectedDist >= 0) {
1961 utility[i] += expectedDist;
1962 } else {
1963 // let only the distance count
1964 utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
1965 }
1966 }
1967 // discourage use of the leftmost stripe (in walking direction) if there are oncoming
1968 if (myDir == FORWARD && obs[0].speed < 0) {
1969 utility[0] += ONCOMING_CONFLICT_PENALTY;
1970 } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
1971 utility[sMax] += ONCOMING_CONFLICT_PENALTY;
1972 }
1973 // penalize lateral movement (if the current stripe permits walking)
1974 if (distance[current] > 0 && myWaitingTime == 0) {
1975 for (int i = 0; i < stripes; ++i) {
1976 utility[i] += abs(i - current) * LATERAL_PENALTY;
1977 }
1978 }
1979 // walk on the right side on shared space
1980 if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
1981 for (int i = 0; i < stripes; ++i) {
1982 if (i <= current) {
1983 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
1984 }
1985 }
1986 }
1987
1988 // select best stripe
1989 int chosen = current;
1990 for (int i = 0; i < stripes; ++i) {
1991 if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
1992 chosen = i;
1993 }
1994 }
1995 // compute speed components along both axes
1996 const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
1997 double xDist = MIN3(distance[current], distance[other], distance[next]);
1998 if (next != chosen) {
1999 // ensure that we do not collide with an obstacle in the stripe beyond
2000 // next as this might become the 'other' stripe in the next step
2001 const int nextOther = chosen < current ? current - 2 : current + 2;
2002 xDist = MIN2(xDist, distance[nextOther]);
2003 }
2004 // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
2005 const double preferredGap = NUMERICAL_EPS;
2006 double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
2007 if (xSpeed < NUMERICAL_EPS) {
2008 xSpeed = 0.;
2009 }
2010 if (DEBUGCOND(*this)) {
2011 std::cout << " xSpeedPotential=" << xSpeed << "\n";
2012 }
2013 // avoid tiny steps
2014 // XXX pressure from behind?
2015 if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
2016 // unless walking towards a short lane
2017 !(
2018 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
2019 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
2020 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
2021 ) {
2022 xSpeed = 0;
2023 }
2024 if (xSpeed == 0) {
2025 if (DEBUGCOND(*this)) {
2026 std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
2027 << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
2028 << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
2029 << "\n";
2030 }
2031 if (myWaitingTime > ((myLane->getEdge().isCrossing()
2032 // treat shared walkingarea like a crossing to avoid deadlocking vehicles
2033 || (myLane->getEdge().isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
2034 && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
2035 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
2036 || myAmJammed) {
2037 // squeeze slowly through the crowd ignoring others
2038 if (!myAmJammed) {
2040 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
2041 myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
2042 myAmJammed = true;
2043 }
2044 xSpeed = vMax * jamFactor;
2045 }
2046 } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST) {
2047 myAmJammed = false;
2048 }
2049 // dawdling
2050 const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
2051 xSpeed -= dawdle;
2052
2053 // XXX ensure that diagonal speed <= vMax
2054 // avoid deadlocks on narrow sidewalks
2055 //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
2056 // if DEBUGCOND(*this) std::cout << " stepping aside to resolve oncoming deadlock\n";
2057 // xSpeed = POSITION_EPS; // reset myWaitingTime
2058 // if (myDir == FORWARD && chosen < sMax) {
2059 // chosen += 1;
2060 // } else if (myDir == BACKWARD && chosen > 0) {
2061 // chosen -= 1;
2062 // }
2063 //}
2064 const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
2065 double ySpeed = 0;
2066 double yDist = 0;
2067 if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
2068 // don't move laterally if the stripes are blocked
2069 yDist = (chosen * stripeWidth) - myPosLat;
2070 if (fabs(yDist) > NUMERICAL_EPS) {
2071 ySpeed = (yDist > 0 ?
2072 MIN2(maxYSpeed, DIST2SPEED(yDist)) :
2073 MAX2(-maxYSpeed, DIST2SPEED(yDist)));
2074 }
2075 } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
2076 // still on the road
2077 && stripe() == stripe(myPosLat)
2078 // only when the vehicle is moving on the same lane
2079 && !(myLane->getEdge().isCrossing() || myLane->getEdge().isWalkingArea())) {
2080 // step aside to let the vehicle pass
2081 int stepAsideDir = myDir;
2082 if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
2083 // always step to the right on multi-lane edges or when closer to
2084 // the right side
2085 stepAsideDir = FORWARD;
2086 }
2087 myAmJammed = true; // ignore pedestrian-pedestrian collisions
2088 ySpeed = stepAsideDir * vMax;
2089 }
2090
2091 // DEBUG
2092 if DEBUGCOND(*this) {
2093 std::cout << SIMTIME
2094 << " ped=" << myPerson->getID()
2095 << " edge=" << myStage->getEdge()->getID()
2096 << " x=" << myEdgePos
2097 << " y=" << myPosLat
2098 << " d=" << myDir
2099 << " pvx=" << mySpeed
2100 << " cur=" << current
2101 << " cho=" << chosen
2102 << " oth=" << other
2103 << " nxt=" << next
2104 << " vx=" << xSpeed
2105 << " dawdle=" << dawdle
2106 << " vy=" << ySpeed
2107 << " xd=" << xDist
2108 << " yd=" << yDist
2109 << " vMax=" << vMax
2110 << " wTime=" << myStage->getWaitingTime(currentTime)
2111 << " jammed=" << myAmJammed
2112 << "\n";
2113 if (DEBUGCOND(*this)) {
2114 for (int i = 0; i < stripes; ++i) {
2115 const Obstacle& o = obs[i];
2116 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
2117 if (o.description != "") {
2118 std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
2119 }
2120 if (i == current) {
2121 std::cout << " current";
2122 }
2123 if (i == other && i != current) {
2124 std::cout << " other";
2125 }
2126 if (i == chosen) {
2127 std::cout << " chosen";
2128 }
2129 if (i == next) {
2130 std::cout << " next";
2131 }
2132 std::cout << "\n";
2133 }
2134 }
2135 }
2136 myEdgePos += SPEED2DIST(xSpeed * myDir);
2137 myPosLat += SPEED2DIST(ySpeed);
2138 mySpeedLat = ySpeed;
2139 mySpeed = xSpeed;
2140 if (xSpeed >= SUMO_const_haltingSpeed) {
2141 myWaitingToEnter = false;
2142 myWaitingTime = 0;
2143 } else {
2144 myWaitingTime += DELTA_T;
2145 }
2146 myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
2147}
2148
2149
2150double
2152 return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
2153 + STEPS2TIME(myStage->getWaitingTime(now)) / MAX_WAIT_TOLERANCE));
2154}
2155
2156
2159 if (myRemoteXYPos != Position::INVALID) {
2160 return myRemoteXYPos;
2161 }
2162 if (myLane == nullptr) {
2163 // pedestrian has already finished
2164 return Position::INVALID;
2165 }
2166 const double lateral_offset = -getLatOffset(); // the minus is hunting me in my dreams but seems to be here for historical reasons
2167 if (myWalkingAreaPath == nullptr) {
2168 return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
2169 } else {
2170 //if DEBUGCOND(*this) {
2171 // std::cout << SIMTIME
2172 // << " getPosition (walkingArea)"
2173 // << " p=" << myPerson->getID()
2174 // << " x=" << myEdgePos
2175 // << " y=" << myPosLat
2176 // << " latOffset=" << lateral_offset
2177 // << " shape=" << myWalkingAreaPath->shape
2178 // << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
2179 // << "\n";
2180 //}
2181 if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
2182 return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
2183 } else {
2184 const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
2185 return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
2186 }
2187 }
2188}
2189
2190
2191double
2193 if (myAngle != std::numeric_limits<double>::max()) {
2194 return myAngle;
2195 }
2196 if (myLane == nullptr) {
2197 // pedestrian has already finished
2198 return 0;
2199 }
2200 if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
2201 return myWalkingAreaPath->angleOverride;
2202 }
2203 const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
2204 double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
2205 double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
2206 if (myDir == MSPModel::BACKWARD) {
2207 angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2208 } else { // myDir == MSPModel::FORWARD
2209 angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2210 }
2211 if (angle > M_PI) {
2212 angle -= 2 * M_PI;
2213 }
2214 myAngle = angle;
2215 return angle;
2216}
2217
2218
2219const MSEdge*
2221 return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
2222}
2223
2224
2225const MSLane*
2227 return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
2228}
2229
2230
2231void
2232MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
2233 myEdgePos = pathLength - myEdgePos;
2234 myPosLat = usableWidth - myPosLat;
2235 myDir = -myWalkingAreaPath->dir;
2236 mySpeedLat = -mySpeedLat;
2237}
2238
2239
2240void
2241MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
2242 myEdgePos = edgePos;
2243 myPosLat = latPos;
2244 myDir = UNDEFINED_DIRECTION; // only an obstacle, speed may be orthogonal to dir
2245 mySpeed = 0.;
2246 mySpeedLat = 0.;
2247}
2248
2249
2250void
2251MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
2252 ConstMSEdgeVector newEdges; // keep route
2253 int routeOffset = 0;
2254 bool laneOnRoute = false;
2255 const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
2256 for (const MSEdge* edge : myStage->getRoute()) {
2257 if (edge == &lane->getEdge()
2258 || edge->getToJunction() == laneOnJunction
2259 || edge->getFromJunction() == laneOnJunction) {
2260 laneOnRoute = true;
2261 break;
2262 }
2263 routeOffset++;
2264 }
2265 if (!laneOnRoute) {
2266 throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
2267 }
2268 Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
2269 if (lane->getEdge().isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
2270 // entered new walkingarea. Determine path to guess position
2271 const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
2272 const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
2273 const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
2274 const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
2275 if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
2276 throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
2277 + "' (fromLane='" + guessed->from->getID()
2278 + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2279 }
2280 // give some slack
2281 lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
2282 pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
2283 }
2284 const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
2285 moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
2286}
2287
2288
2289void
2291 double lanePosLat, double angle, int routeOffset,
2292 const ConstMSEdgeVector& edges, SUMOTime t) {
2294 assert(p == myPerson);
2295 assert(pm != nullptr);
2296 const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
2297 // person already walking in this step. undo this to obtain the previous position
2298 const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
2299 const double tmp = myEdgePos;
2300 myEdgePos = oldX;
2301 Position oldPos = getPosition(*myStage, t);
2302 myEdgePos = tmp;
2303 //if (oldPos == Position::INVALID) {
2304 // oldPos = pos
2305 //}
2306 myAngle = GeomHelper::fromNaviDegree(angle);
2307#ifdef DEBUG_MOVETOXY
2308 std::cout << SIMTIME << " ped=" << p->getID()
2309 << " moveToXY"
2310 << " pos=" << pos
2311 << " lane=" << lane->getID()
2312 << " lanePos=" << lanePos
2313 << " lanePosLat=" << lanePosLat
2314 << " angle=" << angle
2315 << " routeOffset=" << routeOffset
2316 << " edges=" << toString(edges)
2317 << " oldLane=" << Named::getIDSecure(myLane)
2318 << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
2319#endif
2320
2321 if (lane != myLane && myLane != nullptr) {
2322 pm->remove(this);
2323 pm->registerActive();
2324 }
2325 if (lane != nullptr &&
2326 fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
2327 myRemoteXYPos = Position::INVALID;
2328 const MSEdge* old = myStage->getEdge();
2329 const MSLane* oldLane = myLane;
2330 if (lane != myLane) {
2331 // implicitly adds new active lane if necessary
2332 pm->myActiveLanes[lane].push_back(this);
2333 }
2334 if (edges.empty()) {
2335 // map within route
2336 myStage->setRouteIndex(myPerson, routeOffset);
2337 } else {
2338 myStage->replaceRoute(myPerson, edges, routeOffset);
2339 }
2340 if (!lane->getEdge().isNormal()) {
2341 myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
2342 }
2343
2344 myLane = lane;
2345 const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
2346 if (lane->getEdge().isWalkingArea()) {
2347 if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
2348 // entered new walkingarea. Determine path
2349 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
2350#ifdef DEBUG_MOVETOXY
2351 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
2352 << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
2353#endif
2354 }
2355 // lanePos and lanePosLat are matched onto the circumference of the
2356 // walkingarea. Use pos instead
2357 const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
2358 if (relPos == Position::INVALID) {
2359 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
2360 + "' (fromLane='" + myWalkingAreaPath->from->getID()
2361 + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2362 myRemoteXYPos = pos;
2363 } else {
2364 myEdgePos = relPos.x();
2365 myPosLat = lateral_offset + relPos.y();
2366 }
2367 } else {
2368 myWalkingAreaPath = nullptr;
2369 myEdgePos = lanePos;
2370 myPosLat = lateral_offset - lanePosLat;
2371 }
2372 // guess direction
2373 const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
2374 if (myStage->getNextRouteEdge() != nullptr) {
2375 if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
2376 myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
2377 myDir = FORWARD;
2378 } else {
2379 myDir = BACKWARD;
2380 }
2381 } else {
2382 // guess from angle
2383 if (angleDiff <= 90) {
2384 // keep direction
2385 if (myDir == UNDEFINED_DIRECTION) {
2386 myDir = FORWARD;
2387 }
2388 } else {
2389 // change direction
2390 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
2391 }
2392 }
2393 // update next lane info (after guessing direction)
2394 if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
2395 const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
2396 // assume that we will eventually move back onto the sidewalk if
2397 // there is one
2398 myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
2399 myStage->activateEntryReminders(myPerson);
2400#ifdef DEBUG_MOVETOXY
2401 std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
2402#endif
2403 }
2404#ifdef DEBUG_MOVETOXY
2405 std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID() << " newPos=" << myPerson->getPosition()
2406 << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
2407#endif
2408 if (oldLane == myLane) {
2409 mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
2410 } else {
2411 //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
2412 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2413 }
2414 } else {
2415 // map outside the network
2416 myRemoteXYPos = pos;
2417 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2418 }
2419
2420}
2421
2422
2423double
2425 if (myWalkingAreaPath != nullptr) {
2426 return myWalkingAreaPath->length;
2427 } else {
2428 return 0;
2429 }
2430}
2431
2432double
2433MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
2434 // check for overlap
2435 const double maxX = getMaxX(includeMinGap);
2436 const double minX = getMinX(includeMinGap);
2437 //if (DEBUGCOND(*this)) {
2438 // std::cout << std::setprecision(2) << " distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
2439 //}
2440 if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
2441 // avoid blocking by itself on looped route
2442 return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
2443 }
2444 if (myDir == FORWARD) {
2445 return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
2446 } else {
2447 return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
2448 }
2449}
2450
2451
2452void
2454 for (int i = 0; i < (int)into.size(); ++i) {
2455 if (gDebugFlag1) {
2456 std::cout << " i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
2457 << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
2458 << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
2459 }
2460 const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
2461 const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
2462 if (dO < dI) {
2463 into[i] = obs2[i];
2464 } else if (dO == dI
2465 && into[i].type != OBSTACLE_PED
2466 && into[i].type != OBSTACLE_VEHICLE
2467 && (obs2[i].type == OBSTACLE_PED ||
2468 obs2[i].type == OBSTACLE_VEHICLE)) {
2469 into[i] = obs2[i];
2470 }
2471 }
2472}
2473
2474void
2475MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
2476 for (int i = 0; i < (int)into.size(); ++i) {
2477 int i2 = i + offset;
2478 if (i2 >= 0 && i2 < (int)obs2.size()) {
2479 if (dir == FORWARD) {
2480 if (obs2[i2].xBack < into[i].xBack) {
2481 into[i] = obs2[i2];
2482 }
2483 } else {
2484 if (obs2[i2].xFwd > into[i].xFwd) {
2485 into[i] = obs2[i2];
2486 }
2487 }
2488 }
2489 }
2490}
2491
2492
2493bool
2495 if (link->haveRed()) {
2496 const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
2497 if (ignoreRedTime >= 0) {
2498 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2499 if (DEBUGCOND(*this)) {
2500 std::cout << SIMTIME << " ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
2501 }
2502 return ignoreRedTime > redDuration;
2503 } else {
2504 return false;
2505 }
2506 } else {
2507 return false;
2508 }
2509}
2510
2511double
2513 return myPerson->getVehicleType().getWidth();
2514}
2515
2516
2517bool
2519 return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
2520}
2521
2522// ===========================================================================
2523// MSPModel_Striping::PStateVehicle method definitions
2524// ===========================================================================
2525
2526MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
2527 myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
2528 myLane = walkingarea; // to ensure correct limits when calling otherStripe()
2529 // relX is the center but we want it to be the max value if the movement direction is forward
2530 // and the min value otherwise (indicated by xWidth sign)
2531 myEdgePos = relX + xWidth / 2;
2532 myPosLat = relY;
2533}
2534
2535const std::string&
2537 return myVehicle->getID();
2538}
2539
2540double
2542 return myYWidth;
2543}
2544
2545double
2546MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
2547 return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
2548}
2549
2550double
2551MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
2552 return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
2553}
2554
2555// ===========================================================================
2556// MSPModel_Striping::MovePedestrians method definitions
2557// ===========================================================================
2558
2561 std::set<MSPerson*> changedLane;
2562 myModel->moveInDirection(currentTime, changedLane, FORWARD);
2563 myModel->moveInDirection(currentTime, changedLane, BACKWARD);
2564 // DEBUG
2565#ifdef LOG_ALL
2566 for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
2567 const MSLane* lane = it_lane->first;
2568 Pedestrians pedestrians = it_lane->second;
2569 if (pedestrians.size() == 0) {
2570 continue;
2571 }
2572 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
2573 std::cout << SIMTIME << " lane=" << lane->getID();
2574 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
2575 const PState& p = *pedestrians[ii];
2576 std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
2577 }
2578 std::cout << "\n";
2579 }
2580#endif
2581 return DELTA_T;
2582}
long long int SUMOTime
Definition GUI.h:36
#define DEG2RAD(x)
Definition GeomHelper.h:35
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
#define DEBUGCOND2(LANE)
#define DEBUGCOND(PED)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:315
#define TLF(string,...)
Definition MsgHandler.h:317
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMSTEP
Definition SUMOTime.h:61
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
#define DIST2SPEED(x)
Definition SUMOTime.h:47
const std::string DEFAULT_PEDTYPE_ID
@ SVC_PEDESTRIAN
pedestrian
@ SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
bool gDebugFlag1
global utility flags for debugging
Definition StdDefs.cpp:37
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:64
#define UNUSED_PARAMETER(x)
Definition StdDefs.h:30
T MIN3(T a, T b, T c)
Definition StdDefs.h:89
T MIN2(T a, T b)
Definition StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:58
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
Position getCenter() const
Returns the center of the boundary.
Definition Boundary.cpp:112
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition Boundary.cpp:78
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:130
double getWidth() const
Returns the width of the boudary (x-axis)
Definition Boundary.cpp:154
void growWidth(double by)
Increases the width of the boundary (x-axis)
Definition Boundary.cpp:362
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:136
static double naviDegree(const double angle)
static double fromNaviDegree(const double angle)
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:380
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:264
A road/street connecting two junctions.
Definition MSEdge.h:77
static const MSEdgeVector & getAllEdges()
Returns all edges with a numerical id.
Definition MSEdge.cpp:1086
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition MSEdge.h:273
bool isWalkingArea() const
return whether this edge is walking area
Definition MSEdge.h:287
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:263
const MSJunction * getToJunction() const
Definition MSEdge.h:418
double getLength() const
return the length of the edge
Definition MSEdge.h:685
const MSJunction * getFromJunction() const
Definition MSEdge.h:414
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
const MSEdgeVector & getPredecessors() const
Definition MSEdge.h:409
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1258
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gCheck4Accidents
Definition MSGlobals.h:88
The base class for an intersection.
Definition MSJunction.h:58
AnyVehicleIterator is a structure, which manages the iteration through all vehicles on the lane,...
Definition MSLane.h:129
Representation of a lane in the micro simulation.
Definition MSLane.h:84
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction
Definition MSLane.h:495
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition MSLane.h:464
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2668
bool isWalkingArea() const
Definition MSLane.cpp:2562
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:614
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:950
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
const MSLane * getInternalFollowingLane(const MSLane *const) const
returns the internal lane leading to the given lane or nullptr, if there is none
Definition MSLane.cpp:2680
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3215
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3135
AnyVehicleIterator anyVehiclesUpstreamEnd() const
end iterator for iterating over all vehicles touching this lane in upstream direction
Definition MSLane.h:507
bool isNormal() const
Definition MSLane.cpp:2551
bool isCrossing() const
Definition MSLane.cpp:2557
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2414
AnyVehicleIterator anyVehiclesUpstreamBegin() const
begin iterator for iterating over all vehicles touching this lane in upstream direction
Definition MSLane.h:501
AnyVehicleIterator anyVehiclesBegin() const
begin iterator for iterating over all vehicles touching this lane in downstream direction
Definition MSLane.h:489
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4564
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition MSLane.h:560
The simulated network and simulation perfomer.
Definition MSNet.h:89
MSPedestrianRouter & getPedestrianRouter(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition MSNet.cpp:1535
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:185
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:471
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:378
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1189
std::vector< MSPModel_InteractingState * > Pedestrians
Pedestrians & getPedestrians(const MSLane *lane)
retrieves the pedestrian vector for the given lane (may be empty)
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
bool myAmActive
whether an event for pedestrian processing was added
int myNumActivePedestrians
the total number of active pedestrians
void registerActive()
increase the number of active pedestrians
virtual void remove(MSTransportableStateAdapter *state)
remove the specified person from the pedestrian simulation
static void unregisterCrossingApproach(const MSPModel_InteractingState &ped, const MSLane *crossing)
unregister pedestrian approach with the junction model
Container for pedestrian state and individual position update function.
SUMOTime myWaitingTime
the consecutive time spent at speed 0
MSPerson * myPerson
the person who is being represented
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
double myEdgePos
the advancement along the current lane
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
virtual const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
const Position & getRemotePosition() const
return the remote position if being controlled by TraCI or JuPedSim
const MSLane * myLane
the current lane of this pedestrian
double mySpeed
the current walking speed
MSStageMoving * myStage
the current stage of this pedestrian
double myPosLat
the orthogonal shift on the current lane
double mySpeedLat
the current lateral walking speed
bool isWaitingToEnter() const
whether the person still waits to entere the network
bool myWaitingToEnter
whether the pedestrian is waiting to start its walk
const MSLane * getLane() const
the current lane of the transportable
int getDirection() const
return the walking direction (FORWARD, BACKWARD, UNDEFINED_DIRECTION)
bool myAmJammed
whether the person is jammed
double getSpeed(const MSStageMoving &) const
return the current speed of the transportable
bool isJammed() const
whether the transportable is jammed
SUMOTime execute(SUMOTime currentTime)
Executes the command.
Container for pedestrian state and individual position update function.
virtual double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
const WalkingAreaPath * myWalkingAreaPath
the current walkingAreaPath or 0
PState()
constructor for PStateVehicle
double distToLaneEnd() const
the absolute distance to the end of the lane in walking direction (or to the arrivalPos)
void mergeObstacles(Obstacles &into, const Obstacles &obs2)
replace obstacles in the first vector with obstacles from the second if they are closer to me
bool isRemoteControlled() const
whether the person is currently being controlled via TraCI
const MSEdge * getNextEdge(const MSStageMoving &stage) const
return the list of internal edges if the transportable is on an intersection
const MSLane * getNextCrossing() const
placeholder function for the accessing the next crossing
void walk(const Obstacles &obs, SUMOTime currentTime)
perform position update
virtual double getWidth() const
return the person width
void saveState(std::ostringstream &out)
Saves the current state into the given stream.
bool ignoreRed(const MSLink *link) const
whether the pedestrian may ignore a red light
virtual double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
bool moveToNextLane(SUMOTime currentTime)
return whether this pedestrian has passed the end of the current lane and update myRelX if so
void reverse(const double pathLength, const double usableWidth)
double getMinGap() const
return the minimum gap of the pedestrian
void moveToXY(MSPerson *p, Position pos, MSLane *lane, double lanePos, double lanePosLat, double angle, int routeOffset, const ConstMSEdgeVector &edges, SUMOTime t)
try to move transportable to the given position
void moveTo(MSPerson *p, MSLane *lane, double lanePos, double lanePosLat, SUMOTime t)
try to move transportable to the given position
Position getPosition(const MSStageMoving &stage, SUMOTime now) const
return the network coordinate of the transportable
NextLaneInfo myNLI
information about the upcoming lane
double getAngle(const MSStageMoving &stage, SUMOTime now) const
return the current orientation in degrees
double getImpatience(SUMOTime now) const
returns the impatience
void reset(const double edgePos, const double latPos)
double distanceTo(const Obstacle &obs, const bool includeMinGap=true) const
double getLength() const
return the length of the pedestrian
double getPathLength() const
return the total length of the current lane (in particular for on a walkingarea)
double getWidth() const
return the person width
double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
PStateVehicle(const MSVehicle *veh, const MSLane *walkingarea, double relX, double relY, double xWidth, double yWidth)
sorts the persons by position on the lane. If dir is forward, higher x positions come first.
The pedestrian movement model using stripes on sidewalks.
static const double MIN_STARTUP_DIST
the minimum distance to the next obstacle in order to start walking after stopped
static void registerCrossingApproach(const PState &ped, const MSLane *crossing, const MSLane *beforeWA)
register pedestrian approach with the junction model
static double RESERVE_FOR_ONCOMING_FACTOR
fraction of the leftmost lanes to reserve for oncoming traffic
static MinNextLengths myMinNextLengths
static bool addVehicleFoe(const MSVehicle *veh, const MSLane *walkingarea, const Position &relPos, double xWidth, double yWidth, double lateral_offset, double minY, double maxY, Pedestrians &toDelete, Pedestrians &transformedPeds)
MSTransportableStateAdapter * loadState(MSTransportable *transportable, MSStageMoving *stage, std::istringstream &in)
load the state of the given transportable
static double posLatConversion(const double posLat, const double laneWidth)
Convert the striping to the vehicle lateral position and vice versa.
static SUMOTime jamTimeCrossing
void moveInDirection(SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
move all pedestrians forward and advance to the next lane if applicable
static void transformToCurrentLanePositions(Obstacles &o, int currentDir, int nextDir, double currentLength, double nextLength)
static int myWalkingAreaDetail
intermediate points to smooth out lanes within the walkingarea
static const double LOOKAHEAD_SAMEDIR
the distance (in seconds) to look ahead for changing stripes
static double RESERVE_FOR_ONCOMING_MAX
std::map< const MSLane *, Obstacles, ComparatorNumericalIdLess > NextLanesObstacles
static double minGapToVehicle
the safety buffer to vehicles
static NextLaneInfo getNextLane(const PState &ped, const MSLane *currentLane, const MSLane *prevLane)
computes the successor lane for the given pedestrian and sets the link as well as the direction to us...
static const double LOOKAHEAD_ONCOMING_DIST
the distance (in m) to look ahead for obstacles on a subsequent edge
static void initWalkingAreaPaths(const MSNet *net)
static const double LOOKAROUND_VEHICLES
the distance (in m) to look around for vehicles
static const double SQUEEZE
the factor by which pedestrian width is reduced when sqeezing past each other
static SUMOTime jamTimeNarrow
static const WalkingAreaPath * getWalkingAreaPath(const MSEdge *walkingArea, const MSLane *before, const MSLane *after)
void arriveAndAdvance(Pedestrians &pedestrians, SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
handle arrivals and lane advancement
std::map< const MSLane *, double > MinNextLengths
static double RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS
static int getStripeOffset(int origStripes, int destStripes, bool addRemainder)
static const WalkingAreaPath * guessPath(const MSEdge *walkingArea, const MSEdge *before, const MSEdge *after)
static int getReserved(int stripes, double factor)
static SUMOTime jamTime
the time threshold before becoming jammed
static void insertWalkArePaths(const MSEdge *edge, WalkingAreaPaths &into)
creates and inserts all paths into the given map
void moveInDirectionOnLane(Pedestrians &pedestrians, const MSLane *lane, SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir, bool debug)
move pedestrians forward on one lane
static double jamFactor
the factor on speed when jammed
static double stripeWidth
model parameters
static const double MAX_WAIT_TOLERANCE
the time pedestrians take to reach maximum impatience
static Obstacles getVehicleObstacles(const MSLane *lane, int dir, PState *ped=0)
retrieve vehicle obstacles on the given lane
static const double OBSTRUCTED_PENALTY
the utility penalty for obstructed (physically blocking me) stripes (corresponds to meters)
static const MSLane * getNextWalkingArea(const MSLane *currentLane, const int dir, const MSLink *&link)
return the next walkingArea in the given direction
MSTransportableStateAdapter * add(MSTransportable *transportable, MSStageMoving *stage, SUMOTime now)
register the given person as a pedestrian
static const double DIST_OVERLAP
static const WalkingAreaPath * getArbitraryPath(const MSEdge *walkingArea)
return an arbitrary path across the given walkingArea
static const double LATERAL_PENALTY
the utility penalty for moving sideways (corresponds to meters)
std::vector< Obstacle > Obstacles
static const double DIST_BEHIND
MSPModel_Striping(const OptionsCont &oc, MSNet *net)
Constructor (it should not be necessary to construct more than one instance)
static Obstacles getNeighboringObstacles(const Pedestrians &pedestrians, int egoIndex, int stripes)
static bool myLegacyPosLat
use old style departPosLat interpretation
static void addCloserObstacle(Obstacles &obs, double x, int stripe, int numStripes, const std::string &id, double width, int dir, ObstacleType type)
static double dawdling
the factor for random slow-down
static int numStripes(const MSLane *lane)
return the maximum number of pedestrians walking side by side
static const double OBSTRUCTION_THRESHOLD
the minimum utility that indicates obstruction
static bool addCrossingVehs(const MSLane *crossing, int stripes, double lateral_offset, int dir, Obstacles &crossingVehs, bool prio)
add vehicles driving across
static int connectedDirection(const MSLane *from, const MSLane *to)
returns the direction in which these lanes are connectioned or 0 if they are not
static void DEBUG_PRINT(const Obstacles &obs)
static const double LATERAL_SPEED_FACTOR
the fraction of forward speed to be used for lateral movemenk
static const double INAPPROPRIATE_PENALTY
the utility penalty for inappropriate (reserved for oncoming traffic or may violate my min gap) strip...
static const double ONCOMING_CONFLICT_PENALTY
the utility penalty for oncoming conflicts on stripes (corresponds to meters)
static const double LOOKAHEAD_ONCOMING
the distance (in seconds) to look ahead for changing stripes (regarding oncoming pedestrians)
static std::map< const MSEdge *, std::vector< const MSLane * > > myWalkingAreaFoes
const Obstacles & getNextLaneObstacles(NextLanesObstacles &nextLanesObs, const MSLane *lane, const MSLane *nextLane, int stripes, int nextDir, double currentLength, int currentDir)
static const double DIST_FAR_AWAY
std::map< std::pair< const MSLane *, const MSLane * >, const WalkingAreaPath > WalkingAreaPaths
static WalkingAreaPaths myWalkingAreaPaths
store for walkinArea elements
static const int BACKWARD
Definition MSPModel.h:55
static int canTraverse(int dir, const ConstMSEdgeVector &route, int &passedEdges)
Definition MSPModel.cpp:54
static const int FORWARD
Definition MSPModel.h:54
static const double RANDOM_POS_LAT
magic value to encode randomized lateral offset for persons when starting a walk
Definition MSPModel.h:68
static const double SIDEWALK_OFFSET
the offset for computing person positions when walking on edges without a sidewalk
Definition MSPModel.h:62
static const int UNDEFINED_DIRECTION
Definition MSPModel.h:56
static const double UNSPECIFIED_POS_LAT
the default lateral offset for persons when starting a walk
Definition MSPModel.h:65
static const double SAFETY_GAP
Definition MSPModel.h:59
const MSEdge * getDestination() const
returns the destination edge
Definition MSStage.cpp:65
virtual double getArrivalPos() const
Definition MSStage.h:94
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition MSStage.h:85
Position getLanePosition(const MSLane *lane, double at, double offset) const
get position on lane at length at with orthogonal offset
Definition MSStage.cpp:177
virtual int getRoutePosition() const
return index of current edge within route
Definition MSStage.h:196
virtual const MSEdge * getNextRouteEdge() const =0
static const MSLane * checkDepartLane(const MSEdge *edge, SUMOVehicleClass svc, int laneIndex, const std::string &id)
interpret custom depart lane
const std::vector< const MSEdge * > & getRoute() const
int getDepartLane() const
virtual bool moveToNextEdge(MSTransportable *transportable, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)=0
move forward and return whether the transportable arrived
virtual double getMaxSpeed(const MSTransportable *const transportable=nullptr) const =0
the maximum speed of the transportable
int getNumWaitingPersons() const
get number of persons waiting at this stop
int getWaitingCapacity() const
get number of persons that can wait at this stop
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
void registerJammed()
register a jammed transportable
SUMOVehicleClass getVClass() const
Returns the object's access class.
bool isPerson() const
Whether it is a person.
Position getPosition(const double) const
Return current position (x/y, cartesian)
const MSVehicleType & getVehicleType() const
Returns the object's "vehicle" type.
MSStageType getCurrentStageType() const
the current stage type of the transportable
const MSEdge * getEdge() const
Returns the current edge.
abstract base class for managing callbacks to retrieve various state information from the model
Definition MSPModel.h:154
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, SumoRNG *rng=nullptr, bool readOnly=false)
Returns the named vehicle type or a sample from the named distribution.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
const Position getBackPosition() const
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:969
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
A storage for options typed value containers)
Definition OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
double compute(const E *from, const E *to, double departPos, double arrivalPos, double speed, SUMOTime msTime, const N *onlyNode, std::vector< const E * > &into, bool allEdges=false)
Builds the route between the given edges using the minimum effort at the given time The definition of...
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:322
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:276
double x() const
Returns the x-position.
Definition Position.h:55
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:286
double y() const
Returns the y-position.
Definition Position.h:60
A list of positions.
double length() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
PositionVector bezier(int numPoints)
return a bezier interpolation
void push_back_noDoublePos(const Position &p)
insert in back a non double position
PositionVector reverse() const
reverse position vector
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector....
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
double getFloatParam(const std::string &paramName, const bool required=false, const double deflt=INVALID_DOUBLE) const
Retrieve a floating point parameter for the traffic object.
#define M_PI
Definition odrSpiral.cpp:45
int dir
the direction on the next lane
const MSLink * link
the link from the current lane to the next lane
const MSLane * lane
the next lane to be used
information regarding surround Pedestrians (and potentially other things)
double speed
speed relative to lane direction (positive means in the same direction)
double xFwd
maximal position on the current lane in forward direction
Obstacle(int dir, double dist=DIST_FAR_AWAY)
create No-Obstacle
bool closer(const Obstacle &o, int dir)
std::string description
the id / description of the obstacle
const SUMOVehicle * vehicle
a pointer to the vehicle if this obstacle is one
ObstacleType type
whether this obstacle denotes a border, a vehicle or a pedestrian
double xBack
maximal position on the current lane in backward direction