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