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