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