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
1598 >> wapLaneFrom >> wapLaneTo
1599 >> myAmJammed
1600 >> nextLaneID
1601 >> nextLinkFrom
1602 >> nextLinkTo
1603 >> nextDir;
1604
1605
1606 myLane = MSLane::dictionary(laneID);
1607 if (myLane == nullptr) {
1608 throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1609 }
1610
1611 MSLane* nextLane = nullptr;
1612 if (nextLaneID != "null") {
1613 nextLane = MSLane::dictionary(nextLaneID);
1614 if (nextLane == nullptr) {
1615 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1616 }
1617 }
1618 const MSLink* link = nullptr;
1619 if (nextLinkFrom != "null") {
1620 MSLane* from = MSLane::dictionary(nextLinkFrom);
1621 MSLane* to = MSLane::dictionary(nextLinkTo);
1622 if (from == nullptr) {
1623 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1624 }
1625 if (to == nullptr) {
1626 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1627 }
1628 link = from->getLinkTo(to);
1629 }
1630 myNLI = NextLaneInfo(nextLane, link, nextDir);
1631
1632 if (wapLaneFrom != "null") {
1633 MSLane* from = MSLane::dictionary(wapLaneFrom);
1634 MSLane* to = MSLane::dictionary(wapLaneTo);
1635 if (from == nullptr) {
1636 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1637 }
1638 if (to == nullptr) {
1639 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1640 }
1641 const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
1642 if (pathIt != myWalkingAreaPaths.end()) {
1643 myWalkingAreaPath = &pathIt->second;
1644 } else {
1645 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
1646 }
1647 }
1648 }
1649}
1650
1651
1654
1655
1656void
1658 std::string wapLaneFrom = "null";
1659 std::string wapLaneTo = "null";
1660 if (myWalkingAreaPath != nullptr) {
1661 wapLaneFrom = myWalkingAreaPath->from->getID();
1662 wapLaneTo = myWalkingAreaPath->to->getID();
1663 }
1664 std::string nextLaneID = "null";
1665 std::string nextLinkFrom = "null";
1666 std::string nextLinkTo = "null";
1667 if (myNLI.lane != nullptr) {
1668 nextLaneID = myNLI.lane->getID();
1669 }
1670 if (myNLI.link != nullptr) {
1671 nextLinkFrom = myNLI.link->getLaneBefore()->getID();
1672 nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
1673 }
1674 out << " " << myLane->getID()
1675 << " " << myEdgePos
1676 << " " << myPosLat
1677 << " " << myDir
1678 << " " << mySpeed
1679 << " " << mySpeedLat
1680 << " " << myWaitingToEnter
1681 << " " << myWaitingTime
1682 << " " << myTotalWaitingTime
1683 << " " << wapLaneFrom
1684 << " " << wapLaneTo
1685 << " " << myAmJammed
1686 << " " << nextLaneID
1687 << " " << nextLinkFrom
1688 << " " << nextLinkTo
1689 << " " << myNLI.dir;
1690}
1691
1692double
1693MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
1694 // @todo speed should have an influence here because faster persons need more space
1695 if (myDir == FORWARD) {
1696 return myEdgePos - getLength();
1697 }
1698 return myEdgePos - (includeMinGap ? getMinGap() : 0.);
1699}
1700
1701
1702double
1703MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
1704 // @todo speed should have an influence here because faster persons need more space
1705 if (myDir == FORWARD) {
1706 return myEdgePos + (includeMinGap ? getMinGap() : 0.);
1707 }
1708 return myEdgePos + getLength();
1709}
1710
1711
1712double
1714 return myPerson->getVehicleType().getLength();
1715}
1716
1717
1718double
1720 return myPerson->getVehicleType().getMinGap();
1721}
1722
1723
1724int
1726 return (int)floor(relY / stripeWidth + 0.5);
1727}
1728
1729
1730int
1732 const int s = stripe(relY);
1733 const double offset = relY - s * stripeWidth;
1734 const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
1735 int result;
1736 if (offset > threshold) {
1737 result = s + 1;
1738 } else if (offset < -threshold) {
1739 result = s - 1;
1740 } else {
1741 result = s;
1742 }
1743 //std::cout.setf(std::ios::fixed , std::ios::floatfield);
1744 //std::cout << std::setprecision(5);
1745 //if DEBUGCOND(*this) std::cout << " otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
1746 return result;
1747}
1748
1749int
1751 return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
1752}
1753
1754
1755int
1757 return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
1758}
1759
1760
1761double
1763 if (myStage->getNextRouteEdge() == nullptr) {
1764 return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
1765 (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
1766 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
1767 ? getMinGap() : 0);
1768 } else {
1769 const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
1770 return myDir == FORWARD ? length - myEdgePos : myEdgePos;
1771 }
1772}
1773
1774
1775bool
1777 double dist = distToLaneEnd();
1778 if (DEBUGCOND(*this)) {
1779 std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
1780 }
1781 if (dist <= 0) {
1782 //if (ped.getPerson()->getID() == DEBUG1) {
1783 // std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
1784 //}
1785 //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
1786 //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
1787 const int oldDir = myDir;
1788 const MSLane* oldLane = myLane;
1789 myLane = myNLI.lane;
1790 myDir = myNLI.dir;
1791 const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
1792 if DEBUGCOND(*this) {
1793 std::cout << SIMTIME
1794 << " ped=" << myPerson->getID()
1795 << " moveToNextLane old=" << oldLane->getID()
1796 << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
1797 << " oldDir=" << oldDir
1798 << " newDir=" << myDir
1799 << " myEdgePos=" << myEdgePos
1800 << " dist=" << dist
1801 << "\n";
1802 }
1803 if (myLane == nullptr) {
1804 myEdgePos = myStage->getArrivalPos();
1805 }
1806 // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
1807 if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
1808 myLane = nullptr;
1809 } else {
1810 const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
1811 UNUSED_PARAMETER(arrived);
1812 assert(!arrived);
1813 assert(myDir != UNDEFINED_DIRECTION);
1814 myNLI = getNextLane(*this, myLane, oldLane);
1815 // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
1816 myStage->activateEntryReminders(myPerson);
1817 assert(myNLI.lane != oldLane); // do not turn around
1818 if DEBUGCOND(*this) {
1819 std::cout << " nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
1820 }
1821 if (myLane->isWalkingArea()) {
1822 if (myNLI.dir != UNDEFINED_DIRECTION) {
1823 myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
1824 assert(myWalkingAreaPath->shape.size() >= 2);
1825 if DEBUGCOND(*this) {
1826 std::cout << " mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
1827 }
1828 } else if (myNLI.link != nullptr) {
1829 // using direct connection (instead of using walkingarea)
1830 myLane = myNLI.lane;
1831 assert(!myLane->isWalkingArea());
1832 myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
1833 myWalkingAreaPath = nullptr;
1834 myNLI = getNextLane(*this, myLane, oldLane);
1835 } else {
1836 // disconnected route. move to the next edge
1837 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
1838 // try to determine direction from topology, otherwise maintain current direction
1839 const MSEdge* currRouteEdge = *myStage->getRouteStep();
1840 const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
1841 if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
1842 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
1843 myDir = BACKWARD;
1844 } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
1845 || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
1846 myDir = FORWARD;
1847 }
1848 myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
1849 myLane = myNLI.lane;
1850 assert(myLane != 0);
1851 assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
1852 myNLI = getNextLane(*this, myLane, oldLane);
1853 myWalkingAreaPath = nullptr;
1854 } else {
1855 throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
1856 }
1857 }
1858 } else {
1859 myWalkingAreaPath = nullptr;
1860 }
1861 // adapt x to fit onto the new lane
1862 // (make sure we do not move past the end of the new lane since that
1863 // lane was not checked for obstacles)
1864 const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
1865 if (-dist > newLength) {
1866 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
1867 // should not happen because the end of myLane should have been an obstacle as well
1868 // (only when the route is broken)
1869 dist = -newLength;
1870 }
1871 if (myDir == BACKWARD) {
1872 myEdgePos = newLength + dist;
1873 } else {
1874 myEdgePos = -dist;
1875 }
1876 if DEBUGCOND(*this) {
1877 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
1878 << " newLength=" << newLength
1879 << " dist=" << dist
1880 << " myEdgePos=" << myEdgePos
1881 << "\n";
1882 }
1883 // adjust to change in direction
1884 if (myDir != oldDir) {
1885 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
1886 }
1887 // adjust to differences in sidewalk width
1888 const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
1889 myPosLat += offset * stripeWidth;
1890 if DEBUGCOND(*this) {
1891 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
1892 << " newLane=" << Named::getIDSecure(myLane)
1893 << " newY=" << myPosLat
1894 << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
1895 << " od=" << oldDir << " nd=" << myDir
1896 << " offset=" << offset << "\n";
1897 }
1898 }
1899 myAngle = std::numeric_limits<double>::max(); // see #9014
1900 return true;
1901 } else {
1902 return false;
1903 }
1904}
1905
1906
1907int
1908MSPModel_Striping::getReserved(int stripes, double factor) {
1909 return MIN2(
1910 (int)floor(stripes * factor),
1912}
1913
1914void
1916 const int stripes = (int)obs.size();
1917 const int sMax = stripes - 1;
1918 assert(stripes == numStripes(myLane));
1919 // account stage-specific max speed but also for normal lane speed limit
1920 // (speed limits on crossings and walkingareas ignored due to #11527)
1921 const double vMax = (myStage->getConfiguredSpeed() >= 0
1922 ? myStage->getConfiguredSpeed()
1923 : (USE_NET_SPEEDS || myLane->isNormal() || myLane->isInternal()
1924 ? myLane->getVehicleMaxSpeed(myPerson)
1925 : myStage->getMaxSpeed(myPerson)));
1926 // ultimate goal is to choose the preferred stripe (chosen)
1927 const int current = stripe();
1928 const int other = otherStripe();
1929 // compute distances
1930 std::vector<double> distance(stripes);
1931 for (int i = 0; i < stripes; ++i) {
1932 distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
1933 }
1934 // compute utility for all stripes
1935 std::vector<double> utility(stripes, 0);
1936 // forbid stripes which are blocked and also all stripes behind them
1937 for (int i = 0; i < stripes; ++i) {
1938 if (distance[i] == DIST_OVERLAP) {
1939 if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
1940 utility[i] += OBSTRUCTED_PENALTY;
1941 }
1942 if (i < current) {
1943 for (int j = 0; j <= i; ++j) {
1944 utility[j] += OBSTRUCTED_PENALTY;
1945 }
1946 }
1947 if (i > current) {
1948 for (int j = i; j < stripes; ++j) {
1949 utility[j] += OBSTRUCTED_PENALTY;
1950 }
1951 }
1952 }
1953 }
1954 // forbid a portion of the leftmost stripes (in walking direction).
1955 // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
1956 // may still deadlock in heavy pedestrian traffic
1957 const bool onJunction = myLane->isWalkingArea() || myLane->isCrossing();
1958 const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
1959 if (myDir == FORWARD) {
1960 for (int i = 0; i < reserved; ++i) {
1961 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1962 }
1963 } else {
1964 for (int i = sMax; i > sMax - reserved; --i) {
1965 utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1966 }
1967 }
1968 // adapt utility based on obstacles
1969 for (int i = 0; i < stripes; ++i) {
1970 if (obs[i].speed * myDir < 0) {
1971 // penalize evasion to the left unless the obstacle is a vehicle
1972 if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
1973 utility[i - 1] -= 0.5;
1974 } else if (myDir == BACKWARD && i < sMax) {
1975 utility[i + 1] -= 0.5;
1976 }
1977 }
1978 // compute expected distance achievable by staying on this stripe for a time horizon
1979 const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
1980 const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
1981 const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
1982 if (expectedDist >= 0) {
1983 utility[i] += expectedDist;
1984 } else {
1985 // let only the distance count
1986 utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
1987 }
1988 }
1989 // discourage use of the leftmost stripe (in walking direction) if there are oncoming
1990 if (myDir == FORWARD && obs[0].speed < 0) {
1991 utility[0] += ONCOMING_CONFLICT_PENALTY;
1992 } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
1993 utility[sMax] += ONCOMING_CONFLICT_PENALTY;
1994 }
1995 // penalize lateral movement (if the current stripe permits walking)
1996 if (distance[current] > 0 && myWaitingTime == 0) {
1997 for (int i = 0; i < stripes; ++i) {
1998 utility[i] += abs(i - current) * LATERAL_PENALTY;
1999 }
2000 }
2001 // walk on the right side on shared space
2002 if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
2003 for (int i = 0; i < stripes; ++i) {
2004 if (i <= current) {
2005 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
2006 }
2007 }
2008 }
2009
2010 // select best stripe
2011 int chosen = current;
2012 for (int i = 0; i < stripes; ++i) {
2013 if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
2014 chosen = i;
2015 }
2016 }
2017 // compute speed components along both axes
2018 const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
2019 double xDist = MIN3(distance[current], distance[other], distance[next]);
2020 if (next != chosen) {
2021 // ensure that we do not collide with an obstacle in the stripe beyond
2022 // next as this might become the 'other' stripe in the next step
2023 const int nextOther = chosen < current ? current - 2 : current + 2;
2024 xDist = MIN2(xDist, distance[nextOther]);
2025 }
2026 // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
2027 const double preferredGap = NUMERICAL_EPS;
2028 double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
2029 if (xSpeed < NUMERICAL_EPS) {
2030 xSpeed = 0.;
2031 }
2032 if (DEBUGCOND(*this)) {
2033 std::cout << " xSpeedPotential=" << xSpeed << "\n";
2034 }
2035 // avoid tiny steps
2036 // XXX pressure from behind?
2037 if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
2038 // unless walking towards a short lane
2039 !(
2040 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
2041 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
2042 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
2043 ) {
2044 xSpeed = 0;
2045 }
2046 if (xSpeed == 0) {
2047 if (DEBUGCOND(*this)) {
2048 std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
2049 << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
2050 << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
2051 << "\n";
2052 }
2053 if (myWaitingTime > ((myLane->isCrossing()
2054 // treat shared walkingarea like a crossing to avoid deadlocking vehicles
2055 || (myLane->isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
2056 && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
2057 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
2058 || myAmJammed) {
2059 // squeeze slowly through the crowd ignoring others
2060 if (!myAmJammed) {
2062 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
2063 myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
2064 myAmJammed = true;
2065 }
2066 xSpeed = vMax * jamFactor;
2067 }
2068 } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST) {
2069 myAmJammed = false;
2070 }
2071 // dawdling
2072 const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
2073 xSpeed -= dawdle;
2074
2075 // XXX ensure that diagonal speed <= vMax
2076 // avoid deadlocks on narrow sidewalks
2077 //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
2078 // if DEBUGCOND(*this) std::cout << " stepping aside to resolve oncoming deadlock\n";
2079 // xSpeed = POSITION_EPS; // reset myWaitingTime
2080 // if (myDir == FORWARD && chosen < sMax) {
2081 // chosen += 1;
2082 // } else if (myDir == BACKWARD && chosen > 0) {
2083 // chosen -= 1;
2084 // }
2085 //}
2086 const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
2087 double ySpeed = 0;
2088 double yDist = 0;
2089 if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
2090 // don't move laterally if the stripes are blocked
2091 yDist = (chosen * stripeWidth) - myPosLat;
2092 if (fabs(yDist) > NUMERICAL_EPS) {
2093 ySpeed = (yDist > 0 ?
2094 MIN2(maxYSpeed, DIST2SPEED(yDist)) :
2095 MAX2(-maxYSpeed, DIST2SPEED(yDist)));
2096 }
2097 } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
2098 // still on the road
2099 && stripe() == stripe(myPosLat)
2100 // only when the vehicle is moving on the same lane
2101 && !(myLane->isCrossing() || myLane->isWalkingArea())) {
2102 // step aside to let the vehicle pass
2103 int stepAsideDir = myDir;
2104 if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
2105 // always step to the right on multi-lane edges or when closer to
2106 // the right side
2107 stepAsideDir = FORWARD;
2108 }
2109 myAmJammed = true; // ignore pedestrian-pedestrian collisions
2110 ySpeed = stepAsideDir * vMax;
2111 }
2112
2113 // DEBUG
2114 if DEBUGCOND(*this) {
2115 std::cout << SIMTIME
2116 << " ped=" << myPerson->getID()
2117 << " edge=" << myStage->getEdge()->getID()
2118 << " x=" << myEdgePos
2119 << " y=" << myPosLat
2120 << " d=" << myDir
2121 << " pvx=" << mySpeed
2122 << " cur=" << current
2123 << " cho=" << chosen
2124 << " oth=" << other
2125 << " nxt=" << next
2126 << " vx=" << xSpeed
2127 << " dawdle=" << dawdle
2128 << " vy=" << ySpeed
2129 << " xd=" << xDist
2130 << " yd=" << yDist
2131 << " vMax=" << vMax
2132 << " wTime=" << myStage->getWaitingTime()
2133 << " jammed=" << myAmJammed
2134 << "\n";
2135 if (DEBUGCOND(*this)) {
2136 for (int i = 0; i < stripes; ++i) {
2137 const Obstacle& o = obs[i];
2138 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
2139 if (o.description != "") {
2140 std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
2141 }
2142 if (i == current) {
2143 std::cout << " current";
2144 }
2145 if (i == other && i != current) {
2146 std::cout << " other";
2147 }
2148 if (i == chosen) {
2149 std::cout << " chosen";
2150 }
2151 if (i == next) {
2152 std::cout << " next";
2153 }
2154 std::cout << "\n";
2155 }
2156 }
2157 }
2158 myEdgePos += SPEED2DIST(xSpeed * myDir);
2159 myPosLat += SPEED2DIST(ySpeed);
2160 mySpeedLat = ySpeed;
2161 mySpeed = xSpeed;
2162 if (xSpeed >= SUMO_const_haltingSpeed) {
2163 myWaitingToEnter = false;
2164 myWaitingTime = 0;
2165 } else {
2166 myWaitingTime += DELTA_T;
2167 myTotalWaitingTime += DELTA_T;
2168 }
2169 myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
2170}
2171
2172
2173double
2175 return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
2176 + STEPS2TIME(myStage->getWaitingTime()) / MAX_WAIT_TOLERANCE));
2177}
2178
2179
2182 if (myRemoteXYPos != Position::INVALID) {
2183 return myRemoteXYPos;
2184 }
2185 if (myLane == nullptr) {
2186 // pedestrian has already finished
2187 return Position::INVALID;
2188 }
2189 const double lateral_offset = -getLatOffset(); // the minus is hunting me in my dreams but seems to be here for historical reasons
2190 if (myWalkingAreaPath == nullptr) {
2191 return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
2192 } else {
2193 //if DEBUGCOND(*this) {
2194 // std::cout << SIMTIME
2195 // << " getPosition (walkingArea)"
2196 // << " p=" << myPerson->getID()
2197 // << " x=" << myEdgePos
2198 // << " y=" << myPosLat
2199 // << " latOffset=" << lateral_offset
2200 // << " shape=" << myWalkingAreaPath->shape
2201 // << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
2202 // << "\n";
2203 //}
2204 if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
2205 return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
2206 } else {
2207 const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
2208 return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
2209 }
2210 }
2211}
2212
2213
2214double
2216 if (myAngle != std::numeric_limits<double>::max()) {
2217 return myAngle;
2218 }
2219 if (myLane == nullptr) {
2220 // pedestrian has already finished
2221 return 0;
2222 }
2223 if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
2224 return myWalkingAreaPath->angleOverride;
2225 }
2226 const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
2227 double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
2228 double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
2229 if (myDir == MSPModel::BACKWARD) {
2230 angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2231 } else { // myDir == MSPModel::FORWARD
2232 angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
2233 }
2234 if (angle > M_PI) {
2235 angle -= 2 * M_PI;
2236 }
2237 myAngle = angle;
2238 return angle;
2239}
2240
2241
2242const MSEdge*
2244 return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
2245}
2246
2247
2248const MSLane*
2250 return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
2251}
2252
2253
2254void
2255MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
2256 myEdgePos = pathLength - myEdgePos;
2257 myPosLat = usableWidth - myPosLat;
2258 myDir = -myWalkingAreaPath->dir;
2259 mySpeedLat = -mySpeedLat;
2260}
2261
2262
2263void
2264MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
2265 myEdgePos = edgePos;
2266 myPosLat = latPos;
2267 myDir = UNDEFINED_DIRECTION; // only an obstacle, speed may be orthogonal to dir
2268 mySpeed = 0.;
2269 mySpeedLat = 0.;
2270}
2271
2272
2273void
2274MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
2275 ConstMSEdgeVector newEdges; // keep route
2276 int routeOffset = 0;
2277 bool laneOnRoute = false;
2278 const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
2279 for (const MSEdge* edge : myStage->getRoute()) {
2280 if (edge == &lane->getEdge()
2281 || edge->getToJunction() == laneOnJunction
2282 || edge->getFromJunction() == laneOnJunction) {
2283 laneOnRoute = true;
2284 break;
2285 }
2286 routeOffset++;
2287 }
2288 if (!laneOnRoute) {
2289 throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
2290 }
2291 Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
2292 if (lane->isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
2293 // entered new walkingarea. Determine path to guess position
2294 const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
2295 const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
2296 const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
2297 const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
2298 if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
2299 throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
2300 + "' (fromLane='" + guessed->from->getID()
2301 + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2302 }
2303 // give some slack
2304 lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
2305 pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
2306 }
2307 const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
2308 moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
2309}
2310
2311
2312void
2314 double lanePosLat, double angle, int routeOffset,
2315 const ConstMSEdgeVector& edges, SUMOTime t) {
2317 assert(p == myPerson);
2318 assert(pm != nullptr);
2319 const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
2320 // person already walking in this step. undo this to obtain the previous position
2321 const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
2322 const double tmp = myEdgePos;
2323 myEdgePos = oldX;
2324 Position oldPos = getPosition(*myStage, t);
2325 myEdgePos = tmp;
2326 //if (oldPos == Position::INVALID) {
2327 // oldPos = pos
2328 //}
2329 myAngle = GeomHelper::fromNaviDegree(angle);
2330#ifdef DEBUG_MOVETOXY
2331 std::cout << SIMTIME << " ped=" << p->getID()
2332 << " moveToXY"
2333 << " pos=" << pos
2334 << " lane=" << lane->getID()
2335 << " lanePos=" << lanePos
2336 << " lanePosLat=" << lanePosLat
2337 << " angle=" << angle
2338 << " routeOffset=" << routeOffset
2339 << " edges=" << toString(edges)
2340 << " oldLane=" << Named::getIDSecure(myLane)
2341 << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
2342#endif
2343
2344 if (lane != myLane && myLane != nullptr && lane != nullptr) {
2345 pm->remove(this);
2346 pm->registerActive();
2347 }
2348 if (lane != nullptr &&
2349 fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
2350 myRemoteXYPos = Position::INVALID;
2351 const MSEdge* old = myStage->getEdge();
2352 const MSLane* oldLane = myLane;
2353 if (lane != myLane) {
2354 // implicitly adds new active lane if necessary
2355 pm->myActiveLanes[lane].push_back(this);
2356 }
2357 if (edges.empty()) {
2358 // map within route
2359 myStage->setRouteIndex(myPerson, routeOffset);
2360 } else {
2361 myStage->replaceRoute(myPerson, edges, routeOffset);
2362 }
2363 if (!lane->getEdge().isNormal()) {
2364 myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
2365 }
2366
2367 myLane = lane;
2368 const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
2369 if (lane->isWalkingArea()) {
2370 if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
2371 // entered new walkingarea. Determine path
2372 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
2373#ifdef DEBUG_MOVETOXY
2374 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
2375 << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
2376#endif
2377 }
2378 // lanePos and lanePosLat are matched onto the circumference of the
2379 // walkingarea. Use pos instead
2380 const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
2381 if (relPos == Position::INVALID) {
2382 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
2383 + "' (fromLane='" + myWalkingAreaPath->from->getID()
2384 + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
2385 myRemoteXYPos = pos;
2386 } else {
2387 myEdgePos = relPos.x();
2388 myPosLat = lateral_offset + relPos.y();
2389 }
2390 } else {
2391 myWalkingAreaPath = nullptr;
2392 myEdgePos = lanePos;
2393 myPosLat = lateral_offset - lanePosLat;
2394 lane->requireCollisionCheck();
2395 }
2396 // guess direction
2397 const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
2398 if (myStage->getNextRouteEdge() != nullptr) {
2399 if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
2400 myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
2401 myDir = FORWARD;
2402 } else {
2403 myDir = BACKWARD;
2404 }
2405 } else {
2406 // guess from angle
2407 if (angleDiff <= 90) {
2408 // keep direction
2409 if (myDir == UNDEFINED_DIRECTION) {
2410 myDir = FORWARD;
2411 }
2412 } else {
2413 // change direction
2414 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
2415 }
2416 }
2417 // update next lane info (after guessing direction)
2418 if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
2419 const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
2420 // assume that we will eventually move back onto the sidewalk if
2421 // there is one
2422 myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
2423 myStage->activateEntryReminders(myPerson);
2424#ifdef DEBUG_MOVETOXY
2425 std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
2426#endif
2427 }
2428#ifdef DEBUG_MOVETOXY
2429 std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID()
2430 << " newPos=" << myPerson->getPosition()
2431 << " latOffset=" << getLatOffset()
2432 << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
2433#endif
2434 if (oldLane == myLane) {
2435 mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
2436 } else {
2437 //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
2438 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2439 }
2440 } else {
2441 // map outside the network
2442 myRemoteXYPos = pos;
2443 mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
2444 }
2445
2446}
2447
2448
2449double
2451 if (myWalkingAreaPath != nullptr) {
2452 return myWalkingAreaPath->length;
2453 } else {
2454 return 0;
2455 }
2456}
2457
2458double
2459MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
2460 // check for overlap
2461 const double maxX = getMaxX(includeMinGap);
2462 const double minX = getMinX(includeMinGap);
2463 //if (DEBUGCOND(*this)) {
2464 // std::cout << std::setprecision(2) << " distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
2465 //}
2466 if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
2467 // avoid blocking by itself on looped route
2468 return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
2469 }
2470 if (myDir == FORWARD) {
2471 return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
2472 } else {
2473 return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
2474 }
2475}
2476
2477
2478void
2480 for (int i = 0; i < (int)into.size(); ++i) {
2481 if (gDebugFlag1) {
2482 std::cout << " i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
2483 << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
2484 << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
2485 }
2486 const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
2487 const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
2488 if (dO < dI) {
2489 into[i] = obs2[i];
2490 } else if (dO == dI
2491 && into[i].type != OBSTACLE_PED
2492 && into[i].type != OBSTACLE_VEHICLE
2493 && (obs2[i].type == OBSTACLE_PED ||
2494 obs2[i].type == OBSTACLE_VEHICLE)) {
2495 into[i] = obs2[i];
2496 }
2497 }
2498}
2499
2500void
2501MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
2502 for (int i = 0; i < (int)into.size(); ++i) {
2503 int i2 = i + offset;
2504 if (i2 >= 0 && i2 < (int)obs2.size()) {
2505 if (dir == FORWARD) {
2506 if (obs2[i2].xBack < into[i].xBack) {
2507 into[i] = obs2[i2];
2508 }
2509 } else {
2510 if (obs2[i2].xFwd > into[i].xFwd) {
2511 into[i] = obs2[i2];
2512 }
2513 }
2514 }
2515 }
2516}
2517
2518
2519bool
2521 if (link->haveRed()) {
2522 const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
2523 if (ignoreRedTime >= 0) {
2524 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2525 if (DEBUGCOND(*this)) {
2526 std::cout << SIMTIME << " ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
2527 }
2528 return ignoreRedTime > redDuration;
2529 } else {
2530 return false;
2531 }
2532 } else {
2533 return false;
2534 }
2535}
2536
2537
2538bool
2540 // main use case is at rail_crossing
2541 if (link->haveYellow()) {
2542 const double ignoreYellowTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, -1);
2543 if (ignoreYellowTime >= 0) {
2544 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2545 if (DEBUGCOND(*this)) {
2546 std::cout << SIMTIME << " ignoreYellowTime=" << ignoreYellowTime << " yellowDuration=" << yellowDuration << "\n";
2547 }
2548 return ignoreYellowTime < yellowDuration;
2549 } else {
2550 return true;
2551 }
2552 } else {
2553 return false;
2554 }
2555}
2556
2557double
2559 return myPerson->getVehicleType().getWidth();
2560}
2561
2562
2563bool
2565 return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
2566}
2567
2568// ===========================================================================
2569// MSPModel_Striping::PStateVehicle method definitions
2570// ===========================================================================
2571
2572MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
2573 myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
2574 myLane = walkingarea; // to ensure correct limits when calling otherStripe()
2575 // relX is the center but we want it to be the max value if the movement direction is forward
2576 // and the min value otherwise (indicated by xWidth sign)
2577 myEdgePos = relX + xWidth / 2;
2578 myPosLat = relY;
2579}
2580
2581const std::string&
2583 return myVehicle->getID();
2584}
2585
2586double
2588 return myYWidth;
2589}
2590
2591double
2592MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
2593 return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
2594}
2595
2596double
2597MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
2598 return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
2599}
2600
2601// ===========================================================================
2602// MSPModel_Striping::MovePedestrians method definitions
2603// ===========================================================================
2604
2607 std::set<MSPerson*> changedLane;
2608 myModel->moveInDirection(currentTime, changedLane, FORWARD);
2609 myModel->moveInDirection(currentTime, changedLane, BACKWARD);
2610 // DEBUG
2611#ifdef LOG_ALL
2612 for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
2613 const MSLane* lane = it_lane->first;
2614 Pedestrians pedestrians = it_lane->second;
2615 if (pedestrians.size() == 0) {
2616 continue;
2617 }
2618 sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
2619 std::cout << SIMTIME << " lane=" << lane->getID();
2620 for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
2621 const PState& p = *pedestrians[ii];
2622 std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
2623 }
2624 std::cout << "\n";
2625 }
2626#endif
2627 return DELTA_T;
2628}
long long int SUMOTime
Definition GUI.h:36
#define DEG2RAD(x)
Definition GeomHelper.h:35
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
#define DEBUGCOND(PED)
#define DEBUGCOND2(LANE)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h: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:44
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
T MIN3(T a, T b, T c)
Definition StdDefs.h:93
T MIN2(T a, T b)
Definition StdDefs.h:80
std::pair< int, double > MMVersion
(M)ajor/(M)inor version for written networks and default version for loading
Definition StdDefs.h:71
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
Position getCenter() const
Returns the center of the boundary.
Definition Boundary.cpp:109
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition Boundary.cpp:75
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double getWidth() const
Returns the width of the boudary (x-axis)
Definition Boundary.cpp:151
void growWidth(double by)
Increases the width of the boundary (x-axis)
Definition Boundary.cpp:359
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
static double naviDegree(const double angle)
static double fromNaviDegree(const double angle)
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h: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:1120
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:1292
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:2784
bool isWalkingArea() const
Definition MSLane.cpp:2676
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:2670
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:2796
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:3334
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:3254
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:2658
bool isCrossing() const
Definition MSLane.cpp:2664
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2521
bool isInternal() const
Definition MSLane.cpp:2652
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:4719
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:199
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:495
MMVersion getNetworkVersion() const
return the network version
Definition MSNet.h:836
MSPedestrianRouter & getPedestrianRouter(int rngIndex, const Prohibitions &prohibited={}) const
Definition MSNet.cpp:1662
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:402
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1286
std::vector< MSPModel_InteractingState * > Pedestrians
Pedestrians & getPedestrians(const MSLane *lane)
retrieves the pedestrian vector for the given lane (may be empty)
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
bool myAmActive
whether an event for pedestrian processing was added
int myNumActivePedestrians
the total number of active pedestrians
void registerActive()
increase the number of active pedestrians
virtual void remove(MSTransportableStateAdapter *state)
remove the specified person from the pedestrian simulation
static void unregisterCrossingApproach(const MSPModel_InteractingState &ped, const MSLane *crossing)
unregister pedestrian approach with the junction model
Container for pedestrian state and individual position update function.
SUMOTime myWaitingTime
the consecutive time spent at speed 0
MSPerson * myPerson
the person who is being represented
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
double myEdgePos
the advancement along the current lane
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
virtual const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
const Position & getRemotePosition() const
return the remote position if being controlled by TraCI or JuPedSim
const MSLane * myLane
the current lane of this pedestrian
double mySpeed
the current walking speed
MSStageMoving * myStage
the current stage of this pedestrian
SUMOTime myTotalWaitingTime
the total time spent at speed 0
double myPosLat
the orthogonal shift on the current lane
double mySpeedLat
the current lateral walking speed
bool isWaitingToEnter() const
whether the person still waits to entere the network
bool myWaitingToEnter
whether the pedestrian is waiting to start its walk
const MSLane * getLane() const
the current lane of the transportable
double getSpeed() const
return the current speed of the transportable, we need to be able to do this for vehicles as well,...
int getDirection() const
return the walking direction (FORWARD, BACKWARD, UNDEFINED_DIRECTION)
bool myAmJammed
whether the person is jammed
bool isJammed() const
whether the transportable is jammed
SUMOTime execute(SUMOTime currentTime)
Executes the command.
Container for pedestrian state and individual position update function.
virtual double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
const WalkingAreaPath * myWalkingAreaPath
the current walkingAreaPath or 0
PState()
constructor for PStateVehicle
double distToLaneEnd() const
the absolute distance to the end of the lane in walking direction (or to the arrivalPos)
void mergeObstacles(Obstacles &into, const Obstacles &obs2)
replace obstacles in the first vector with obstacles from the second if they are closer to me
bool isRemoteControlled() const
whether the person is currently being controlled via TraCI
const MSEdge * getNextEdge(const MSStageMoving &stage) const
return the list of internal edges if the transportable is on an intersection
const MSLane * getNextCrossing() const
placeholder function for the accessing the next crossing
virtual double getWidth() const
return the person width
void saveState(std::ostringstream &out)
Saves the current state into the given stream.
bool ignoreRed(const MSLink *link) const
whether the pedestrian may ignore a red light
virtual double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
bool moveToNextLane(SUMOTime currentTime)
return whether this pedestrian has passed the end of the current lane and update myRelX if so
void reverse(const double pathLength, const double usableWidth)
double getMinGap() const
return the minimum gap of the pedestrian
void moveToXY(MSPerson *p, Position pos, MSLane *lane, double lanePos, double lanePosLat, double angle, int routeOffset, const ConstMSEdgeVector &edges, SUMOTime t)
try to move transportable to the given position
void moveTo(MSPerson *p, MSLane *lane, double lanePos, double lanePosLat, SUMOTime t)
try to move transportable to the given position
Position getPosition(const MSStageMoving &stage, SUMOTime now) const
return the network coordinate of the transportable
NextLaneInfo myNLI
information about the upcoming lane
double getAngle(const MSStageMoving &stage, SUMOTime now) const
return the current orientation in degrees
void reset(const double edgePos, const double latPos)
double getImpatience() const
returns the impatience
double distanceTo(const Obstacle &obs, const bool includeMinGap=true) const
bool stopForYellow(const MSLink *link) const
whether the pedestrian should stop at a yellow light
double getLength() const
return the length of the pedestrian
void walk(const Obstacles &obs)
perform position update
double getPathLength() const
return the total length of the current lane (in particular for on a walkingarea)
double getWidth() const
return the person width
double getMaxX(const bool includeMinGap=true) const
return the maximum position on the lane
double getMinX(const bool includeMinGap=true) const
return the minimum position on the lane
const std::string & getID() const
return ID of the person (or sometimes vehicle) being represented
PStateVehicle(const MSVehicle *veh, const MSLane *walkingarea, double relX, double relY, double xWidth, double yWidth)
sorts the persons by position on the lane. If dir is forward, higher x positions come first.
The pedestrian movement model using stripes on sidewalks.
static const double MIN_STARTUP_DIST
the minimum distance to the next obstacle in order to start walking after stopped
static void registerCrossingApproach(const PState &ped, const MSLane *crossing, const MSLane *beforeWA)
register pedestrian approach with the junction model
static double RESERVE_FOR_ONCOMING_FACTOR
fraction of the leftmost lanes to reserve for oncoming traffic
static MinNextLengths myMinNextLengths
static bool addVehicleFoe(const MSVehicle *veh, const MSLane *walkingarea, const Position &relPos, double xWidth, double yWidth, double lateral_offset, double minY, double maxY, Pedestrians &toDelete, Pedestrians &transformedPeds)
MSTransportableStateAdapter * loadState(MSTransportable *transportable, MSStageMoving *stage, std::istringstream &in)
load the state of the given transportable
static double posLatConversion(const double posLat, const double laneWidth)
Convert the striping to the vehicle lateral position and vice versa.
static SUMOTime jamTimeCrossing
void moveInDirection(SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
move all pedestrians forward and advance to the next lane if applicable
static bool USE_NET_SPEEDS
whether to use speed limits embedded in the network
static void transformToCurrentLanePositions(Obstacles &o, int currentDir, int nextDir, double currentLength, double nextLength)
static int myWalkingAreaDetail
intermediate points to smooth out lanes within the walkingarea
static const double LOOKAHEAD_SAMEDIR
the distance (in seconds) to look ahead for changing stripes
static double RESERVE_FOR_ONCOMING_MAX
std::map< const MSLane *, Obstacles, ComparatorNumericalIdLess > NextLanesObstacles
static double minGapToVehicle
the safety buffer to vehicles
static NextLaneInfo getNextLane(const PState &ped, const MSLane *currentLane, const MSLane *prevLane)
computes the successor lane for the given pedestrian and sets the link as well as the direction to us...
static const double LOOKAHEAD_ONCOMING_DIST
the distance (in m) to look ahead for obstacles on a subsequent edge
static void initWalkingAreaPaths(const MSNet *net)
static bool addCrossingVehs(const MSLane *crossing, int stripes, double lateral_offset, int dir, Obstacles &crossingVehs, bool prio, bool flipY)
add vehicles driving across
static const double LOOKAROUND_VEHICLES
the distance (in m) to look around for vehicles
static const double SQUEEZE
the factor by which pedestrian width is reduced when sqeezing past each other
static SUMOTime jamTimeNarrow
static const WalkingAreaPath * getWalkingAreaPath(const MSEdge *walkingArea, const MSLane *before, const MSLane *after)
void arriveAndAdvance(Pedestrians &pedestrians, SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
handle arrivals and lane advancement
std::map< const MSLane *, double > MinNextLengths
static double RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS
static int getStripeOffset(int origStripes, int destStripes, bool addRemainder)
static const WalkingAreaPath * guessPath(const MSEdge *walkingArea, const MSEdge *before, const MSEdge *after)
static int getReserved(int stripes, double factor)
static SUMOTime jamTime
the time threshold before becoming jammed
static void insertWalkArePaths(const MSEdge *edge, WalkingAreaPaths &into)
creates and inserts all paths into the given map
void moveInDirectionOnLane(Pedestrians &pedestrians, const MSLane *lane, SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir, bool debug)
move pedestrians forward on one lane
static double jamFactor
the factor on speed when jammed
static double stripeWidth
model parameters
static const double MAX_WAIT_TOLERANCE
the time pedestrians take to reach maximum impatience
static Obstacles getVehicleObstacles(const MSLane *lane, int dir, PState *ped=0)
retrieve vehicle obstacles on the given lane
static const double OBSTRUCTED_PENALTY
the utility penalty for obstructed (physically blocking me) stripes (corresponds to meters)
static const MSLane * getNextWalkingArea(const MSLane *currentLane, const int dir, const MSLink *&link)
return the next walkingArea in the given direction
MSTransportableStateAdapter * add(MSTransportable *transportable, MSStageMoving *stage, SUMOTime now)
register the given person as a pedestrian
static const double DIST_OVERLAP
static const WalkingAreaPath * getArbitraryPath(const MSEdge *walkingArea)
return an arbitrary path across the given walkingArea
static const double LATERAL_PENALTY
the utility penalty for moving sideways (corresponds to meters)
std::vector< Obstacle > Obstacles
static const double DIST_BEHIND
MSPModel_Striping(const OptionsCont &oc, MSNet *net)
Constructor (it should not be necessary to construct more than one instance)
static Obstacles getNeighboringObstacles(const Pedestrians &pedestrians, int egoIndex, int stripes)
static bool myLegacyPosLat
use old style departPosLat interpretation
static void addCloserObstacle(Obstacles &obs, double x, int stripe, int numStripes, const std::string &id, double width, int dir, ObstacleType type)
static double dawdling
the factor for random slow-down
static int numStripes(const MSLane *lane)
return the maximum number of pedestrians walking side by side
static const double OBSTRUCTION_THRESHOLD
the minimum utility that indicates obstruction
static int connectedDirection(const MSLane *from, const MSLane *to)
returns the direction in which these lanes are connectioned or 0 if they are not
static void DEBUG_PRINT(const Obstacles &obs)
static const double LATERAL_SPEED_FACTOR
the fraction of forward speed to be used for lateral movemenk
static const double INAPPROPRIATE_PENALTY
the utility penalty for inappropriate (reserved for oncoming traffic or may violate my min gap) strip...
static const double ONCOMING_CONFLICT_PENALTY
the utility penalty for oncoming conflicts on stripes (corresponds to meters)
static const double LOOKAHEAD_ONCOMING
the distance (in seconds) to look ahead for changing stripes (regarding oncoming pedestrians)
static std::map< const MSEdge *, std::vector< const MSLane * > > myWalkingAreaFoes
const Obstacles & getNextLaneObstacles(NextLanesObstacles &nextLanesObs, const MSLane *lane, const MSLane *nextLane, int stripes, int nextDir, double currentLength, int currentDir)
static const double DIST_FAR_AWAY
std::map< std::pair< const MSLane *, const MSLane * >, const WalkingAreaPath > WalkingAreaPaths
static WalkingAreaPaths myWalkingAreaPaths
store for walkinArea elements
static const int BACKWARD
Definition MSPModel.h:55
static int canTraverse(int dir, const ConstMSEdgeVector &route, int &passedEdges)
Definition MSPModel.cpp:54
static const int FORWARD
Definition MSPModel.h:54
static const double RANDOM_POS_LAT
magic value to encode randomized lateral offset for persons when starting a walk
Definition MSPModel.h:68
static const double SIDEWALK_OFFSET
the offset for computing person positions when walking on edges without a sidewalk
Definition MSPModel.h:62
static const int UNDEFINED_DIRECTION
Definition MSPModel.h:56
static const double UNSPECIFIED_POS_LAT
the default lateral offset for persons when starting a walk
Definition MSPModel.h:65
static const double SAFETY_GAP
Definition MSPModel.h:59
double getTimegapCrossing() const
Definition MSPerson.h:178
const MSEdge * getDestination() const
returns the destination edge
Definition MSStage.cpp:65
virtual double getArrivalPos() const
Definition MSStage.h:97
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition MSStage.h:88
Position getLanePosition(const MSLane *lane, double at, double offset) const
get position on lane at length at with orthogonal offset
Definition MSStage.cpp:183
virtual int getRoutePosition() const
return index of current edge within route
Definition MSStage.h:208
virtual const MSEdge * getNextRouteEdge() const =0
static const MSLane * checkDepartLane(const MSEdge *edge, SUMOVehicleClass svc, int laneIndex, const std::string &id)
interpret custom depart lane
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