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