Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSPModel_Striping.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2014-2024 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
19// The pedestrian following model (prototype)
20/****************************************************************************/
21#include <config.h>
22
23#include <cmath>
24#include <algorithm>
29#include <microsim/MSNet.h>
30#include <microsim/MSEdge.h>
32#include <microsim/MSLane.h>
33#include <microsim/MSLink.h>
34#include <microsim/MSJunction.h>
37#include <microsim/MSGlobals.h>
40#include "MSPModel_Striping.h"
41
42
43// ===========================================================================
44// DEBUGGING HELPERS
45// ===========================================================================
46//
47#define DEBUGID1 ""
48#define DEBUGID2 ""
49//#define DEBUGCOND(PED) (false)
50//#define DEBUGCOND(PED) ((PED).getPerson()->getID() == DEBUGID1 || (PED).getPerson()->getID() == DEBUGID2)
51#define DEBUGCOND(PED) ((PED).getPerson()->isSelected())
52#define DEBUGCOND2(LANE) ((LANE)->isSelected())
53//#define LOG_ALL 1
54//#define DEBUG_MOVETOXY
55
57 for (int i = 0; i < (int)obs.size(); ++i) {
58 std::cout
59 << "(" << obs[i].description
60 << " x=(" << obs[i].xBack << "," << obs[i].xFwd
61 << ") s=" << obs[i].speed
62 << ") ";
63 }
64 std::cout << "\n";
65}
66
67// ===========================================================================
68// named (internal) constants
69// ===========================================================================
70
71// distances are comparable with lower values being "more important"
72const double MSPModel_Striping::DIST_FAR_AWAY(10000);
73const double MSPModel_Striping::DIST_BEHIND(1000);
74const double MSPModel_Striping::DIST_OVERLAP(-1);
75
76// ===========================================================================
77// static members
78// ===========================================================================
79
81std::map<const MSEdge*, std::vector<const MSLane*> > MSPModel_Striping::myWalkingAreaFoes;
83
84// model parameters (static to simplify access from class PState
94const double MSPModel_Striping::LOOKAHEAD_SAMEDIR(4.0); // seconds
95const double MSPModel_Striping::LOOKAHEAD_ONCOMING(10.0); // seconds
96const double MSPModel_Striping::LOOKAHEAD_ONCOMING_DIST(10.0); // m
97const double MSPModel_Striping::LOOKAROUND_VEHICLES(60.0); // meters
98const double MSPModel_Striping::LATERAL_PENALTY(-1.); // meters
99const double MSPModel_Striping::OBSTRUCTED_PENALTY(-300000.); // meters
100const double MSPModel_Striping::INAPPROPRIATE_PENALTY(-20000.); // meters
101const double MSPModel_Striping::ONCOMING_CONFLICT_PENALTY(-1000.); // meters
102const double MSPModel_Striping::OBSTRUCTION_THRESHOLD(MSPModel_Striping::OBSTRUCTED_PENALTY * 0.5); // despite obstruction, additional utility may have been added
103const double MSPModel_Striping::SQUEEZE(0.7);
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 MSEdgeVector prohibited;
460 if (prevLane != nullptr) {
461 prohibited.push_back(&prevLane->getEdge());
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(currentTime), 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;
1156 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
1157 } else {
1158 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
1159 }
1160 p.mergeObstacles(currentObs, arrival);
1161 }
1162
1163 if (lane->getVehicleNumberWithPartials() > 0) {
1164 // react to vehicles on the same lane
1165 // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
1166 Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
1167 p.mergeObstacles(currentObs, vehObs);
1168 if DEBUGCOND(p) {
1169 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs=";
1170 DEBUG_PRINT(currentObs);
1171 }
1172 }
1173 if (hasCrossingVehObs) {
1174 p.mergeObstacles(currentObs, crossingVehs);
1175 if DEBUGCOND(p) {
1176 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs2=";
1177 DEBUG_PRINT(currentObs);
1178 }
1179 }
1180
1181 // walk, taking into account all obstacles
1182 p.walk(currentObs, currentTime);
1183 gDebugFlag1 = false;
1184 if (!p.isWaitingToEnter() && !p.isJammed()) {
1185 Obstacle o(p);
1186 if (o.closer(obs[p.stripe()], dir)) {
1187 obs[p.stripe()] = o;
1188 }
1189 if (o.closer(obs[p.otherStripe()], dir)) {
1190 obs[p.otherStripe()] = o;
1191 }
1192 if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.isJammed()) {
1193 for (int coll = 0; coll < ii; ++coll) {
1194 PState& c = *static_cast<PState*>(pedestrians[coll]);
1195 if (!c.isWaitingToEnter() && c.myWalkingAreaPath == nullptr && !c.isJammed()) {
1196 if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
1197 Obstacle cObs(c);
1198 // we check only for real collisions, no min gap violations
1199 if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
1200 WRITE_WARNING("Collision of person '" + p.getPerson()->getID() + "' and person '" + c.getPerson()->getID()
1201 + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
1202 }
1203 }
1204 }
1205 }
1206 }
1207 }
1208 //std::cout << SIMTIME << p.getPerson()->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
1209 }
1210}
1211
1212
1213void
1214MSPModel_Striping::registerCrossingApproach(const PState& ped, const MSLane* crossing, const MSLane* beforeWA) {
1215 // person has entered the walkingarea
1216 SUMOTime arrivalTime = SIMSTEP;
1217 assert(ped.getLane()->isWalkingArea());
1218 const WalkingAreaPath* wa = getWalkingAreaPath(&ped.getLane()->getEdge(), beforeWA, crossing);
1219 const double speed = ped.getStage()->getMaxSpeed(ped.getPerson()) * (1 - dawdling / 2);
1220 arrivalTime += TIME2STEPS(wa->length / speed);
1221 SUMOTime leavingTime = arrivalTime + TIME2STEPS(crossing->getLength() / speed);
1222 crossing->getIncomingLanes()[0].viaLink->setApproachingPerson(ped.getPerson(), arrivalTime, leavingTime);
1223 if DEBUGCOND(ped) {
1224 std::cout << SIMTIME << " register " << ped.getPerson()->getID() << " at crossing " << crossing->getID() << "\n";
1225 }
1226}
1227
1228
1229bool
1230MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio) {
1231 bool hasCrossingVehObs = false;
1232 const MSLink* crossingExitLink = crossing->getLinkCont().front();
1233 gDebugFlag1 = DEBUGCOND2(crossing);
1234 const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
1235 gDebugFlag1 = false;
1236 if (linkLeaders.size() > 0) {
1237 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
1238 // the vehicle to enter the junction first has priority
1239 const MSVehicle* veh = (*it).vehAndGap.first;
1240 if (veh != nullptr) {
1241 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
1242 // block entry to the crossing in walking direction but allow leaving it
1243 Obstacle voBlock = vo;
1244 if (dir == FORWARD) {
1245 voBlock.xBack = NUMERICAL_EPS;
1246 } else {
1247 voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
1248 }
1249 // when approaching a priority crossings, vehicles must be able
1250 // to brake, otherwise the person must be able to cross in time
1251 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
1252 const double bGap = (prio
1254 : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
1255 double vehYmin;
1256 double vehYmax;
1257 // relY increases from left to right (the other way around from vehicles)
1258 if ((*it).fromLeft()) {
1259 vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
1260 vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
1261 vehYmin -= minGapToVehicle;
1262 } else {
1263 vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
1264 vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
1265 vehYmax += minGapToVehicle;
1266
1267 }
1268 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
1269 if ((dir == FORWARD && obs[s].xBack > vo.xBack)
1270 || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
1271 if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
1272 // do not enter the crossing
1273 obs[s] = voBlock;
1274 } else {
1275 obs[s] = vo;
1276 }
1277 hasCrossingVehObs = true;
1278 }
1279 }
1280 if (DEBUGCOND2(crossing)) {
1281 std::cout << SIMTIME
1282 << " crossingVeh=" << veh->getID()
1283 << " lane=" << crossing->getID()
1284 << " prio=" << prio
1285 << " latOffset=" << lateral_offset
1286 << " dir=" << dir
1287 << " stripes=" << stripes
1288 << " dist=" << (*it).distToCrossing
1289 << " gap=" << (*it).vehAndGap.second
1290 << " brakeGap=" << bGap
1291 << " fromLeft=" << (*it).fromLeft()
1292 << " distToCrossBefore=" << distToCrossBeforeVeh
1293 << " ymin=" << vehYmin
1294 << " ymax=" << vehYmax
1295 << " smin=" << PState::stripe(vehYmin)
1296 << " smax=" << PState::stripe(vehYmax)
1297 << "\n";
1298 DEBUG_PRINT(obs);
1299 }
1300 }
1301 }
1302 if (hasCrossingVehObs) {
1303 // check whether the crossing is fully blocked
1304 const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
1305 bool allBlocked = true;
1306
1307 for (int i = 0; i < (int)obs.size(); i++) {
1308 const Obstacle& o = obs[i];
1309 if (o.type != OBSTACLE_VEHICLE && (
1310 (dir == FORWARD && i >= reserved) ||
1311 (dir == BACKWARD && i < (int)obs.size() - reserved))) {
1312 allBlocked = false;
1313 break;
1314 }
1315 }
1316 if (allBlocked) {
1317 if (DEBUGCOND2(crossing)) {
1318 std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
1319 }
1320 for (Obstacle& o : obs) {
1321 if (dir == FORWARD) {
1322 o.xBack = NUMERICAL_EPS;
1323 } else {
1324 o.xFwd = crossing->getLength() - NUMERICAL_EPS;
1325 }
1326 }
1327 }
1328 }
1329 }
1330 return hasCrossingVehObs;
1331}
1332
1333
1336 const int stripes = numStripes(lane);
1337 Obstacles vehObs(stripes, Obstacle(dir));
1338 int current = -1;
1339 double minX = 0.;
1340 double maxX = 0.;
1341 double pRelY = -1.;
1342 double pWidth = 0.;
1343 std::string pID;
1344 bool debug = DEBUGCOND2(lane);
1345 if (ped != nullptr) {
1346 current = ped->stripe();
1347 minX = ped->getMinX();
1348 maxX = ped->getMaxX();
1349 pRelY = ped->getPosLat();
1350 pWidth = ped->getPerson()->getVehicleType().getWidth();
1351 pID = ped->getPerson()->getID();
1352 debug = DEBUGCOND(*ped);
1353 } else if (dir == BACKWARD) {
1354 // checking vehicles on the next lane. Use entry point as reference
1355 minX = lane->getLength();
1356 maxX = lane->getLength();
1357 }
1360 for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
1361 const MSVehicle* veh = *it;
1362 const bool bidi = veh->getLane() == lane->getBidiLane();
1363 const double vehBack = veh->getBackPositionOnLane(lane);
1364 double vehFront = vehBack + veh->getVehicleType().getLength();
1365 // ensure that vehicles are not blocked
1366 const double vehNextSpeed = veh->getWaitingTime() > DELTA_T ? 0 : MAX2(veh->getSpeed(), 1.0);
1367 const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
1368 // boundaries for range checking
1369 double vehXMax;
1370 double vehXMin;
1371 double vehXMaxCheck;
1372 double vehXMinCheck;
1373 if (bidi) {
1374 vehFront = vehBack - veh->getVehicleType().getLength();
1375 vehXMax = vehBack + SAFETY_GAP;
1376 vehXMin = vehFront - clearance;
1377 if (dir == FORWARD) {
1378 vehXMaxCheck = vehBack + NUMERICAL_EPS;
1379 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
1380 } else {
1381 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
1382 vehXMinCheck = vehFront - clearance;
1383 }
1384 } else {
1385 vehXMax = vehFront + clearance;
1386 vehXMin = vehBack - SAFETY_GAP;
1387 if (dir == FORWARD) {
1388 vehXMaxCheck = vehFront + clearance;
1389 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
1390 } else {
1391 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
1392 vehXMinCheck = vehBack - NUMERICAL_EPS;
1393 }
1394 }
1395 if (debug) {
1396 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
1397 << "\n"
1398 << " vehXMin=" << vehXMin
1399 << " vehXMax=" << vehXMax
1400 << " vehXMinC=" << vehXMinCheck
1401 << " vehXMaxC=" << vehXMaxCheck
1402 << " minX=" << minX
1403 << " maxX=" << maxX
1404 << " bidi=" << bidi
1405 << " vFront=" << vehFront
1406 << " vBack=" << vehBack
1407 << "\n";
1408 }
1409 if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
1410 Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
1411 // moving vehicles block space along their path
1412 vo.xFwd = vehXMax;
1413 vo.xBack = vehXMin;
1414 // relY increases from left to right (the other way around from vehicles)
1415 // XXX lateral offset for partial vehicles
1416 const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
1417 const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
1418 const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
1419 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
1420 Obstacle prior = vehObs[s];
1421 vehObs[s] = vo;
1422 if (s == current && vehFront + SAFETY_GAP < minX) {
1423 // ignore if already overlapping while vehicle is still behind
1424 if (pRelY - pWidth < vehYmax &&
1425 pRelY + pWidth > vehYmin && dir == FORWARD) {
1426 if (debug) {
1427 std::cout << " ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
1428 }
1429 if (dir == FORWARD) {
1430 vehObs[s] = prior;
1431 } else {
1432 vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
1433 }
1434 }
1435 }
1436 }
1437 if (debug) {
1438 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
1439 << "\n"
1440 << " ymin=" << vehYmin
1441 << " ymax=" << vehYmax
1442 << " smin=" << PState::stripe(vehYmin)
1443 << " smax=" << PState::stripe(vehYmax)
1444 << " relY=" << pRelY
1445 << " current=" << current
1446 << " vo.xFwd=" << vo.xFwd
1447 << " vo.xBack=" << vo.xBack
1448 << " vFront=" << vehFront
1449 << " vBack=" << vehBack
1450 << "\n";
1451 }
1452 }
1453 }
1454 return vehObs;
1455}
1456
1457
1458// ===========================================================================
1459// MSPModel_Striping::Obstacle method definitions
1460// ===========================================================================
1462 xFwd(dir * dist), // by default, far away when seen in dir
1463 xBack(dir * dist), // by default, far away when seen in dir
1464 speed(0),
1465 type(OBSTACLE_NONE),
1466 description("") {
1467}
1468
1469
1471 xFwd(ped.getMaxX()),
1472 xBack(ped.getMinX()),
1473 speed(ped.getDirection() * ped.getSpeed(*ped.getStage())),
1474 type(ped.getOType()),
1475 description(ped.getID()) {
1476 assert(!ped.isWaitingToEnter());
1477 if (type == OBSTACLE_VEHICLE) {
1478 vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
1479 }
1480}
1481
1482
1483bool
1485 if (dir == FORWARD) {
1486 return xBack <= o.xBack;
1487 } else {
1488 return xFwd >= o.xFwd;
1489 }
1490}
1491
1492
1493// ===========================================================================
1494// MSPModel_Striping::PState method definitions
1495// ===========================================================================
1497 MSPModel_InteractingState(person, stage, lane),
1498 myWalkingAreaPath(nullptr) {
1499 const MSEdge* currentEdge = &lane->getEdge();
1500 const ConstMSEdgeVector& route = myStage->getRoute();
1501 assert(!route.empty());
1502 myDir = FORWARD;
1503 if (route.size() == 1) {
1504 // only a single edge, move towards end pos
1506 } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
1507 // start on an intersection
1508 if (route.front()->isWalkingArea()) {
1509 myWalkingAreaPath = getArbitraryPath(route.front());
1510 }
1511 } else {
1512 int passedFwd = 0;
1513 int passedBwd = 0;
1514 const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
1515 const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
1516 if DEBUGCOND(*this) {
1517 std::cout << " initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
1518 }
1519 if (mayStartForward && mayStartBackward) {
1520 // figure out the best direction via routing
1521 ConstMSEdgeVector crossingRoute;
1522 MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myEdgePos, myStage->getArrivalPos(), myStage->getMaxSpeed(person), 0, nullptr, crossingRoute, true);
1523 if (crossingRoute.size() > 1) {
1524 // route found
1525 const MSEdge* nextEdge = crossingRoute[1];
1526 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
1527 myDir = BACKWARD;
1528 }
1529 }
1530 if DEBUGCOND(*this) {
1531 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
1532 }
1533 } else if (!mayStartForward && !mayStartBackward) {
1534 int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
1535 std::string dLoc;
1536 if (route.size() > 2) {
1537 dLoc = TLF(" between edge '%' and edge '%'", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID());
1538 }
1539 WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%, time=%."),
1540 myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc, SIMTIME);
1541 myDir = passedFwd >= passedBwd ? FORWARD : BACKWARD;
1542 } else {
1543 myDir = !mayStartBackward ? FORWARD : BACKWARD;
1544 }
1545 }
1548 myPosLat = 0;
1549 }
1550 if (lane->getVehicleNumberWithPartials() > 0 && myPosLat == 0) {
1551 // better start next to the road if nothing was specified
1553 }
1554 if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
1555 // start at the right side of the sidewalk on shared roads
1556 myPosLat = stripeWidth * (numStripes(lane) - 1) - myPosLat;
1557 }
1558 } else if (myPosLat == RANDOM_POS_LAT) {
1559 myPosLat = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
1560 } else {
1561 // vehicle to striping coordinate system
1563 }
1564 if DEBUGCOND(*this) {
1565 std::cout << " added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myEdgePos=" << myEdgePos << " myPosLat=" << myPosLat << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
1566 }
1567
1568 myNLI = getNextLane(*this, lane, nullptr);
1569}
1570
1571
1572MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in) :
1573 MSPModel_InteractingState(person, stage, nullptr),
1574 myWalkingAreaPath(nullptr) {
1575 if (in != nullptr) {
1576 std::string laneID;
1577 std::string wapLaneFrom;
1578 std::string wapLaneTo;
1579 std::string nextLaneID;
1580 std::string nextLinkFrom;
1581 std::string nextLinkTo;
1582 int nextDir;
1583
1584 (*in) >> laneID
1586 >> wapLaneFrom >> wapLaneTo
1587 >> myAmJammed
1588 >> nextLaneID
1589 >> nextLinkFrom
1590 >> nextLinkTo
1591 >> nextDir;
1592
1593
1594 myLane = MSLane::dictionary(laneID);
1595 if (myLane == nullptr) {
1596 throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1597 }
1598
1599 MSLane* nextLane = nullptr;
1600 if (nextLaneID != "null") {
1601 nextLane = MSLane::dictionary(nextLaneID);
1602 if (nextLane == nullptr) {
1603 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1604 }
1605 }
1606 const MSLink* link = nullptr;
1607 if (nextLinkFrom != "null") {
1608 MSLane* from = MSLane::dictionary(nextLinkFrom);
1609 MSLane* to = MSLane::dictionary(nextLinkTo);
1610 if (from == nullptr) {
1611 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1612 }
1613 if (to == nullptr) {
1614 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1615 }
1616 link = from->getLinkTo(to);
1617 }
1618 myNLI = NextLaneInfo(nextLane, link, nextDir);
1619
1620 if (wapLaneFrom != "null") {
1621 MSLane* from = MSLane::dictionary(wapLaneFrom);
1622 MSLane* to = MSLane::dictionary(wapLaneTo);
1623 if (from == nullptr) {
1624 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1625 }
1626 if (to == nullptr) {
1627 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1628 }
1629 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
1630 if (pathIt != myWalkingAreaPaths.end()) {
1631 myWalkingAreaPath = &pathIt->second;
1632 } else {
1633 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1634 }
1635 }
1636 }
1637}
1638
1639
1642
1643
1644void
1646 std::string wapLaneFrom = "null";
1647 std::string wapLaneTo = "null";
1648 if (myWalkingAreaPath != nullptr) {
1649 wapLaneFrom = myWalkingAreaPath->from->getID();
1650 wapLaneTo = myWalkingAreaPath->to->getID();
1651 }
1652 std::string nextLaneID = "null";
1653 std::string nextLinkFrom = "null";
1654 std::string nextLinkTo = "null";
1655 if (myNLI.lane != nullptr) {
1656 nextLaneID = myNLI.lane->getID();
1657 }
1658 if (myNLI.link != nullptr) {
1659 nextLinkFrom = myNLI.link->getLaneBefore()->getID();
1660 nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
1661 }
1662 out << " " << myLane->getID()
1663 << " " << myEdgePos
1664 << " " << myPosLat
1665 << " " << myDir
1666 << " " << mySpeed
1667 << " " << mySpeedLat
1668 << " " << myWaitingToEnter
1669 << " " << myWaitingTime
1670 << " " << wapLaneFrom
1671 << " " << wapLaneTo
1672 << " " << myAmJammed
1673 << " " << nextLaneID
1674 << " " << nextLinkFrom
1675 << " " << nextLinkTo
1676 << " " << myNLI.dir;
1677}
1678
1679double
1680MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
1681 // @todo speed should have an influence here because faster persons need more space
1682 if (myDir == FORWARD) {
1683 return myEdgePos - getLength();
1684 }
1685 return myEdgePos - (includeMinGap ? getMinGap() : 0.);
1686}
1687
1688
1689double
1690MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
1691 // @todo speed should have an influence here because faster persons need more space
1692 if (myDir == FORWARD) {
1693 return myEdgePos + (includeMinGap ? getMinGap() : 0.);
1694 }
1695 return myEdgePos + getLength();
1696}
1697
1698
1699double
1701 return myPerson->getVehicleType().getLength();
1702}
1703
1704
1705double
1707 return myPerson->getVehicleType().getMinGap();
1708}
1709
1710
1711int
1713 return (int)floor(relY / stripeWidth + 0.5);
1714}
1715
1716
1717int
1719 const int s = stripe(relY);
1720 const double offset = relY - s * stripeWidth;
1721 const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
1722 int result;
1723 if (offset > threshold) {
1724 result = s + 1;
1725 } else if (offset < -threshold) {
1726 result = s - 1;
1727 } else {
1728 result = s;
1729 }
1730 //std::cout.setf(std::ios::fixed , std::ios::floatfield);
1731 //std::cout << std::setprecision(5);
1732 //if DEBUGCOND(*this) std::cout << " otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
1733 return result;
1734}
1735
1736int
1738 return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
1739}
1740
1741
1742int
1744 return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
1745}
1746
1747
1748double
1750 if (myStage->getNextRouteEdge() == nullptr) {
1751 return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
1752 (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
1753 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
1754 ? getMinGap() : 0);
1755 } else {
1756 const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
1757 return myDir == FORWARD ? length - myEdgePos : myEdgePos;
1758 }
1759}
1760
1761
1762bool
1764 double dist = distToLaneEnd();
1765 if (DEBUGCOND(*this)) {
1766 std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
1767 }
1768 if (dist <= 0) {
1769 //if (ped.getPerson()->getID() == DEBUG1) {
1770 // std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
1771 //}
1772 //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
1773 //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
1774 const int oldDir = myDir;
1775 const MSLane* oldLane = myLane;
1776 myLane = myNLI.lane;
1777 myDir = myNLI.dir;
1778 const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
1779 if DEBUGCOND(*this) {
1780 std::cout << SIMTIME
1781 << " ped=" << myPerson->getID()
1782 << " moveToNextLane old=" << oldLane->getID()
1783 << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
1784 << " oldDir=" << oldDir
1785 << " newDir=" << myDir
1786 << " myEdgePos=" << myEdgePos
1787 << " dist=" << dist
1788 << "\n";
1789 }
1790 if (myLane == nullptr) {
1791 myEdgePos = myStage->getArrivalPos();
1792 }
1793 // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
1794 if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
1795 myLane = nullptr;
1796 } else {
1797 const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
1798 UNUSED_PARAMETER(arrived);
1799 assert(!arrived);
1800 assert(myDir != UNDEFINED_DIRECTION);
1801 myNLI = getNextLane(*this, myLane, oldLane);
1802 // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
1803 myStage->activateEntryReminders(myPerson);
1804 assert(myNLI.lane != oldLane); // do not turn around
1805 if DEBUGCOND(*this) {
1806 std::cout << " nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
1807 }
1808 if (myLane->getEdge().isWalkingArea()) {
1809 if (myNLI.dir != UNDEFINED_DIRECTION) {
1810 myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
1811 assert(myWalkingAreaPath->shape.size() >= 2);
1812 if DEBUGCOND(*this) {
1813 std::cout << " mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
1814 }
1815 } else if (myNLI.link != nullptr) {
1816 // using direct connection (instead of using walkingarea)
1817 myLane = myNLI.lane;
1818 assert(!myLane->getEdge().isWalkingArea());
1819 myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
1820 myWalkingAreaPath = nullptr;
1821 myNLI = getNextLane(*this, myLane, oldLane);
1822 } else {
1823 // disconnected route. move to the next edge
1824 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
1825 // try to determine direction from topology, otherwise maintain current direction
1826 const MSEdge* currRouteEdge = *myStage->getRouteStep();
1827 const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
1828 if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
1829 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
1830 myDir = BACKWARD;
1831 } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
1832 || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
1833 myDir = FORWARD;
1834 }
1835 myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
1836 myLane = myNLI.lane;
1837 assert(myLane != 0);
1838 assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
1839 myNLI = getNextLane(*this, myLane, oldLane);
1840 myWalkingAreaPath = nullptr;
1841 } else {
1842 throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
1843 }
1844 }
1845 } else {
1846 myWalkingAreaPath = nullptr;
1847 }
1848 // adapt x to fit onto the new lane
1849 // (make sure we do not move past the end of the new lane since that
1850 // lane was not checked for obstacles)
1851 const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
1852 if (-dist > newLength) {
1853 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
1854 // should not happen because the end of myLane should have been an obstacle as well
1855 // (only when the route is broken)
1856 dist = -newLength;
1857 }
1858 if (myDir == BACKWARD) {
1859 myEdgePos = newLength + dist;
1860 } else {
1861 myEdgePos = -dist;
1862 }
1863 if DEBUGCOND(*this) {
1864 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
1865 << " newLength=" << newLength
1866 << " dist=" << dist
1867 << " myEdgePos=" << myEdgePos
1868 << "\n";
1869 }
1870 // adjust to change in direction
1871 if (myDir != oldDir) {
1872 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
1873 }
1874 // adjust to differences in sidewalk width
1875 const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
1876 myPosLat += offset * stripeWidth;
1877 if DEBUGCOND(*this) {
1878 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
1879 << " newLane=" << Named::getIDSecure(myLane)
1880 << " newY=" << myPosLat
1881 << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
1882 << " od=" << oldDir << " nd=" << myDir
1883 << " offset=" << offset << "\n";
1884 }
1885 }
1886 myAngle = std::numeric_limits<double>::max(); // see #9014
1887 return true;
1888 } else {
1889 return false;
1890 }
1891}
1892
1893
1894int
1895MSPModel_Striping::getReserved(int stripes, double factor) {
1896 return MIN2(
1897 (int)floor(stripes * factor),
1899}
1900
1901void
1903 const int stripes = (int)obs.size();
1904 const int sMax = stripes - 1;
1905 assert(stripes == numStripes(myLane));
1906 // account stage-specific max speed but also for normal lane speed limit
1907 // (speed limits on crossings and walkingareas ignored due to #11527)
1908 const double vMax = (myStage->getConfiguredSpeed() >= 0
1909 ? myStage->getConfiguredSpeed()
1910 : (USE_NET_SPEEDS || myLane->isNormal() || myLane->isInternal()
1911 ? myLane->getVehicleMaxSpeed(myPerson)
1912 : myStage->getMaxSpeed(myPerson)));
1913 // ultimate goal is to choose the preferred stripe (chosen)
1914 const int current = stripe();
1915 const int other = otherStripe();
1916 // compute distances
1917 std::vector<double> distance(stripes);
1918 for (int i = 0; i < stripes; ++i) {
1919 distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
1920 }
1921 // compute utility for all stripes
1922 std::vector<double> utility(stripes, 0);
1923 // forbid stripes which are blocked and also all stripes behind them
1924 for (int i = 0; i < stripes; ++i) {
1925 if (distance[i] == DIST_OVERLAP) {
1926 if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
1927 utility[i] += OBSTRUCTED_PENALTY;
1928 }
1929 if (i < current) {
1930 for (int j = 0; j <= i; ++j) {
1931 utility[j] += OBSTRUCTED_PENALTY;
1932 }
1933 }
1934 if (i > current) {
1935 for (int j = i; j < stripes; ++j) {
1936 utility[j] += OBSTRUCTED_PENALTY;
1937 }
1938 }
1939 }
1940 }
1941 // forbid a portion of the leftmost stripes (in walking direction).
1942 // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
1943 // may still deadlock in heavy pedestrian traffic
1944 const bool onJunction = myLane->getEdge().isWalkingArea() || myLane->getEdge().isCrossing();
1945 const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
1946 if (myDir == FORWARD) {
1947 for (int i = 0; i < reserved; ++i) {
1948 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1949 }
1950 } else {
1951 for (int i = sMax; i > sMax - reserved; --i) {
1952 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1953 }
1954 }
1955 // adapt utility based on obstacles
1956 for (int i = 0; i < stripes; ++i) {
1957 if (obs[i].speed * myDir < 0) {
1958 // penalize evasion to the left unless the obstacle is a vehicle
1959 if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
1960 utility[i - 1] -= 0.5;
1961 } else if (myDir == BACKWARD && i < sMax) {
1962 utility[i + 1] -= 0.5;
1963 }
1964 }
1965 // compute expected distance achievable by staying on this stripe for a time horizon
1966 const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
1967 const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
1968 const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
1969 if (expectedDist >= 0) {
1970 utility[i] += expectedDist;
1971 } else {
1972 // let only the distance count
1973 utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
1974 }
1975 }
1976 // discourage use of the leftmost stripe (in walking direction) if there are oncoming
1977 if (myDir == FORWARD && obs[0].speed < 0) {
1978 utility[0] += ONCOMING_CONFLICT_PENALTY;
1979 } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
1980 utility[sMax] += ONCOMING_CONFLICT_PENALTY;
1981 }
1982 // penalize lateral movement (if the current stripe permits walking)
1983 if (distance[current] > 0 && myWaitingTime == 0) {
1984 for (int i = 0; i < stripes; ++i) {
1985 utility[i] += abs(i - current) * LATERAL_PENALTY;
1986 }
1987 }
1988 // walk on the right side on shared space
1989 if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
1990 for (int i = 0; i < stripes; ++i) {
1991 if (i <= current) {
1992 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
1993 }
1994 }
1995 }
1996
1997 // select best stripe
1998 int chosen = current;
1999 for (int i = 0; i < stripes; ++i) {
2000 if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
2001 chosen = i;
2002 }
2003 }
2004 // compute speed components along both axes
2005 const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
2006 double xDist = MIN3(distance[current], distance[other], distance[next]);
2007 if (next != chosen) {
2008 // ensure that we do not collide with an obstacle in the stripe beyond
2009 // next as this might become the 'other' stripe in the next step
2010 const int nextOther = chosen < current ? current - 2 : current + 2;
2011 xDist = MIN2(xDist, distance[nextOther]);
2012 }
2013 // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
2014 const double preferredGap = NUMERICAL_EPS;
2015 double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
2016 if (xSpeed < NUMERICAL_EPS) {
2017 xSpeed = 0.;
2018 }
2019 if (DEBUGCOND(*this)) {
2020 std::cout << " xSpeedPotential=" << xSpeed << "\n";
2021 }
2022 // avoid tiny steps
2023 // XXX pressure from behind?
2024 if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
2025 // unless walking towards a short lane
2026 !(
2027 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
2028 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
2029 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
2030 ) {
2031 xSpeed = 0;
2032 }
2033 if (xSpeed == 0) {
2034 if (DEBUGCOND(*this)) {
2035 std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
2036 << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
2037 << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
2038 << "\n";
2039 }
2040 if (myWaitingTime > ((myLane->getEdge().isCrossing()
2041 // treat shared walkingarea like a crossing to avoid deadlocking vehicles
2042 || (myLane->getEdge().isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
2043 && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
2044 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
2045 || myAmJammed) {
2046 // squeeze slowly through the crowd ignoring others
2047 if (!myAmJammed) {
2049 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
2050 myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
2051 myAmJammed = true;
2052 }
2053 xSpeed = vMax * jamFactor;
2054 }
2055 } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST) {
2056 myAmJammed = false;
2057 }
2058 // dawdling
2059 const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
2060 xSpeed -= dawdle;
2061
2062 // XXX ensure that diagonal speed <= vMax
2063 // avoid deadlocks on narrow sidewalks
2064 //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
2065 // if DEBUGCOND(*this) std::cout << " stepping aside to resolve oncoming deadlock\n";
2066 // xSpeed = POSITION_EPS; // reset myWaitingTime
2067 // if (myDir == FORWARD && chosen < sMax) {
2068 // chosen += 1;
2069 // } else if (myDir == BACKWARD && chosen > 0) {
2070 // chosen -= 1;
2071 // }
2072 //}
2073 const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
2074 double ySpeed = 0;
2075 double yDist = 0;
2076 if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
2077 // don't move laterally if the stripes are blocked
2078 yDist = (chosen * stripeWidth) - myPosLat;
2079 if (fabs(yDist) > NUMERICAL_EPS) {
2080 ySpeed = (yDist > 0 ?
2081 MIN2(maxYSpeed, DIST2SPEED(yDist)) :
2082 MAX2(-maxYSpeed, DIST2SPEED(yDist)));
2083 }
2084 } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
2085 // still on the road
2086 && stripe() == stripe(myPosLat)
2087 // only when the vehicle is moving on the same lane
2088 && !(myLane->getEdge().isCrossing() || myLane->getEdge().isWalkingArea())) {
2089 // step aside to let the vehicle pass
2090 int stepAsideDir = myDir;
2091 if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
2092 // always step to the right on multi-lane edges or when closer to
2093 // the right side
2094 stepAsideDir = FORWARD;
2095 }
2096 myAmJammed = true; // ignore pedestrian-pedestrian collisions
2097 ySpeed = stepAsideDir * vMax;
2098 }
2099
2100 // DEBUG
2101 if DEBUGCOND(*this) {
2102 std::cout << SIMTIME
2103 << " ped=" << myPerson->getID()
2104 << " edge=" << myStage->getEdge()->getID()
2105 << " x=" << myEdgePos
2106 << " y=" << myPosLat
2107 << " d=" << myDir
2108 << " pvx=" << mySpeed
2109 << " cur=" << current
2110 << " cho=" << chosen
2111 << " oth=" << other
2112 << " nxt=" << next
2113 << " vx=" << xSpeed
2114 << " dawdle=" << dawdle
2115 << " vy=" << ySpeed
2116 << " xd=" << xDist
2117 << " yd=" << yDist
2118 << " vMax=" << vMax
2119 << " wTime=" << myStage->getWaitingTime(currentTime)
2120 << " jammed=" << myAmJammed
2121 << "\n";
2122 if (DEBUGCOND(*this)) {
2123 for (int i = 0; i < stripes; ++i) {
2124 const Obstacle& o = obs[i];
2125 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
2126 if (o.description != "") {
2127 std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
2128 }
2129 if (i == current) {
2130 std::cout << " current";
2131 }
2132 if (i == other && i != current) {
2133 std::cout << " other";
2134 }
2135 if (i == chosen) {
2136 std::cout << " chosen";
2137 }
2138 if (i == next) {
2139 std::cout << " next";
2140 }
2141 std::cout << "\n";
2142 }
2143 }
2144 }
2145 myEdgePos += SPEED2DIST(xSpeed * myDir);
2146 myPosLat += SPEED2DIST(ySpeed);
2147 mySpeedLat = ySpeed;
2148 mySpeed = xSpeed;
2149 if (xSpeed >= SUMO_const_haltingSpeed) {
2150 myWaitingToEnter = false;
2151 myWaitingTime = 0;
2152 } else {
2153 myWaitingTime += DELTA_T;
2154 }
2155 myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
2156}
2157
2158
2159double
2161 return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
2162 + STEPS2TIME(myStage->getWaitingTime(now)) / MAX_WAIT_TOLERANCE));
2163}
2164
2165
2168 if (myRemoteXYPos != Position::INVALID) {
2169 return myRemoteXYPos;
2170 }
2171 if (myLane == nullptr) {
2172 // pedestrian has already finished
2173 return Position::INVALID;
2174 }
2175 const double lateral_offset = -getLatOffset(); // the minus is hunting me in my dreams but seems to be here for historical reasons
2176 if (myWalkingAreaPath == nullptr) {
2177 return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
2178 } else {
2179 //if DEBUGCOND(*this) {
2180 // std::cout << SIMTIME
2181 // << " getPosition (walkingArea)"
2182 // << " p=" << myPerson->getID()
2183 // << " x=" << myEdgePos
2184 // << " y=" << myPosLat
2185 // << " latOffset=" << lateral_offset
2186 // << " shape=" << myWalkingAreaPath->shape
2187 // << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
2188 // << "\n";
2189 //}
2190 if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
2191 return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
2192 } else {
2193 const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
2194 return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
2195 }
2196 }
2197}
2198
2199
2200double
2202 if (myAngle != std::numeric_limits<double>::max()) {
2203 return myAngle;
2204 }
2205 if (myLane == nullptr) {
2206 // pedestrian has already finished
2207 return 0;
2208 }
2209 if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
2210 return myWalkingAreaPath->angleOverride;
2211 }
2212 const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
2213 double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
2214 double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
2215 if (myDir == MSPModel::BACKWARD) {
2216 angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2217 } else { // myDir == MSPModel::FORWARD
2218 angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2219 }
2220 if (angle > M_PI) {
2221 angle -= 2 * M_PI;
2222 }
2223 myAngle = angle;
2224 return angle;
2225}
2226
2227
2228const MSEdge*
2230 return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
2231}
2232
2233
2234const MSLane*
2236 return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
2237}
2238
2239
2240void
2241MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
2242 myEdgePos = pathLength - myEdgePos;
2243 myPosLat = usableWidth - myPosLat;
2244 myDir = -myWalkingAreaPath->dir;
2245 mySpeedLat = -mySpeedLat;
2246}
2247
2248
2249void
2250MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
2251 myEdgePos = edgePos;
2252 myPosLat = latPos;
2253 myDir = UNDEFINED_DIRECTION; // only an obstacle, speed may be orthogonal to dir
2254 mySpeed = 0.;
2255 mySpeedLat = 0.;
2256}
2257
2258
2259void
2260MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
2261 ConstMSEdgeVector newEdges; // keep route
2262 int routeOffset = 0;
2263 bool laneOnRoute = false;
2264 const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
2265 for (const MSEdge* edge : myStage->getRoute()) {
2266 if (edge == &lane->getEdge()
2267 || edge->getToJunction() == laneOnJunction
2268 || edge->getFromJunction() == laneOnJunction) {
2269 laneOnRoute = true;
2270 break;
2271 }
2272 routeOffset++;
2273 }
2274 if (!laneOnRoute) {
2275 throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
2276 }
2277 Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
2278 if (lane->getEdge().isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
2279 // entered new walkingarea. Determine path to guess position
2280 const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
2281 const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
2282 const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
2283 const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
2284 if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
2285 throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
2286 + "' (fromLane='" + guessed->from->getID()
2287 + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2288 }
2289 // give some slack
2290 lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
2291 pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
2292 }
2293 const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
2294 moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
2295}
2296
2297
2298void
2300 double lanePosLat, double angle, int routeOffset,
2301 const ConstMSEdgeVector& edges, SUMOTime t) {
2303 assert(p == myPerson);
2304 assert(pm != nullptr);
2305 const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
2306 // person already walking in this step. undo this to obtain the previous position
2307 const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
2308 const double tmp = myEdgePos;
2309 myEdgePos = oldX;
2310 Position oldPos = getPosition(*myStage, t);
2311 myEdgePos = tmp;
2312 //if (oldPos == Position::INVALID) {
2313 // oldPos = pos
2314 //}
2315 myAngle = GeomHelper::fromNaviDegree(angle);
2316#ifdef DEBUG_MOVETOXY
2317 std::cout << SIMTIME << " ped=" << p->getID()
2318 << " moveToXY"
2319 << " pos=" << pos
2320 << " lane=" << lane->getID()
2321 << " lanePos=" << lanePos
2322 << " lanePosLat=" << lanePosLat
2323 << " angle=" << angle
2324 << " routeOffset=" << routeOffset
2325 << " edges=" << toString(edges)
2326 << " oldLane=" << Named::getIDSecure(myLane)
2327 << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
2328#endif
2329
2330 if (lane != myLane && myLane != nullptr) {
2331 pm->remove(this);
2332 pm->registerActive();
2333 }
2334 if (lane != nullptr &&
2335 fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
2336 myRemoteXYPos = Position::INVALID;
2337 const MSEdge* old = myStage->getEdge();
2338 const MSLane* oldLane = myLane;
2339 if (lane != myLane) {
2340 // implicitly adds new active lane if necessary
2341 pm->myActiveLanes[lane].push_back(this);
2342 }
2343 if (edges.empty()) {
2344 // map within route
2345 myStage->setRouteIndex(myPerson, routeOffset);
2346 } else {
2347 myStage->replaceRoute(myPerson, edges, routeOffset);
2348 }
2349 if (!lane->getEdge().isNormal()) {
2350 myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
2351 }
2352
2353 myLane = lane;
2354 const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
2355 if (lane->getEdge().isWalkingArea()) {
2356 if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
2357 // entered new walkingarea. Determine path
2358 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
2359#ifdef DEBUG_MOVETOXY
2360 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
2361 << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
2362#endif
2363 }
2364 // lanePos and lanePosLat are matched onto the circumference of the
2365 // walkingarea. Use pos instead
2366 const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
2367 if (relPos == Position::INVALID) {
2368 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
2369 + "' (fromLane='" + myWalkingAreaPath->from->getID()
2370 + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2371 myRemoteXYPos = pos;
2372 } else {
2373 myEdgePos = relPos.x();
2374 myPosLat = lateral_offset + relPos.y();
2375 }
2376 } else {
2377 myWalkingAreaPath = nullptr;
2378 myEdgePos = lanePos;
2379 myPosLat = lateral_offset - lanePosLat;
2380 }
2381 // guess direction
2382 const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
2383 if (myStage->getNextRouteEdge() != nullptr) {
2384 if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
2385 myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
2386 myDir = FORWARD;
2387 } else {
2388 myDir = BACKWARD;
2389 }
2390 } else {
2391 // guess from angle
2392 if (angleDiff <= 90) {
2393 // keep direction
2394 if (myDir == UNDEFINED_DIRECTION) {
2395 myDir = FORWARD;
2396 }
2397 } else {
2398 // change direction
2399 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
2400 }
2401 }
2402 // update next lane info (after guessing direction)
2403 if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
2404 const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
2405 // assume that we will eventually move back onto the sidewalk if
2406 // there is one
2407 myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
2408 myStage->activateEntryReminders(myPerson);
2409#ifdef DEBUG_MOVETOXY
2410 std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
2411#endif
2412 }
2413#ifdef DEBUG_MOVETOXY
2414 std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID() << " newPos=" << myPerson->getPosition()
2415 << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
2416#endif
2417 if (oldLane == myLane) {
2418 mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
2419 } else {
2420 //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
2421 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2422 }
2423 } else {
2424 // map outside the network
2425 myRemoteXYPos = pos;
2426 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2427 }
2428
2429}
2430
2431
2432double
2434 if (myWalkingAreaPath != nullptr) {
2435 return myWalkingAreaPath->length;
2436 } else {
2437 return 0;
2438 }
2439}
2440
2441double
2442MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
2443 // check for overlap
2444 const double maxX = getMaxX(includeMinGap);
2445 const double minX = getMinX(includeMinGap);
2446 //if (DEBUGCOND(*this)) {
2447 // std::cout << std::setprecision(2) << " distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
2448 //}
2449 if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
2450 // avoid blocking by itself on looped route
2451 return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
2452 }
2453 if (myDir == FORWARD) {
2454 return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
2455 } else {
2456 return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
2457 }
2458}
2459
2460
2461void
2463 for (int i = 0; i < (int)into.size(); ++i) {
2464 if (gDebugFlag1) {
2465 std::cout << " i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
2466 << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
2467 << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
2468 }
2469 const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
2470 const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
2471 if (dO < dI) {
2472 into[i] = obs2[i];
2473 } else if (dO == dI
2474 && into[i].type != OBSTACLE_PED
2475 && into[i].type != OBSTACLE_VEHICLE
2476 && (obs2[i].type == OBSTACLE_PED ||
2477 obs2[i].type == OBSTACLE_VEHICLE)) {
2478 into[i] = obs2[i];
2479 }
2480 }
2481}
2482
2483void
2484MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
2485 for (int i = 0; i < (int)into.size(); ++i) {
2486 int i2 = i + offset;
2487 if (i2 >= 0 && i2 < (int)obs2.size()) {
2488 if (dir == FORWARD) {
2489 if (obs2[i2].xBack < into[i].xBack) {
2490 into[i] = obs2[i2];
2491 }
2492 } else {
2493 if (obs2[i2].xFwd > into[i].xFwd) {
2494 into[i] = obs2[i2];
2495 }
2496 }
2497 }
2498 }
2499}
2500
2501
2502bool
2504 if (link->haveRed()) {
2505 const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
2506 if (ignoreRedTime >= 0) {
2507 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2508 if (DEBUGCOND(*this)) {
2509 std::cout << SIMTIME << " ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
2510 }
2511 return ignoreRedTime > redDuration;
2512 } else {
2513 return false;
2514 }
2515 } else {
2516 return false;
2517 }
2518}
2519
2520
2521bool
2523 // main use case is at rail_crossing
2524 if (link->haveYellow()) {
2525 const double ignoreYellowTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, -1);
2526 if (ignoreYellowTime >= 0) {
2527 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2528 if (DEBUGCOND(*this)) {
2529 std::cout << SIMTIME << " ignoreYellowTime=" << ignoreYellowTime << " yellowDuration=" << yellowDuration << "\n";
2530 }
2531 return ignoreYellowTime < yellowDuration;
2532 } else {
2533 return true;
2534 }
2535 } else {
2536 return false;
2537 }
2538}
2539
2540double
2542 return myPerson->getVehicleType().getWidth();
2543}
2544
2545
2546bool
2548 return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
2549}
2550
2551// ===========================================================================
2552// MSPModel_Striping::PStateVehicle method definitions
2553// ===========================================================================
2554
2555MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
2556 myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
2557 myLane = walkingarea; // to ensure correct limits when calling otherStripe()
2558 // relX is the center but we want it to be the max value if the movement direction is forward
2559 // and the min value otherwise (indicated by xWidth sign)
2560 myEdgePos = relX + xWidth / 2;
2561 myPosLat = relY;
2562}
2563
2564const std::string&
2566 return myVehicle->getID();
2567}
2568
2569double
2571 return myYWidth;
2572}
2573
2574double
2575MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
2576 return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
2577}
2578
2579double
2580MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
2581 return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
2582}
2583
2584// ===========================================================================
2585// MSPModel_Striping::MovePedestrians method definitions
2586// ===========================================================================
2587
2590 std::set<MSPerson*> changedLane;
2591 myModel->moveInDirection(currentTime, changedLane, FORWARD);
2592 myModel->moveInDirection(currentTime, changedLane, BACKWARD);
2593 // DEBUG
2594#ifdef LOG_ALL
2595 for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
2596 const MSLane* lane = it_lane->first;
2597 Pedestrians pedestrians = it_lane->second;
2598 if (pedestrians.size() == 0) {
2599 continue;
2600 }
2601 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
2602 std::cout << SIMTIME << " lane=" << lane->getID();
2603 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
2604 const PState& p = *pedestrians[ii];
2605 std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
2606 }
2607 std::cout << "\n";
2608 }
2609#endif
2610 return DELTA_T;
2611}
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:296
#define WRITE_WARNING(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:315
#define TLF(string,...)
Definition MsgHandler.h:317
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMSTEP
Definition SUMOTime.h:61
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
#define DIST2SPEED(x)
Definition SUMOTime.h:47
const std::string DEFAULT_PEDTYPE_ID
@ SVC_PEDESTRIAN
pedestrian
@ SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
@ SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
bool gDebugFlag1
global utility flags for debugging
Definition StdDefs.cpp:37
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:64
#define UNUSED_PARAMETER(x)
Definition StdDefs.h:30
T MIN3(T a, T b, T c)
Definition StdDefs.h:89
T MIN2(T a, T b)
Definition StdDefs.h:76
std::pair< int, double > MMVersion
(M)ajor/(M)inor version for written networks and default version for loading
Definition StdDefs.h:67
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:58
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
Position getCenter() const
Returns the center of the boundary.
Definition Boundary.cpp:112
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition Boundary.cpp:78
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:130
double getWidth() const
Returns the width of the boudary (x-axis)
Definition Boundary.cpp:154
void growWidth(double by)
Increases the width of the boundary (x-axis)
Definition Boundary.cpp:362
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:136
static double naviDegree(const double angle)
static double fromNaviDegree(const double angle)
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:380
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:264
A road/street connecting two junctions.
Definition MSEdge.h:77
static const MSEdgeVector & getAllEdges()
Returns all edges with a numerical id.
Definition MSEdge.cpp:1086
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition MSEdge.h:273
bool isWalkingArea() const
return whether this edge is walking area
Definition MSEdge.h:287
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:263
const MSJunction * getToJunction() const
Definition MSEdge.h:418
double getLength() const
return the length of the edge
Definition MSEdge.h:685
const MSJunction * getFromJunction() const
Definition MSEdge.h:414
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
const MSEdgeVector & getPredecessors() const
Definition MSEdge.h:409
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1258
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gCheck4Accidents
Definition MSGlobals.h:88
The base class for an intersection.
Definition MSJunction.h:58
AnyVehicleIterator is a structure, which manages the iteration through all vehicles on the lane,...
Definition MSLane.h:129
Representation of a lane in the micro simulation.
Definition MSLane.h:84
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction
Definition MSLane.h:495
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition MSLane.h:464
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2669
bool isWalkingArea() const
Definition MSLane.cpp:2563
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:614
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:950
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
const MSLane * getInternalFollowingLane(const MSLane *const) const
returns the internal lane leading to the given lane or nullptr, if there is none
Definition MSLane.cpp:2681
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:3216
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3136
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:2552
bool isCrossing() const
Definition MSLane.cpp:2558
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2415
bool isInternal() const
Definition MSLane.cpp:2546
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:4565
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition MSLane.h:560
The simulated network and simulation perfomer.
Definition MSNet.h:89
MSPedestrianRouter & getPedestrianRouter(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition MSNet.cpp:1536
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:471
MMVersion getNetworkVersion() const
return the network version
Definition MSNet.h:805
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:378
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1190
std::vector< MSPModel_InteractingState * > Pedestrians
Pedestrians & getPedestrians(const MSLane *lane)
retrieves the pedestrian vector for the given lane (may be empty)
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
bool myAmActive
whether an event for pedestrian processing was added
int myNumActivePedestrians
the total number of active pedestrians
void registerActive()
increase the number of active pedestrians
virtual void remove(MSTransportableStateAdapter *state)
remove the specified person from the pedestrian simulation
static void unregisterCrossingApproach(const MSPModel_InteractingState &ped, const MSLane *crossing)
unregister pedestrian approach with the junction model
Container for pedestrian state and individual position update function.
SUMOTime myWaitingTime
the consecutive time spent at speed 0
MSPerson * myPerson
the person who is being represented
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
double myEdgePos
the advancement along the current lane
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
virtual const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
const Position & getRemotePosition() const
return the remote position if being controlled by TraCI or JuPedSim
const MSLane * myLane
the current lane of this pedestrian
double mySpeed
the current walking speed
MSStageMoving * myStage
the current stage of this pedestrian
double myPosLat
the orthogonal shift on the current lane
double mySpeedLat
the current lateral walking speed
bool isWaitingToEnter() const
whether the person still waits to entere the network
bool myWaitingToEnter
whether the pedestrian is waiting to start its walk
const MSLane * getLane() const
the current lane of the transportable
int getDirection() const
return the walking direction (FORWARD, BACKWARD, UNDEFINED_DIRECTION)
bool myAmJammed
whether the person is jammed
double getSpeed(const MSStageMoving &) const
return the current speed of the transportable
bool isJammed() const
whether the transportable is jammed
SUMOTime execute(SUMOTime currentTime)
Executes the command.
Container for pedestrian state and individual position update function.
virtual double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
const WalkingAreaPath * myWalkingAreaPath
the current walkingAreaPath or 0
PState()
constructor for PStateVehicle
double distToLaneEnd() const
the absolute distance to the end of the lane in walking direction (or to the arrivalPos)
void mergeObstacles(Obstacles &into, const Obstacles &obs2)
replace obstacles in the first vector with obstacles from the second if they are closer to me
bool isRemoteControlled() const
whether the person is currently being controlled via TraCI
const MSEdge * getNextEdge(const MSStageMoving &stage) const
return the list of internal edges if the transportable is on an intersection
const MSLane * getNextCrossing() const
placeholder function for the accessing the next crossing
void walk(const Obstacles &obs, SUMOTime currentTime)
perform position update
virtual double getWidth() const
return the person width
void saveState(std::ostringstream &out)
Saves the current state into the given stream.
bool ignoreRed(const MSLink *link) const
whether the pedestrian may ignore a red light
virtual double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
bool moveToNextLane(SUMOTime currentTime)
return whether this pedestrian has passed the end of the current lane and update myRelX if so
void reverse(const double pathLength, const double usableWidth)
double getMinGap() const
return the minimum gap of the pedestrian
void moveToXY(MSPerson *p, Position pos, MSLane *lane, double lanePos, double lanePosLat, double angle, int routeOffset, const ConstMSEdgeVector &edges, SUMOTime t)
try to move transportable to the given position
void moveTo(MSPerson *p, MSLane *lane, double lanePos, double lanePosLat, SUMOTime t)
try to move transportable to the given position
Position getPosition(const MSStageMoving &stage, SUMOTime now) const
return the network coordinate of the transportable
NextLaneInfo myNLI
information about the upcoming lane
double getAngle(const MSStageMoving &stage, SUMOTime now) const
return the current orientation in degrees
double getImpatience(SUMOTime now) const
returns the impatience
void reset(const double edgePos, const double latPos)
double distanceTo(const Obstacle &obs, const bool includeMinGap=true) const
bool stopForYellow(const MSLink *link) const
whether the pedestrian should stop at a yellow light
double getLength() const
return the length of the pedestrian
double getPathLength() const
return the total length of the current lane (in particular for on a walkingarea)
double getWidth() const
return the person width
double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
PStateVehicle(const MSVehicle *veh, const MSLane *walkingarea, double relX, double relY, double xWidth, double yWidth)
sorts the persons by position on the lane. If dir is forward, higher x positions come first.
The pedestrian movement model using stripes on sidewalks.
static const double MIN_STARTUP_DIST
the minimum distance to the next obstacle in order to start walking after stopped
static void registerCrossingApproach(const PState &ped, const MSLane *crossing, const MSLane *beforeWA)
register pedestrian approach with the junction model
static double RESERVE_FOR_ONCOMING_FACTOR
fraction of the leftmost lanes to reserve for oncoming traffic
static MinNextLengths myMinNextLengths
static bool addVehicleFoe(const MSVehicle *veh, const MSLane *walkingarea, const Position &relPos, double xWidth, double yWidth, double lateral_offset, double minY, double maxY, Pedestrians &toDelete, Pedestrians &transformedPeds)
MSTransportableStateAdapter * loadState(MSTransportable *transportable, MSStageMoving *stage, std::istringstream &in)
load the state of the given transportable
static double posLatConversion(const double posLat, const double laneWidth)
Convert the striping to the vehicle lateral position and vice versa.
static SUMOTime jamTimeCrossing
void moveInDirection(SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
move all pedestrians forward and advance to the next lane if applicable
static 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:94
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition MSStage.h:85
Position getLanePosition(const MSLane *lane, double at, double offset) const
get position on lane at length at with orthogonal offset
Definition MSStage.cpp:177
virtual int getRoutePosition() const
return index of current edge within route
Definition MSStage.h:196
virtual const MSEdge * getNextRouteEdge() const =0
static const MSLane * checkDepartLane(const MSEdge *edge, SUMOVehicleClass svc, int laneIndex, const std::string &id)
interpret custom depart lane
const std::vector< const MSEdge * > & getRoute() const
int getDepartLane() const
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
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
void registerJammed()
register a jammed transportable
SUMOVehicleClass getVClass() const
Returns the object's access class.
bool isPerson() const
Whether it is a person.
Position getPosition(const double) const
Return current position (x/y, cartesian)
const MSVehicleType & getVehicleType() const
Returns the object's "vehicle" type.
MSStageType getCurrentStageType() const
the current stage type of the transportable
const MSEdge * getEdge() const
Returns the current edge.
abstract base class for managing callbacks to retrieve various state information from the model
Definition MSPModel.h:154
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, SumoRNG *rng=nullptr, bool readOnly=false)
Returns the named vehicle type or a sample from the named distribution.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
const Position getBackPosition() const
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:969
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
A storage for options typed value containers)
Definition OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
double compute(const E *from, const E *to, double departPos, double arrivalPos, double speed, SUMOTime msTime, const N *onlyNode, std::vector< const E * > &into, bool allEdges=false)
Builds the route between the given edges using the minimum effort at the given time The definition of...
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:322
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:276
double x() const
Returns the x-position.
Definition Position.h:55
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:286
double y() const
Returns the y-position.
Definition Position.h:60
A list of positions.
double length() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
PositionVector bezier(int numPoints)
return a bezier interpolation
void push_back_noDoublePos(const Position &p)
insert in back a non double position
PositionVector reverse() const
reverse position vector
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector....
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
#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