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