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