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);
1034 } else {
1035 // end walking stage and destroy PState
1036 p->getStage()->moveToNextEdge(p->getPerson(), currentTime, dir);
1038 }
1039 }
1040 }
1041}
1042
1043
1044void
1045MSPModel_Striping::moveInDirectionOnLane(Pedestrians& pedestrians, const MSLane* lane, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir, bool debug) {
1046 const int stripes = numStripes(lane);
1047 //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
1048 Obstacles obs(stripes, Obstacle(dir)); // continuously updated
1049 NextLanesObstacles nextLanesObs; // continuously updated
1050 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
1051
1052 Obstacles crossingVehs(stripes, Obstacle(dir));
1053 bool hasCrossingVehObs = false;
1054 if (lane->isCrossing()) {
1055 // assume that vehicles will brake when already on the crossing
1056 hasCrossingVehObs = addCrossingVehs(lane, stripes, 0, dir, crossingVehs, true, false);
1057 }
1058
1059 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
1060 PState& p = *static_cast<PState*>(pedestrians[ii]);
1061 UNUSED_PARAMETER(debug);
1062 //if (debug) {
1063 // std::cout << SIMTIME << " CHECKING d=" << dir << " p=" << p.getID() << " relX=" << p.myRelX << " xmin=" << p.getMinX() << " xmax=" << p.getMaxX() << " pdir=" << p.getDirection() << "\n";
1064 //}
1065 Obstacles currentObs = obs;
1066 if (p.getDirection() != dir || changedLane.count(p.getPerson()) != 0 || p.getRemotePosition() != Position::INVALID) {
1067 if (!p.isWaitingToEnter() && !p.isJammed()) {
1068 //if DEBUGCOND(p) {
1069 // std::cout << " obs=" << p.getPerson()->getID() << " y=" << p.getPosLat() << " stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
1070 //}
1071 Obstacle o(p);
1072 if (p.getDirection() != dir && p.getSpeed() == 0.) {
1073 // ensure recognition of oncoming
1074 o.speed = (p.getDirection() == FORWARD ? 0.1 : -0.1);
1075 }
1076 if (o.closer(obs[p.stripe()], dir)) {
1077 obs[p.stripe()] = o;
1078 }
1079 if (o.closer(obs[p.otherStripe()], dir)) {
1080 obs[p.otherStripe()] = o;
1081 }
1082 }
1083 continue;
1084 }
1085 if DEBUGCOND(p) {
1086 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " currentObs=";
1087 gDebugFlag1 = true;
1088 DEBUG_PRINT(currentObs);
1089 }
1090 const MSLane* nextLane = p.myNLI.lane;
1091 const MSLink* link = p.myNLI.link;
1092 const double dist = p.distToLaneEnd();
1093 const double speed(p.getStage()->getConfiguredSpeed() >= 0
1095 : ((nextLane != nullptr && (USE_NET_SPEEDS || nextLane->isNormal() || nextLane->isInternal()))
1096 ? nextLane->getVehicleMaxSpeed(p.getPerson())
1097 : p.getStage()->getMaxSpeed(p.getPerson())));
1098
1099
1100 if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING_DIST) {
1101 const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
1102 const Obstacles& nextObs = getNextLaneObstacles(
1103 nextLanesObs, lane, nextLane, stripes,
1104 p.myNLI.dir, currentLength, dir);
1105
1106 if DEBUGCOND(p) {
1107 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " nextObs=";
1108 DEBUG_PRINT(nextObs);
1109 }
1110 p.mergeObstacles(currentObs, nextObs);
1111 }
1112 if DEBUGCOND(p) {
1113 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithNext=";
1114 DEBUG_PRINT(currentObs);
1115 }
1116 p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
1117 if DEBUGCOND(p) {
1118 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithNeigh=";
1119 DEBUG_PRINT(currentObs);
1120 }
1121 // time gap to pass the intersection ahead of a vehicle.
1122 const double passingLength = p.getLength() + p.getPerson()->getTimegapCrossing() * speed;
1123 // check link state
1124 if DEBUGCOND(p) {
1125 gDebugFlag1 = true; // get debug output from MSLink
1126 std::cout << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
1127 << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
1128 }
1129 if (link != nullptr
1130 // only check close before junction, @todo we should take deceleration into account here
1131 && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
1132 // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
1133 && (!link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(), speed, 0, 0, nullptr, p.ignoreRed(link), p.getPerson())
1134 || p.stopForYellow(link))) {
1135 // prevent movement passed a closed link
1136 Obstacles closedLink(stripes, Obstacle(p.getEdgePos(0) + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
1137 p.mergeObstacles(currentObs, closedLink);
1138 if DEBUGCOND(p) {
1139 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithTLS=";
1140 DEBUG_PRINT(currentObs);
1141 }
1142 // consider rerouting over another crossing
1143 if (p.myWalkingAreaPath != nullptr) {
1144 // @todo actually another path would be needed starting at the current position
1145 const MSLane* oldNext = p.myNLI.lane;
1147 if (p.myNLI.lane != oldNext && oldNext->isPriorityCrossing()) {
1148 unregisterCrossingApproach(p, oldNext);
1149 }
1150 }
1151 }
1152 if DEBUGCOND(p) {
1153 gDebugFlag1 = false;
1154 }
1155 if (&lane->getEdge() == p.getStage()->getDestination() && p.getStage()->getDestinationStop() != nullptr) {
1156 Obstacles arrival;
1159 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
1160 } else {
1161 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
1162 }
1163 p.mergeObstacles(currentObs, arrival);
1164 }
1165
1166 if (lane->getVehicleNumberWithPartials() > 0) {
1167 // react to vehicles on the same lane
1168 // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
1169 Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
1170 p.mergeObstacles(currentObs, vehObs);
1171 if DEBUGCOND(p) {
1172 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs=";
1173 DEBUG_PRINT(currentObs);
1174 }
1175 }
1176 if (hasCrossingVehObs) {
1177 p.mergeObstacles(currentObs, crossingVehs);
1178 if DEBUGCOND(p) {
1179 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << " obsWithVehs2=";
1180 DEBUG_PRINT(currentObs);
1181 }
1182 }
1183
1184 // walk, taking into account all obstacles
1185 p.walk(currentObs);
1186 gDebugFlag1 = false;
1187 if (!p.isWaitingToEnter() && !p.isJammed()) {
1188 Obstacle o(p);
1189 if (o.closer(obs[p.stripe()], dir)) {
1190 obs[p.stripe()] = o;
1191 }
1192 if (o.closer(obs[p.otherStripe()], dir)) {
1193 obs[p.otherStripe()] = o;
1194 }
1195 if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.isJammed()) {
1196 for (int coll = 0; coll < ii; ++coll) {
1197 PState& c = *static_cast<PState*>(pedestrians[coll]);
1198 if (!c.isWaitingToEnter() && c.myWalkingAreaPath == nullptr && !c.isJammed()) {
1199 if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
1200 Obstacle cObs(c);
1201 // we check only for real collisions, no min gap violations
1202 if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
1203 WRITE_WARNING("Collision of person '" + p.getPerson()->getID() + "' and person '" + c.getPerson()->getID()
1204 + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
1205 }
1206 }
1207 }
1208 }
1209 }
1210 }
1211 //std::cout << SIMTIME << p.getPerson()->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
1212 }
1213}
1214
1215
1216void
1217MSPModel_Striping::registerCrossingApproach(const PState& ped, const MSLane* crossing, const MSLane* beforeWA) {
1218 // person has entered the walkingarea
1219 SUMOTime arrivalTime = SIMSTEP;
1220 assert(ped.getLane()->isWalkingArea());
1221 const WalkingAreaPath* wa = getWalkingAreaPath(&ped.getLane()->getEdge(), beforeWA, crossing);
1222 const double speed = ped.getStage()->getMaxSpeed(ped.getPerson()) * (1 - dawdling / 2);
1223 arrivalTime += TIME2STEPS(wa->length / speed);
1224 SUMOTime leavingTime = arrivalTime + TIME2STEPS(crossing->getLength() / speed);
1225 crossing->getIncomingLanes()[0].viaLink->setApproachingPerson(ped.getPerson(), arrivalTime, leavingTime);
1226 if DEBUGCOND(ped) {
1227 std::cout << SIMTIME << " register " << ped.getPerson()->getID() << " at crossing " << crossing->getID() << "\n";
1228 }
1229}
1230
1231
1232bool
1233MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio, bool flipY) {
1234 bool hasCrossingVehObs = false;
1235 const MSLink* crossingExitLink = crossing->getLinkCont().front();
1236 gDebugFlag1 = DEBUGCOND2(crossing);
1237 const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
1238 gDebugFlag1 = false;
1239 if (linkLeaders.size() > 0) {
1240 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
1241 // the vehicle to enter the junction first has priority
1242 const MSVehicle* veh = (*it).vehAndGap.first;
1243 if (veh != nullptr) {
1244 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
1245 // block entry to the crossing in walking direction but allow leaving it
1246 Obstacle voBlock = vo;
1247 if (dir == FORWARD) {
1248 voBlock.xBack = NUMERICAL_EPS;
1249 } else {
1250 voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
1251 }
1252 // when approaching a priority crossings, vehicles must be able
1253 // to brake, otherwise the person must be able to cross in time
1254 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
1255 const double bGap = (prio
1257 : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
1258 double vehYmin;
1259 double vehYmax;
1260 // relY increases from left to right (the other way around from vehicles)
1261 if ((*it).fromLeft()) {
1262 vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
1263 vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
1264 vehYmin -= minGapToVehicle;
1265 } else {
1266 vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
1267 vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
1268 vehYmax += minGapToVehicle;
1269
1270 }
1271 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
1272 if ((dir == FORWARD && obs[s].xBack > vo.xBack)
1273 || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
1274 if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
1275 // do not enter the crossing
1276 obs[s] = voBlock;
1277 } else {
1278 obs[s] = vo;
1279 }
1280 hasCrossingVehObs = true;
1281 }
1282 }
1283 if (flipY) {
1284 Obstacles tmp = obs;
1285 for (int i = 0; i < (int)obs.size(); i++) {
1286 obs[i] = tmp[obs.size() - 1 - i];
1287 }
1288 }
1289 if (DEBUGCOND2(crossing)) {
1290 std::cout << SIMTIME
1291 << " crossingVeh=" << veh->getID()
1292 << " lane=" << crossing->getID()
1293 << " prio=" << prio
1294 << " latOffset=" << lateral_offset
1295 << " dir=" << dir
1296 << " flipY=" << flipY
1297 << " stripes=" << stripes
1298 << " dist=" << (*it).distToCrossing
1299 << " gap=" << (*it).vehAndGap.second
1300 << " brakeGap=" << bGap
1301 << " fromLeft=" << (*it).fromLeft()
1302 << " distToCrossBefore=" << distToCrossBeforeVeh
1303 << " ymin=" << vehYmin
1304 << " ymax=" << vehYmax
1305 << " smin=" << PState::stripe(vehYmin)
1306 << " smax=" << PState::stripe(vehYmax)
1307 << "\n";
1308 DEBUG_PRINT(obs);
1309 }
1310 }
1311 }
1312 if (hasCrossingVehObs) {
1313 // check whether the crossing is fully blocked
1314 const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
1315 bool allBlocked = true;
1316
1317 for (int i = 0; i < (int)obs.size(); i++) {
1318 const Obstacle& o = obs[i];
1319 if (o.type != OBSTACLE_VEHICLE && (
1320 (dir == FORWARD && i >= reserved) ||
1321 (dir == BACKWARD && i < (int)obs.size() - reserved))) {
1322 allBlocked = false;
1323 break;
1324 }
1325 }
1326 if (allBlocked) {
1327 if (DEBUGCOND2(crossing)) {
1328 std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
1329 }
1330 for (Obstacle& o : obs) {
1331 if (dir == FORWARD) {
1332 o.xBack = NUMERICAL_EPS;
1333 } else {
1334 o.xFwd = crossing->getLength() - NUMERICAL_EPS;
1335 }
1336 }
1337 }
1338 }
1339 }
1340 return hasCrossingVehObs;
1341}
1342
1343
1346 const int stripes = numStripes(lane);
1347 Obstacles vehObs(stripes, Obstacle(dir));
1348 int current = -1;
1349 double minX = 0.;
1350 double maxX = 0.;
1351 double pRelY = -1.;
1352 double pWidth = 0.;
1353 std::string pID;
1354 bool debug = DEBUGCOND2(lane);
1355 if (ped != nullptr) {
1356 current = ped->stripe();
1357 minX = ped->getMinX();
1358 maxX = ped->getMaxX();
1359 pRelY = ped->getPosLat();
1360 pWidth = ped->getPerson()->getVehicleType().getWidth();
1361 pID = ped->getPerson()->getID();
1362 debug = DEBUGCOND(*ped);
1363 } else if (dir == BACKWARD) {
1364 // checking vehicles on the next lane. Use entry point as reference
1365 minX = lane->getLength();
1366 maxX = lane->getLength();
1367 }
1370 for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
1371 const MSVehicle* veh = *it;
1372 const bool bidi = veh->getLane() == lane->getBidiLane();
1373 const double vehBack = veh->getBackPositionOnLane(lane);
1374 double vehFront = vehBack + veh->getVehicleType().getLength();
1375 // ensure that vehicles are not blocked
1376 const double vehNextSpeed = veh->getWaitingTime() > DELTA_T ? 0 : MAX2(veh->getSpeed(), 1.0);
1377 const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
1378 // boundaries for range checking
1379 double vehXMax;
1380 double vehXMin;
1381 double vehXMaxCheck;
1382 double vehXMinCheck;
1383 if (bidi) {
1384 vehFront = vehBack - veh->getVehicleType().getLength();
1385 vehXMax = vehBack + SAFETY_GAP;
1386 vehXMin = vehFront - clearance;
1387 if (dir == FORWARD) {
1388 vehXMaxCheck = vehBack + NUMERICAL_EPS;
1389 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
1390 } else {
1391 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
1392 vehXMinCheck = vehFront - clearance;
1393 }
1394 } else {
1395 vehXMax = vehFront + clearance;
1396 vehXMin = vehBack - SAFETY_GAP;
1397 if (dir == FORWARD) {
1398 vehXMaxCheck = vehFront + clearance;
1399 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
1400 } else {
1401 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
1402 vehXMinCheck = vehBack - NUMERICAL_EPS;
1403 }
1404 }
1405 if (debug) {
1406 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
1407 << "\n"
1408 << " vehXMin=" << vehXMin
1409 << " vehXMax=" << vehXMax
1410 << " vehXMinC=" << vehXMinCheck
1411 << " vehXMaxC=" << vehXMaxCheck
1412 << " minX=" << minX
1413 << " maxX=" << maxX
1414 << " bidi=" << bidi
1415 << " vFront=" << vehFront
1416 << " vBack=" << vehBack
1417 << "\n";
1418 }
1419 if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
1420 Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
1421 // moving vehicles block space along their path
1422 vo.xFwd = vehXMax;
1423 vo.xBack = vehXMin;
1424 // relY increases from left to right (the other way around from vehicles)
1425 // XXX lateral offset for partial vehicles
1426 const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
1427 const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
1428 const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
1429 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
1430 Obstacle prior = vehObs[s];
1431 vehObs[s] = vo;
1432 if (s == current && vehFront + SAFETY_GAP < minX) {
1433 // ignore if already overlapping while vehicle is still behind
1434 if (pRelY - pWidth < vehYmax &&
1435 pRelY + pWidth > vehYmin && dir == FORWARD) {
1436 if (debug) {
1437 std::cout << " ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
1438 }
1439 if (dir == FORWARD) {
1440 vehObs[s] = prior;
1441 } else {
1442 vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
1443 }
1444 }
1445 }
1446 }
1447 if (debug) {
1448 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
1449 << "\n"
1450 << " ymin=" << vehYmin
1451 << " ymax=" << vehYmax
1452 << " smin=" << PState::stripe(vehYmin)
1453 << " smax=" << PState::stripe(vehYmax)
1454 << " relY=" << pRelY
1455 << " current=" << current
1456 << " vo.xFwd=" << vo.xFwd
1457 << " vo.xBack=" << vo.xBack
1458 << " vFront=" << vehFront
1459 << " vBack=" << vehBack
1460 << "\n";
1461 }
1462 }
1463 }
1464 return vehObs;
1465}
1466
1467
1468// ===========================================================================
1469// MSPModel_Striping::Obstacle method definitions
1470// ===========================================================================
1472 xFwd(dir * dist), // by default, far away when seen in dir
1473 xBack(dir * dist), // by default, far away when seen in dir
1474 speed(0),
1475 type(OBSTACLE_NONE),
1476 description("") {
1477}
1478
1479
1481 xFwd(ped.getMaxX()),
1482 xBack(ped.getMinX()),
1483 speed(ped.getDirection() * ped.getSpeed()),
1484 type(ped.getOType()),
1485 description(ped.getID()) {
1486 assert(!ped.isWaitingToEnter());
1487 if (type == OBSTACLE_VEHICLE) {
1488 vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
1489 }
1490}
1491
1492
1493bool
1495 if (dir == FORWARD) {
1496 return xBack <= o.xBack;
1497 } else {
1498 return xFwd >= o.xFwd;
1499 }
1500}
1501
1502
1503// ===========================================================================
1504// MSPModel_Striping::PState method definitions
1505// ===========================================================================
1507 MSPModel_InteractingState(person, stage, lane),
1508 myWalkingAreaPath(nullptr) {
1509 const MSEdge* currentEdge = &lane->getEdge();
1510 const ConstMSEdgeVector& route = myStage->getRoute();
1511 assert(!route.empty());
1512 myDir = FORWARD;
1513 if (route.size() == 1) {
1514 // only a single edge, move towards end pos
1516 } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
1517 // start on an intersection
1518 if (route.front()->isWalkingArea()) {
1519 myWalkingAreaPath = getArbitraryPath(route.front());
1520 }
1521 } else {
1522 int passedFwd = 0;
1523 int passedBwd = 0;
1524 const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
1525 const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
1526 if DEBUGCOND(*this) {
1527 std::cout << " initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
1528 }
1529 if (mayStartForward && mayStartBackward) {
1530 // figure out the best direction via routing
1531 ConstMSEdgeVector crossingRoute;
1532 MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myEdgePos, myStage->getArrivalPos(),
1533 myStage->getMaxSpeed(person), 0, nullptr, person->getVTypeParameter(), crossingRoute, true);
1534 if (crossingRoute.size() > 1) {
1535 // route found
1536 const MSEdge* nextEdge = crossingRoute[1];
1537 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
1538 myDir = BACKWARD;
1539 }
1540 }
1541 if DEBUGCOND(*this) {
1542 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
1543 }
1544 } else if (!mayStartForward && !mayStartBackward) {
1545 int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
1546 std::string dLoc;
1547 if (route.size() > 2) {
1548 dLoc = TLF(" between edge '%' and edge '%'", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID());
1549 }
1550 WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%, time=%."),
1551 myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc, SIMTIME);
1552 myDir = passedFwd >= passedBwd ? FORWARD : BACKWARD;
1553 } else {
1554 myDir = !mayStartBackward ? FORWARD : BACKWARD;
1555 }
1556 }
1559 myPosLat = 0;
1560 }
1561 if (lane->getVehicleNumberWithPartials() > 0 && myPosLat == 0) {
1562 // better start next to the road if nothing was specified
1564 }
1565 if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
1566 // start at the right side of the sidewalk on shared roads
1567 myPosLat = stripeWidth * (numStripes(lane) - 1) - myPosLat;
1568 }
1569 } else if (myPosLat == RANDOM_POS_LAT) {
1570 myPosLat = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
1571 } else {
1572 // vehicle to striping coordinate system
1574 }
1575 if DEBUGCOND(*this) {
1576 std::cout << " added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myEdgePos=" << myEdgePos << " myPosLat=" << myPosLat << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
1577 }
1578
1579 myNLI = getNextLane(*this, lane, nullptr);
1580}
1581
1582
1583MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in) :
1584 MSPModel_InteractingState(person, stage, nullptr),
1585 myWalkingAreaPath(nullptr) {
1586 if (in != nullptr) {
1587 std::string laneID;
1588 std::string wapLaneFrom;
1589 std::string wapLaneTo;
1590 std::string nextLaneID;
1591 std::string nextLinkFrom;
1592 std::string nextLinkTo;
1593 int nextDir;
1594
1595 (*in) >> laneID
1597 >> wapLaneFrom >> wapLaneTo
1598 >> myAmJammed
1599 >> nextLaneID
1600 >> nextLinkFrom
1601 >> nextLinkTo
1602 >> nextDir;
1603
1604
1605 myLane = MSLane::dictionary(laneID);
1606 if (myLane == nullptr) {
1607 throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1608 }
1609
1610 MSLane* nextLane = nullptr;
1611 if (nextLaneID != "null") {
1612 nextLane = MSLane::dictionary(nextLaneID);
1613 if (nextLane == nullptr) {
1614 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1615 }
1616 }
1617 const MSLink* link = nullptr;
1618 if (nextLinkFrom != "null") {
1619 MSLane* from = MSLane::dictionary(nextLinkFrom);
1620 MSLane* to = MSLane::dictionary(nextLinkTo);
1621 if (from == nullptr) {
1622 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1623 }
1624 if (to == nullptr) {
1625 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1626 }
1627 link = from->getLinkTo(to);
1628 }
1629 myNLI = NextLaneInfo(nextLane, link, nextDir);
1630
1631 if (wapLaneFrom != "null") {
1632 MSLane* from = MSLane::dictionary(wapLaneFrom);
1633 MSLane* to = MSLane::dictionary(wapLaneTo);
1634 if (from == nullptr) {
1635 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1636 }
1637 if (to == nullptr) {
1638 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1639 }
1640 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
1641 if (pathIt != myWalkingAreaPaths.end()) {
1642 myWalkingAreaPath = &pathIt->second;
1643 } else {
1644 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1645 }
1646 }
1647 }
1648}
1649
1650
1653
1654
1655void
1657 std::string wapLaneFrom = "null";
1658 std::string wapLaneTo = "null";
1659 if (myWalkingAreaPath != nullptr) {
1660 wapLaneFrom = myWalkingAreaPath->from->getID();
1661 wapLaneTo = myWalkingAreaPath->to->getID();
1662 }
1663 std::string nextLaneID = "null";
1664 std::string nextLinkFrom = "null";
1665 std::string nextLinkTo = "null";
1666 if (myNLI.lane != nullptr) {
1667 nextLaneID = myNLI.lane->getID();
1668 }
1669 if (myNLI.link != nullptr) {
1670 nextLinkFrom = myNLI.link->getLaneBefore()->getID();
1671 nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
1672 }
1673 out << " " << myLane->getID()
1674 << " " << myEdgePos
1675 << " " << myPosLat
1676 << " " << myDir
1677 << " " << mySpeed
1678 << " " << mySpeedLat
1679 << " " << myWaitingToEnter
1680 << " " << myWaitingTime
1681 << " " << wapLaneFrom
1682 << " " << wapLaneTo
1683 << " " << myAmJammed
1684 << " " << nextLaneID
1685 << " " << nextLinkFrom
1686 << " " << nextLinkTo
1687 << " " << myNLI.dir;
1688}
1689
1690double
1691MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
1692 // @todo speed should have an influence here because faster persons need more space
1693 if (myDir == FORWARD) {
1694 return myEdgePos - getLength();
1695 }
1696 return myEdgePos - (includeMinGap ? getMinGap() : 0.);
1697}
1698
1699
1700double
1701MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
1702 // @todo speed should have an influence here because faster persons need more space
1703 if (myDir == FORWARD) {
1704 return myEdgePos + (includeMinGap ? getMinGap() : 0.);
1705 }
1706 return myEdgePos + getLength();
1707}
1708
1709
1710double
1712 return myPerson->getVehicleType().getLength();
1713}
1714
1715
1716double
1718 return myPerson->getVehicleType().getMinGap();
1719}
1720
1721
1722int
1724 return (int)floor(relY / stripeWidth + 0.5);
1725}
1726
1727
1728int
1730 const int s = stripe(relY);
1731 const double offset = relY - s * stripeWidth;
1732 const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
1733 int result;
1734 if (offset > threshold) {
1735 result = s + 1;
1736 } else if (offset < -threshold) {
1737 result = s - 1;
1738 } else {
1739 result = s;
1740 }
1741 //std::cout.setf(std::ios::fixed , std::ios::floatfield);
1742 //std::cout << std::setprecision(5);
1743 //if DEBUGCOND(*this) std::cout << " otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
1744 return result;
1745}
1746
1747int
1749 return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
1750}
1751
1752
1753int
1755 return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
1756}
1757
1758
1759double
1761 if (myStage->getNextRouteEdge() == nullptr) {
1762 return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
1763 (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
1764 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
1765 ? getMinGap() : 0);
1766 } else {
1767 const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
1768 return myDir == FORWARD ? length - myEdgePos : myEdgePos;
1769 }
1770}
1771
1772
1773bool
1775 double dist = distToLaneEnd();
1776 if (DEBUGCOND(*this)) {
1777 std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
1778 }
1779 if (dist <= 0) {
1780 //if (ped.getPerson()->getID() == DEBUG1) {
1781 // std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
1782 //}
1783 //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
1784 //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
1785 const int oldDir = myDir;
1786 const MSLane* oldLane = myLane;
1787 myLane = myNLI.lane;
1788 myDir = myNLI.dir;
1789 const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
1790 if DEBUGCOND(*this) {
1791 std::cout << SIMTIME
1792 << " ped=" << myPerson->getID()
1793 << " moveToNextLane old=" << oldLane->getID()
1794 << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
1795 << " oldDir=" << oldDir
1796 << " newDir=" << myDir
1797 << " myEdgePos=" << myEdgePos
1798 << " dist=" << dist
1799 << "\n";
1800 }
1801 if (myLane == nullptr) {
1802 myEdgePos = myStage->getArrivalPos();
1803 }
1804 // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
1805 if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
1806 myLane = nullptr;
1807 } else {
1808 const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
1809 UNUSED_PARAMETER(arrived);
1810 assert(!arrived);
1811 assert(myDir != UNDEFINED_DIRECTION);
1812 myNLI = getNextLane(*this, myLane, oldLane);
1813 // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
1814 myStage->activateEntryReminders(myPerson);
1815 assert(myNLI.lane != oldLane); // do not turn around
1816 if DEBUGCOND(*this) {
1817 std::cout << " nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
1818 }
1819 if (myLane->isWalkingArea()) {
1820 if (myNLI.dir != UNDEFINED_DIRECTION) {
1821 myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
1822 assert(myWalkingAreaPath->shape.size() >= 2);
1823 if DEBUGCOND(*this) {
1824 std::cout << " mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
1825 }
1826 } else if (myNLI.link != nullptr) {
1827 // using direct connection (instead of using walkingarea)
1828 myLane = myNLI.lane;
1829 assert(!myLane->isWalkingArea());
1830 myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
1831 myWalkingAreaPath = nullptr;
1832 myNLI = getNextLane(*this, myLane, oldLane);
1833 } else {
1834 // disconnected route. move to the next edge
1835 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
1836 // try to determine direction from topology, otherwise maintain current direction
1837 const MSEdge* currRouteEdge = *myStage->getRouteStep();
1838 const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
1839 if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
1840 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
1841 myDir = BACKWARD;
1842 } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
1843 || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
1844 myDir = FORWARD;
1845 }
1846 myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
1847 myLane = myNLI.lane;
1848 assert(myLane != 0);
1849 assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
1850 myNLI = getNextLane(*this, myLane, oldLane);
1851 myWalkingAreaPath = nullptr;
1852 } else {
1853 throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
1854 }
1855 }
1856 } else {
1857 myWalkingAreaPath = nullptr;
1858 }
1859 // adapt x to fit onto the new lane
1860 // (make sure we do not move past the end of the new lane since that
1861 // lane was not checked for obstacles)
1862 const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
1863 if (-dist > newLength) {
1864 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
1865 // should not happen because the end of myLane should have been an obstacle as well
1866 // (only when the route is broken)
1867 dist = -newLength;
1868 }
1869 if (myDir == BACKWARD) {
1870 myEdgePos = newLength + dist;
1871 } else {
1872 myEdgePos = -dist;
1873 }
1874 if DEBUGCOND(*this) {
1875 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
1876 << " newLength=" << newLength
1877 << " dist=" << dist
1878 << " myEdgePos=" << myEdgePos
1879 << "\n";
1880 }
1881 // adjust to change in direction
1882 if (myDir != oldDir) {
1883 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
1884 }
1885 // adjust to differences in sidewalk width
1886 const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
1887 myPosLat += offset * stripeWidth;
1888 if DEBUGCOND(*this) {
1889 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
1890 << " newLane=" << Named::getIDSecure(myLane)
1891 << " newY=" << myPosLat
1892 << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
1893 << " od=" << oldDir << " nd=" << myDir
1894 << " offset=" << offset << "\n";
1895 }
1896 }
1897 myAngle = std::numeric_limits<double>::max(); // see #9014
1898 return true;
1899 } else {
1900 return false;
1901 }
1902}
1903
1904
1905int
1906MSPModel_Striping::getReserved(int stripes, double factor) {
1907 return MIN2(
1908 (int)floor(stripes * factor),
1910}
1911
1912void
1914 const int stripes = (int)obs.size();
1915 const int sMax = stripes - 1;
1916 assert(stripes == numStripes(myLane));
1917 // account stage-specific max speed but also for normal lane speed limit
1918 // (speed limits on crossings and walkingareas ignored due to #11527)
1919 const double vMax = (myStage->getConfiguredSpeed() >= 0
1920 ? myStage->getConfiguredSpeed()
1921 : (USE_NET_SPEEDS || myLane->isNormal() || myLane->isInternal()
1922 ? myLane->getVehicleMaxSpeed(myPerson)
1923 : myStage->getMaxSpeed(myPerson)));
1924 // ultimate goal is to choose the preferred stripe (chosen)
1925 const int current = stripe();
1926 const int other = otherStripe();
1927 // compute distances
1928 std::vector<double> distance(stripes);
1929 for (int i = 0; i < stripes; ++i) {
1930 distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
1931 }
1932 // compute utility for all stripes
1933 std::vector<double> utility(stripes, 0);
1934 // forbid stripes which are blocked and also all stripes behind them
1935 for (int i = 0; i < stripes; ++i) {
1936 if (distance[i] == DIST_OVERLAP) {
1937 if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
1938 utility[i] += OBSTRUCTED_PENALTY;
1939 }
1940 if (i < current) {
1941 for (int j = 0; j <= i; ++j) {
1942 utility[j] += OBSTRUCTED_PENALTY;
1943 }
1944 }
1945 if (i > current) {
1946 for (int j = i; j < stripes; ++j) {
1947 utility[j] += OBSTRUCTED_PENALTY;
1948 }
1949 }
1950 }
1951 }
1952 // forbid a portion of the leftmost stripes (in walking direction).
1953 // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
1954 // may still deadlock in heavy pedestrian traffic
1955 const bool onJunction = myLane->isWalkingArea() || myLane->isCrossing();
1956 const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
1957 if (myDir == FORWARD) {
1958 for (int i = 0; i < reserved; ++i) {
1959 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1960 }
1961 } else {
1962 for (int i = sMax; i > sMax - reserved; --i) {
1963 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1964 }
1965 }
1966 // adapt utility based on obstacles
1967 for (int i = 0; i < stripes; ++i) {
1968 if (obs[i].speed * myDir < 0) {
1969 // penalize evasion to the left unless the obstacle is a vehicle
1970 if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
1971 utility[i - 1] -= 0.5;
1972 } else if (myDir == BACKWARD && i < sMax) {
1973 utility[i + 1] -= 0.5;
1974 }
1975 }
1976 // compute expected distance achievable by staying on this stripe for a time horizon
1977 const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
1978 const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
1979 const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
1980 if (expectedDist >= 0) {
1981 utility[i] += expectedDist;
1982 } else {
1983 // let only the distance count
1984 utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
1985 }
1986 }
1987 // discourage use of the leftmost stripe (in walking direction) if there are oncoming
1988 if (myDir == FORWARD && obs[0].speed < 0) {
1989 utility[0] += ONCOMING_CONFLICT_PENALTY;
1990 } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
1991 utility[sMax] += ONCOMING_CONFLICT_PENALTY;
1992 }
1993 // penalize lateral movement (if the current stripe permits walking)
1994 if (distance[current] > 0 && myWaitingTime == 0) {
1995 for (int i = 0; i < stripes; ++i) {
1996 utility[i] += abs(i - current) * LATERAL_PENALTY;
1997 }
1998 }
1999 // walk on the right side on shared space
2000 if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
2001 for (int i = 0; i < stripes; ++i) {
2002 if (i <= current) {
2003 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
2004 }
2005 }
2006 }
2007
2008 // select best stripe
2009 int chosen = current;
2010 for (int i = 0; i < stripes; ++i) {
2011 if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
2012 chosen = i;
2013 }
2014 }
2015 // compute speed components along both axes
2016 const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
2017 double xDist = MIN3(distance[current], distance[other], distance[next]);
2018 if (next != chosen) {
2019 // ensure that we do not collide with an obstacle in the stripe beyond
2020 // next as this might become the 'other' stripe in the next step
2021 const int nextOther = chosen < current ? current - 2 : current + 2;
2022 xDist = MIN2(xDist, distance[nextOther]);
2023 }
2024 // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
2025 const double preferredGap = NUMERICAL_EPS;
2026 double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
2027 if (xSpeed < NUMERICAL_EPS) {
2028 xSpeed = 0.;
2029 }
2030 if (DEBUGCOND(*this)) {
2031 std::cout << " xSpeedPotential=" << xSpeed << "\n";
2032 }
2033 // avoid tiny steps
2034 // XXX pressure from behind?
2035 if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
2036 // unless walking towards a short lane
2037 !(
2038 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
2039 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
2040 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
2041 ) {
2042 xSpeed = 0;
2043 }
2044 if (xSpeed == 0) {
2045 if (DEBUGCOND(*this)) {
2046 std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
2047 << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
2048 << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
2049 << "\n";
2050 }
2051 if (myWaitingTime > ((myLane->isCrossing()
2052 // treat shared walkingarea like a crossing to avoid deadlocking vehicles
2053 || (myLane->isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
2054 && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
2055 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
2056 || myAmJammed) {
2057 // squeeze slowly through the crowd ignoring others
2058 if (!myAmJammed) {
2060 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
2061 myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
2062 myAmJammed = true;
2063 }
2064 xSpeed = vMax * jamFactor;
2065 }
2066 } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST) {
2067 myAmJammed = false;
2068 }
2069 // dawdling
2070 const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
2071 xSpeed -= dawdle;
2072
2073 // XXX ensure that diagonal speed <= vMax
2074 // avoid deadlocks on narrow sidewalks
2075 //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
2076 // if DEBUGCOND(*this) std::cout << " stepping aside to resolve oncoming deadlock\n";
2077 // xSpeed = POSITION_EPS; // reset myWaitingTime
2078 // if (myDir == FORWARD && chosen < sMax) {
2079 // chosen += 1;
2080 // } else if (myDir == BACKWARD && chosen > 0) {
2081 // chosen -= 1;
2082 // }
2083 //}
2084 const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
2085 double ySpeed = 0;
2086 double yDist = 0;
2087 if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
2088 // don't move laterally if the stripes are blocked
2089 yDist = (chosen * stripeWidth) - myPosLat;
2090 if (fabs(yDist) > NUMERICAL_EPS) {
2091 ySpeed = (yDist > 0 ?
2092 MIN2(maxYSpeed, DIST2SPEED(yDist)) :
2093 MAX2(-maxYSpeed, DIST2SPEED(yDist)));
2094 }
2095 } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
2096 // still on the road
2097 && stripe() == stripe(myPosLat)
2098 // only when the vehicle is moving on the same lane
2099 && !(myLane->isCrossing() || myLane->isWalkingArea())) {
2100 // step aside to let the vehicle pass
2101 int stepAsideDir = myDir;
2102 if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
2103 // always step to the right on multi-lane edges or when closer to
2104 // the right side
2105 stepAsideDir = FORWARD;
2106 }
2107 myAmJammed = true; // ignore pedestrian-pedestrian collisions
2108 ySpeed = stepAsideDir * vMax;
2109 }
2110
2111 // DEBUG
2112 if DEBUGCOND(*this) {
2113 std::cout << SIMTIME
2114 << " ped=" << myPerson->getID()
2115 << " edge=" << myStage->getEdge()->getID()
2116 << " x=" << myEdgePos
2117 << " y=" << myPosLat
2118 << " d=" << myDir
2119 << " pvx=" << mySpeed
2120 << " cur=" << current
2121 << " cho=" << chosen
2122 << " oth=" << other
2123 << " nxt=" << next
2124 << " vx=" << xSpeed
2125 << " dawdle=" << dawdle
2126 << " vy=" << ySpeed
2127 << " xd=" << xDist
2128 << " yd=" << yDist
2129 << " vMax=" << vMax
2130 << " wTime=" << myStage->getWaitingTime()
2131 << " jammed=" << myAmJammed
2132 << "\n";
2133 if (DEBUGCOND(*this)) {
2134 for (int i = 0; i < stripes; ++i) {
2135 const Obstacle& o = obs[i];
2136 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
2137 if (o.description != "") {
2138 std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
2139 }
2140 if (i == current) {
2141 std::cout << " current";
2142 }
2143 if (i == other && i != current) {
2144 std::cout << " other";
2145 }
2146 if (i == chosen) {
2147 std::cout << " chosen";
2148 }
2149 if (i == next) {
2150 std::cout << " next";
2151 }
2152 std::cout << "\n";
2153 }
2154 }
2155 }
2156 myEdgePos += SPEED2DIST(xSpeed * myDir);
2157 myPosLat += SPEED2DIST(ySpeed);
2158 mySpeedLat = ySpeed;
2159 mySpeed = xSpeed;
2160 if (xSpeed >= SUMO_const_haltingSpeed) {
2161 myWaitingToEnter = false;
2162 myWaitingTime = 0;
2163 } else {
2164 myWaitingTime += DELTA_T;
2165 myTotalWaitingTime += DELTA_T;
2166 }
2167 myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
2168}
2169
2170
2171double
2173 return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
2174 + STEPS2TIME(myStage->getWaitingTime()) / MAX_WAIT_TOLERANCE));
2175}
2176
2177
2180 if (myRemoteXYPos != Position::INVALID) {
2181 return myRemoteXYPos;
2182 }
2183 if (myLane == nullptr) {
2184 // pedestrian has already finished
2185 return Position::INVALID;
2186 }
2187 const double lateral_offset = -getLatOffset(); // the minus is hunting me in my dreams but seems to be here for historical reasons
2188 if (myWalkingAreaPath == nullptr) {
2189 return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
2190 } else {
2191 //if DEBUGCOND(*this) {
2192 // std::cout << SIMTIME
2193 // << " getPosition (walkingArea)"
2194 // << " p=" << myPerson->getID()
2195 // << " x=" << myEdgePos
2196 // << " y=" << myPosLat
2197 // << " latOffset=" << lateral_offset
2198 // << " shape=" << myWalkingAreaPath->shape
2199 // << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
2200 // << "\n";
2201 //}
2202 if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
2203 return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
2204 } else {
2205 const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
2206 return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
2207 }
2208 }
2209}
2210
2211
2212double
2214 if (myAngle != std::numeric_limits<double>::max()) {
2215 return myAngle;
2216 }
2217 if (myLane == nullptr) {
2218 // pedestrian has already finished
2219 return 0;
2220 }
2221 if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
2222 return myWalkingAreaPath->angleOverride;
2223 }
2224 const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
2225 double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
2226 double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
2227 if (myDir == MSPModel::BACKWARD) {
2228 angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2229 } else { // myDir == MSPModel::FORWARD
2230 angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2231 }
2232 if (angle > M_PI) {
2233 angle -= 2 * M_PI;
2234 }
2235 myAngle = angle;
2236 return angle;
2237}
2238
2239
2240const MSEdge*
2242 return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
2243}
2244
2245
2246const MSLane*
2248 return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
2249}
2250
2251
2252void
2253MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
2254 myEdgePos = pathLength - myEdgePos;
2255 myPosLat = usableWidth - myPosLat;
2256 myDir = -myWalkingAreaPath->dir;
2257 mySpeedLat = -mySpeedLat;
2258}
2259
2260
2261void
2262MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
2263 myEdgePos = edgePos;
2264 myPosLat = latPos;
2265 myDir = UNDEFINED_DIRECTION; // only an obstacle, speed may be orthogonal to dir
2266 mySpeed = 0.;
2267 mySpeedLat = 0.;
2268}
2269
2270
2271void
2272MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
2273 ConstMSEdgeVector newEdges; // keep route
2274 int routeOffset = 0;
2275 bool laneOnRoute = false;
2276 const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
2277 for (const MSEdge* edge : myStage->getRoute()) {
2278 if (edge == &lane->getEdge()
2279 || edge->getToJunction() == laneOnJunction
2280 || edge->getFromJunction() == laneOnJunction) {
2281 laneOnRoute = true;
2282 break;
2283 }
2284 routeOffset++;
2285 }
2286 if (!laneOnRoute) {
2287 throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
2288 }
2289 Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
2290 if (lane->isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
2291 // entered new walkingarea. Determine path to guess position
2292 const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
2293 const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
2294 const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
2295 const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
2296 if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
2297 throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
2298 + "' (fromLane='" + guessed->from->getID()
2299 + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2300 }
2301 // give some slack
2302 lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
2303 pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
2304 }
2305 const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
2306 moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
2307}
2308
2309
2310void
2312 double lanePosLat, double angle, int routeOffset,
2313 const ConstMSEdgeVector& edges, SUMOTime t) {
2315 assert(p == myPerson);
2316 assert(pm != nullptr);
2317 const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
2318 // person already walking in this step. undo this to obtain the previous position
2319 const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
2320 const double tmp = myEdgePos;
2321 myEdgePos = oldX;
2322 Position oldPos = getPosition(*myStage, t);
2323 myEdgePos = tmp;
2324 //if (oldPos == Position::INVALID) {
2325 // oldPos = pos
2326 //}
2327 myAngle = GeomHelper::fromNaviDegree(angle);
2328#ifdef DEBUG_MOVETOXY
2329 std::cout << SIMTIME << " ped=" << p->getID()
2330 << " moveToXY"
2331 << " pos=" << pos
2332 << " lane=" << lane->getID()
2333 << " lanePos=" << lanePos
2334 << " lanePosLat=" << lanePosLat
2335 << " angle=" << angle
2336 << " routeOffset=" << routeOffset
2337 << " edges=" << toString(edges)
2338 << " oldLane=" << Named::getIDSecure(myLane)
2339 << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
2340#endif
2341
2342 if (lane != myLane && myLane != nullptr && lane != nullptr) {
2343 pm->remove(this);
2344 pm->registerActive();
2345 }
2346 if (lane != nullptr &&
2347 fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
2348 myRemoteXYPos = Position::INVALID;
2349 const MSEdge* old = myStage->getEdge();
2350 const MSLane* oldLane = myLane;
2351 if (lane != myLane) {
2352 // implicitly adds new active lane if necessary
2353 pm->myActiveLanes[lane].push_back(this);
2354 }
2355 if (edges.empty()) {
2356 // map within route
2357 myStage->setRouteIndex(myPerson, routeOffset);
2358 } else {
2359 myStage->replaceRoute(myPerson, edges, routeOffset);
2360 }
2361 if (!lane->getEdge().isNormal()) {
2362 myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
2363 }
2364
2365 myLane = lane;
2366 const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
2367 if (lane->isWalkingArea()) {
2368 if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
2369 // entered new walkingarea. Determine path
2370 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
2371#ifdef DEBUG_MOVETOXY
2372 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
2373 << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
2374#endif
2375 }
2376 // lanePos and lanePosLat are matched onto the circumference of the
2377 // walkingarea. Use pos instead
2378 const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
2379 if (relPos == Position::INVALID) {
2380 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
2381 + "' (fromLane='" + myWalkingAreaPath->from->getID()
2382 + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2383 myRemoteXYPos = pos;
2384 } else {
2385 myEdgePos = relPos.x();
2386 myPosLat = lateral_offset + relPos.y();
2387 }
2388 } else {
2389 myWalkingAreaPath = nullptr;
2390 myEdgePos = lanePos;
2391 myPosLat = lateral_offset - lanePosLat;
2392 lane->requireCollisionCheck();
2393 }
2394 // guess direction
2395 const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
2396 if (myStage->getNextRouteEdge() != nullptr) {
2397 if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
2398 myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
2399 myDir = FORWARD;
2400 } else {
2401 myDir = BACKWARD;
2402 }
2403 } else {
2404 // guess from angle
2405 if (angleDiff <= 90) {
2406 // keep direction
2407 if (myDir == UNDEFINED_DIRECTION) {
2408 myDir = FORWARD;
2409 }
2410 } else {
2411 // change direction
2412 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
2413 }
2414 }
2415 // update next lane info (after guessing direction)
2416 if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
2417 const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
2418 // assume that we will eventually move back onto the sidewalk if
2419 // there is one
2420 myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
2421 myStage->activateEntryReminders(myPerson);
2422#ifdef DEBUG_MOVETOXY
2423 std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
2424#endif
2425 }
2426#ifdef DEBUG_MOVETOXY
2427 std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID()
2428 << " newPos=" << myPerson->getPosition()
2429 << " latOffset=" << getLatOffset()
2430 << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
2431#endif
2432 if (oldLane == myLane) {
2433 mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
2434 } else {
2435 //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
2436 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2437 }
2438 } else {
2439 // map outside the network
2440 myRemoteXYPos = pos;
2441 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2442 }
2443
2444}
2445
2446
2447double
2449 if (myWalkingAreaPath != nullptr) {
2450 return myWalkingAreaPath->length;
2451 } else {
2452 return 0;
2453 }
2454}
2455
2456double
2457MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
2458 // check for overlap
2459 const double maxX = getMaxX(includeMinGap);
2460 const double minX = getMinX(includeMinGap);
2461 //if (DEBUGCOND(*this)) {
2462 // std::cout << std::setprecision(2) << " distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
2463 //}
2464 if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
2465 // avoid blocking by itself on looped route
2466 return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
2467 }
2468 if (myDir == FORWARD) {
2469 return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
2470 } else {
2471 return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
2472 }
2473}
2474
2475
2476void
2478 for (int i = 0; i < (int)into.size(); ++i) {
2479 if (gDebugFlag1) {
2480 std::cout << " i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
2481 << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
2482 << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
2483 }
2484 const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
2485 const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
2486 if (dO < dI) {
2487 into[i] = obs2[i];
2488 } else if (dO == dI
2489 && into[i].type != OBSTACLE_PED
2490 && into[i].type != OBSTACLE_VEHICLE
2491 && (obs2[i].type == OBSTACLE_PED ||
2492 obs2[i].type == OBSTACLE_VEHICLE)) {
2493 into[i] = obs2[i];
2494 }
2495 }
2496}
2497
2498void
2499MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
2500 for (int i = 0; i < (int)into.size(); ++i) {
2501 int i2 = i + offset;
2502 if (i2 >= 0 && i2 < (int)obs2.size()) {
2503 if (dir == FORWARD) {
2504 if (obs2[i2].xBack < into[i].xBack) {
2505 into[i] = obs2[i2];
2506 }
2507 } else {
2508 if (obs2[i2].xFwd > into[i].xFwd) {
2509 into[i] = obs2[i2];
2510 }
2511 }
2512 }
2513 }
2514}
2515
2516
2517bool
2519 if (link->haveRed()) {
2520 const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
2521 if (ignoreRedTime >= 0) {
2522 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2523 if (DEBUGCOND(*this)) {
2524 std::cout << SIMTIME << " ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
2525 }
2526 return ignoreRedTime > redDuration;
2527 } else {
2528 return false;
2529 }
2530 } else {
2531 return false;
2532 }
2533}
2534
2535
2536bool
2538 // main use case is at rail_crossing
2539 if (link->haveYellow()) {
2540 const double ignoreYellowTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, -1);
2541 if (ignoreYellowTime >= 0) {
2542 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2543 if (DEBUGCOND(*this)) {
2544 std::cout << SIMTIME << " ignoreYellowTime=" << ignoreYellowTime << " yellowDuration=" << yellowDuration << "\n";
2545 }
2546 return ignoreYellowTime < yellowDuration;
2547 } else {
2548 return true;
2549 }
2550 } else {
2551 return false;
2552 }
2553}
2554
2555double
2557 return myPerson->getVehicleType().getWidth();
2558}
2559
2560
2561bool
2563 return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
2564}
2565
2566// ===========================================================================
2567// MSPModel_Striping::PStateVehicle method definitions
2568// ===========================================================================
2569
2570MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
2571 myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
2572 myLane = walkingarea; // to ensure correct limits when calling otherStripe()
2573 // relX is the center but we want it to be the max value if the movement direction is forward
2574 // and the min value otherwise (indicated by xWidth sign)
2575 myEdgePos = relX + xWidth / 2;
2576 myPosLat = relY;
2577}
2578
2579const std::string&
2581 return myVehicle->getID();
2582}
2583
2584double
2586 return myYWidth;
2587}
2588
2589double
2590MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
2591 return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
2592}
2593
2594double
2595MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
2596 return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
2597}
2598
2599// ===========================================================================
2600// MSPModel_Striping::MovePedestrians method definitions
2601// ===========================================================================
2602
2605 std::set<MSPerson*> changedLane;
2606 myModel->moveInDirection(currentTime, changedLane, FORWARD);
2607 myModel->moveInDirection(currentTime, changedLane, BACKWARD);
2608 // DEBUG
2609#ifdef LOG_ALL
2610 for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
2611 const MSLane* lane = it_lane->first;
2612 Pedestrians pedestrians = it_lane->second;
2613 if (pedestrians.size() == 0) {
2614 continue;
2615 }
2616 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
2617 std::cout << SIMTIME << " lane=" << lane->getID();
2618 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
2619 const PState& p = *pedestrians[ii];
2620 std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
2621 }
2622 std::cout << "\n";
2623 }
2624#endif
2625 return DELTA_T;
2626}
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:64
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:65
#define TIME2STEPS(x)
Definition SUMOTime.h:60
#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:43
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
T MIN3(T a, T b, T c)
Definition StdDefs.h:93
T MIN2(T a, T b)
Definition StdDefs.h:80
std::pair< int, double > MMVersion
(M)ajor/(M)inor version for written networks and default version for loading
Definition StdDefs.h:71
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h: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:408
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:269
A road/street connecting two junctions.
Definition MSEdge.h:77
static const MSEdgeVector & getAllEdges()
Returns all edges with a numerical id.
Definition MSEdge.cpp:1114
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:1286
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:2758
bool isWalkingArea() const
Definition MSLane.cpp:2650
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:625
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:966
bool isPriorityCrossing() const
Definition MSLane.cpp:2644
double getLength() const
Returns the lane's length.
Definition MSLane.h:617
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:2770
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:3308
void requireCollisionCheck()
require another collision check due to relevant changes in the simulation
Definition MSLane.h:721
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3228
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:2632
bool isCrossing() const
Definition MSLane.cpp:2638
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2495
bool isInternal() const
Definition MSLane.cpp:2626
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:4691
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:775
double getWidth() const
Returns the lane's width.
Definition MSLane.h:646
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:735
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:187
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:485
MMVersion getNetworkVersion() const
return the network version
Definition MSNet.h:823
MSPedestrianRouter & getPedestrianRouter(int rngIndex, const Prohibitions &prohibited={}) const
Definition MSNet.cpp:1641
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:392
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1265
std::vector< MSPModel_InteractingState * > Pedestrians
Pedestrians & getPedestrians(const MSLane *lane)
retrieves the pedestrian vector for the given lane (may be empty)
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
bool myAmActive
whether an event for pedestrian processing was added
int myNumActivePedestrians
the total number of active pedestrians
void registerActive()
increase the number of active pedestrians
virtual void remove(MSTransportableStateAdapter *state)
remove the specified person from the pedestrian simulation
static void unregisterCrossingApproach(const MSPModel_InteractingState &ped, const MSLane *crossing)
unregister pedestrian approach with the junction model
Container for pedestrian state and individual position update function.
SUMOTime myWaitingTime
the consecutive time spent at speed 0
MSPerson * myPerson
the person who is being represented
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
double myEdgePos
the advancement along the current lane
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
virtual const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
const Position & getRemotePosition() const
return the remote position if being controlled by TraCI or JuPedSim
const MSLane * myLane
the current lane of this pedestrian
double mySpeed
the current walking speed
MSStageMoving * myStage
the current stage of this pedestrian
double myPosLat
the orthogonal shift on the current lane
double mySpeedLat
the current lateral walking speed
bool isWaitingToEnter() const
whether the person still waits to entere the network
bool myWaitingToEnter
whether the pedestrian is waiting to start its walk
const MSLane * getLane() const
the current lane of the transportable
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:170
const MSEdge * getDestination() const
returns the destination edge
Definition MSStage.cpp:65
virtual double getArrivalPos() const
Definition MSStage.h:97
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition MSStage.h:88
Position getLanePosition(const MSLane *lane, double at, double offset) const
get position on lane at length at with orthogonal offset
Definition MSStage.cpp:176
virtual int getRoutePosition() const
return index of current edge within route
Definition MSStage.h:205
virtual const MSEdge * getNextRouteEdge() const =0
static const MSLane * checkDepartLane(const MSEdge *edge, SUMOVehicleClass svc, int laneIndex, const std::string &id)
interpret custom depart lane
const std::vector< const MSEdge * > & getRoute() const
int getDepartLane() const
double getConfiguredSpeed() const
Returns the configured speed in this stage.
virtual bool moveToNextEdge(MSTransportable *transportable, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)=0
move forward and return whether the transportable arrived
virtual double getMaxSpeed(const MSTransportable *const transportable=nullptr) const =0
the maximum speed of the transportable
int getNumWaitingPersons() const
get number of persons waiting at this stop
int getWaitingCapacity() const
get number of persons that can wait at this stop
bool checkPersonCapacity() const
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
void registerJammed()
register a jammed transportable
Position getPosition(const double) const override
Return current position (x/y, cartesian)
SUMOVehicleClass getVClass() const override
Returns the object's access class.
const SUMOVTypeParameter & getVTypeParameter() const override
Returns the object's "vehicle" type parameter.
bool isPerson() const override
Whether it is a person.
MSStageType getCurrentStageType() const
the current stage type of the transportable
const MSVehicleType & getVehicleType() const override
Returns the object's "vehicle" type.
const MSEdge * getEdge() const override
Returns the current edge.
abstract base class for managing callbacks to retrieve various state information from the model
Definition MSPModel.h:154
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, SumoRNG *rng=nullptr, bool readOnly=false)
Returns the named vehicle type or a sample from the named distribution.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
const Position getBackPosition() const
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:969
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
A storage for options typed value containers)
Definition OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
double compute(const E *from, const E *to, double departPos, double arrivalPos, double speed, SUMOTime msTime, const N *onlyNode, const SUMOVTypeParameter &pars, std::vector< const E * > &into, bool allEdges=false) const
Builds the route between the given edges using the minimum effort at the given time The definition of...
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:323
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
double x() const
Returns the x-position.
Definition Position.h:52
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:283
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
double length() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
PositionVector bezier(int numPoints)
return a bezier interpolation
void push_back_noDoublePos(const Position &p)
insert in back a non double position
PositionVector reverse() const
reverse position vector
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector....
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
std::map< const E *, RouterProhibition > Prohibitions
#define UNUSED_PARAMETER(x)
#define M_PI
Definition odrSpiral.cpp:45
int dir
the direction on the next lane
const MSLink * link
the link from the current lane to the next lane
const MSLane * lane
the next lane to be used
information regarding surround Pedestrians (and potentially other things)
double speed
speed relative to lane direction (positive means in the same direction)
double xFwd
maximal position on the current lane in forward direction
Obstacle(int dir, double dist=DIST_FAR_AWAY)
create No-Obstacle
bool closer(const Obstacle &o, int dir)
std::string description
the id / description of the obstacle
const SUMOVehicle * vehicle
a pointer to the vehicle if this obstacle is one
ObstacleType type
whether this obstacle denotes a border, a vehicle or a pedestrian
double xBack
maximal position on the current lane in backward direction