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