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.org/sumo
3 // Copyright (C) 2014-2020 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/MSJunction.h>
34 #include <microsim/MSGlobals.h>
37 #include "MSPModel_Striping.h"
38 
39 
40 // ===========================================================================
41 // DEBUGGING HELPERS
42 // ===========================================================================
43 //
44 #define DEBUGID1 ""
45 #define DEBUGID2 ""
46 //#define DEBUGCOND(PED) (false)
47 //#define DEBUGCOND(PED) ((PED).myPerson->getID() == DEBUGID1 || (PED).myPerson->getID() == DEBUGID2)
48 #define DEBUGCOND(PED) ((PED).myPerson->isSelected())
49 #define DEBUGCOND2(LANE) ((LANE)->isSelected())
50 //#define LOG_ALL 1
51 //#define DEBUG_MOVETOXY
52 
54  for (int i = 0; i < (int)obs.size(); ++i) {
55  std::cout
56  << "(" << obs[i].description
57  << " x=(" << obs[i].xBack << "," << obs[i].xFwd
58  << ") s=" << obs[i].speed
59  << ") ";
60  }
61  std::cout << "\n";
62 }
63 
64 // ===========================================================================
65 // named (internal) constants
66 // ===========================================================================
67 
68 // distances are comparable with lower values being "more important"
69 const double MSPModel_Striping::DIST_FAR_AWAY(10000);
70 const double MSPModel_Striping::DIST_BEHIND(1000);
71 const double MSPModel_Striping::DIST_OVERLAP(-1);
72 
73 // ===========================================================================
74 // static members
75 // ===========================================================================
76 
78 std::map<const MSEdge*, std::vector<const MSLane*> > MSPModel_Striping::myWalkingAreaFoes;
81 
82 // model parameters (static to simplify access from class PState
88 const double MSPModel_Striping::LOOKAHEAD_SAMEDIR(4.0); // seconds
89 const double MSPModel_Striping::LOOKAHEAD_ONCOMING(10.0); // seconds
90 const double MSPModel_Striping::LOOKAROUND_VEHICLES(60.0); // meters
91 const double MSPModel_Striping::LATERAL_PENALTY(-1.); // meters
92 const double MSPModel_Striping::OBSTRUCTED_PENALTY(-300000.); // meters
93 const double MSPModel_Striping::INAPPROPRIATE_PENALTY(-20000.); // meters
94 const double MSPModel_Striping::ONCOMING_CONFLICT_PENALTY(-1000.); // meters
95 const double MSPModel_Striping::OBSTRUCTION_THRESHOLD(MSPModel_Striping::OBSTRUCTED_PENALTY * 0.5); // despite obstruction, additional utility may have been added
96 const double MSPModel_Striping::SQUEEZE(0.7);
99 const double MSPModel_Striping::MAX_WAIT_TOLERANCE(120.); // seconds
101 const double MSPModel_Striping::MIN_STARTUP_DIST(0.4); // meters
102 
103 #define MINGAP_TO_VEHICLE 0.25
104 
105 
106 // ===========================================================================
107 // MSPModel_Striping method definitions
108 // ===========================================================================
109 
111  myNumActivePedestrians(0),
112  myAmActive(false) {
114  // configurable parameters
115  stripeWidth = oc.getFloat("pedestrian.striping.stripe-width");
116  dawdling = oc.getFloat("pedestrian.striping.dawdling");
117  RESERVE_FOR_ONCOMING_FACTOR = oc.getFloat("pedestrian.striping.reserve-oncoming");
118  RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS = oc.getFloat("pedestrian.striping.reserve-oncoming.junctions");
119 
120  jamTime = string2time(oc.getString("pedestrian.striping.jamtime"));
121  if (jamTime <= 0) {
123  }
124  jamTimeCrossing = string2time(oc.getString("pedestrian.striping.jamtime.crossing"));
125  if (jamTimeCrossing <= 0) {
127  }
128  jamTimeNarrow = string2time(oc.getString("pedestrian.striping.jamtime.narrow"));
129  if (jamTimeNarrow <= 0) {
131  }
132 }
133 
134 
136  myActiveLanes.clear();
138  myWalkingAreaPaths.clear(); // need to recompute when lane pointers change
139  myWalkingAreaFoes.clear();
140  myMinNextLengths.clear();
141 }
142 
143 
146  if (!transportable->isPerson()) {
147  // containers are not supported (TODO add a warning here?)
148  return nullptr;
149  }
150  MSPerson* person = static_cast<MSPerson*>(transportable);
151  MSNet* net = MSNet::getInstance();
152  if (!myAmActive) {
154  myAmActive = true;
155  }
156  assert(person->getCurrentStageType() == MSStageType::WALKING);
157  const MSLane* lane = getSidewalk<MSEdge, MSLane>(person->getEdge());
158  if (lane == nullptr) {
159  std::string error = "Person '" + person->getID() + "' could not find sidewalk on edge '" + person->getEdge()->getID() + "', time="
160  + time2string(net->getCurrentTimeStep()) + ".";
161  if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
162  WRITE_WARNING(error);
163  return nullptr;
164  } else {
165  throw ProcessError(error);
166  }
167  }
168  PState* ped = new PState(person, stage, lane);
169  myActiveLanes[lane].push_back(ped);
171  return ped;
172 }
173 
174 
175 void
177  const MSLane* lane = dynamic_cast<PState*>(state)->myLane;
178  Pedestrians& pedestrians = myActiveLanes[lane];
179  for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
180  if (*it == state) {
181  pedestrians.erase(it);
183  return;
184  }
185  }
186 }
187 
188 
189 bool
190 MSPModel_Striping::blockedAtDist(const MSLane* lane, double vehSide, double vehWidth,
191  double oncomingGap, std::vector<const MSPerson*>* collectBlockers) {
192  const Pedestrians& pedestrians = getPedestrians(lane);
193  for (Pedestrians::const_iterator it_ped = pedestrians.begin(); it_ped != pedestrians.end(); ++it_ped) {
194  const PState& ped = **it_ped;
195  const double leaderFrontDist = (ped.myDir == FORWARD ? vehSide - ped.myRelX : ped.myRelX - vehSide);
196  const double leaderBackDist = leaderFrontDist + ped.getLength();
197  if DEBUGCOND(ped) {
198  std::cout << SIMTIME << " lane=" << lane->getID() << " dir=" << ped.myDir << " pX=" << ped.myRelX << " pL=" << ped.getLength()
199  << " vehSide=" << vehSide
200  << " vehWidth=" << vehWidth
201  << " lBD=" << leaderBackDist
202  << " lFD=" << leaderFrontDist
203  << "\n";
204  }
205  if (leaderBackDist >= -vehWidth
206  && (leaderFrontDist < 0
207  // give right of way to (close) approaching pedestrians unless they are standing
208  || (leaderFrontDist <= oncomingGap && ped.myWaitingTime < TIME2STEPS(2.0)))) {
209  // found one pedestrian that is not completely past the crossing point
210  //std::cout << SIMTIME << " blocking pedestrian foeLane=" << lane->getID() << " ped=" << ped.myPerson->getID() << " dir=" << ped.myDir << " pX=" << ped.myRelX << " pL=" << ped.getLength() << " fDTC=" << distToCrossing << " lBD=" << leaderBackDist << "\n";
211  if (collectBlockers == nullptr) {
212  return true;
213  } else {
214  collectBlockers->push_back(ped.myPerson);
215  }
216  }
217  }
218  if (collectBlockers == nullptr) {
219  return false;
220  } else {
221  return collectBlockers->size() > 0;
222  }
223 }
224 
225 
226 bool
228  return getPedestrians(lane).size() > 0;
229 }
230 
231 
232 bool
234  return usingInternalLanesStatic();
235 }
236 
237 bool
240 }
241 
243 MSPModel_Striping::nextBlocking(const MSLane* lane, double minPos, double minRight, double maxLeft, double stopTime) {
244  PersonDist result((const MSPerson*)nullptr, -1);
245  double closest = std::numeric_limits<double>::max();
246  const Pedestrians& pedestrians = getPedestrians(lane);
247  for (Pedestrians::const_iterator it_ped = pedestrians.begin(); it_ped != pedestrians.end(); ++it_ped) {
248  const PState& ped = **it_ped;
249  // account for distance covered by oncoming pedestrians
250  double relX2 = ped.myRelX - (ped.myDir == FORWARD ? 0 : stopTime * ped.myPerson->getVehicleType().getMaxSpeed());
251  if (ped.myRelX > minPos && (result.first == 0 || closest > relX2)) {
252  const double center = lane->getWidth() - (ped.myRelY + stripeWidth * 0.5);
253  const double halfWidth = 0.5 * ped.myPerson->getVehicleType().getWidth();
254  const bool overlap = (center + halfWidth > minRight && center - halfWidth < maxLeft);
255  if DEBUGCOND(ped) {
256  std::cout << " nextBlocking lane=" << lane->getID()
257  << " minPos=" << minPos << " minRight=" << minRight << " maxLeft=" << maxLeft
258  << " stopTime=" << stopTime
259  << " pedY=" << ped.myRelY
260  << " pedX=" << ped.myRelX
261  << " relX2=" << relX2
262  << " center=" << center
263  << " pedLeft=" << center + halfWidth
264  << " pedRight=" << center - halfWidth
265  << " overlap=" << overlap
266  << "\n";
267  }
268  if (overlap) {
269  closest = relX2;
270  result.first = ped.myPerson;
271  result.second = relX2 - minPos - (ped.myDir == FORWARD ? ped.myPerson->getVehicleType().getLength() : 0);
272  }
273  }
274  }
275  return result;
276 }
277 
278 
281  ActiveLanes::iterator it = myActiveLanes.find(lane);
282  if (it != myActiveLanes.end()) {
283  //std::cout << " found lane=" << lane->getID() << " n=" << it->second.size() << "\n";
284  return (it->second);
285  } else {
286  return noPedestrians;
287  }
288 }
289 
290 
291 int
293  return MAX2(1, (int)floor(lane->getWidth() / stripeWidth));
294 }
295 
296 int
298  if (from == nullptr || to == nullptr) {
299  return UNDEFINED_DIRECTION;
300  } else if (from->getLinkTo(to) != nullptr) {
301  return FORWARD;
302  } else if (to->getLinkTo(from) != nullptr) {
303  return BACKWARD;
304  } else {
305  return UNDEFINED_DIRECTION;
306  }
307 }
308 
309 
310 void
312  if (myWalkingAreaPaths.size() > 0) {
313  return;
314  }
315  // collect vehicle lanes that cross walkingareas
316  for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
317  const MSEdge* edge = *i;
318  if (!edge->isWalkingArea() && !edge->isCrossing()) {
319  for (MSLane* lane : edge->getLanes()) {
320  for (MSLink* link : lane->getLinkCont()) {
321  if (link->getWalkingAreaFoe() != nullptr) {
322  // link is an exit link
323  myWalkingAreaFoes[&link->getWalkingAreaFoe()->getEdge()].push_back(link->getLaneBefore());
324  //std::cout << " wa=" << link->getWalkingAreaFoe()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
325  }
326  if (link->getWalkingAreaFoeExit() != nullptr) {
327  // link is an exit link
328  myWalkingAreaFoes[&link->getWalkingAreaFoeExit()->getEdge()].push_back(link->getLaneBefore());
329  //std::cout << " wa=" << link->getWalkingAreaFoeExit()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
330  }
331  }
332  }
333  }
334  }
335 
336  // build walkingareaPaths
337  for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
338  const MSEdge* edge = *i;
339  if (edge->isWalkingArea()) {
340  const MSLane* walkingArea = getSidewalk<MSEdge, MSLane>(edge);
341  myMinNextLengths[walkingArea] = walkingArea->getLength();
342  // build all possible paths across this walkingArea
343  // gather all incident lanes
344  std::vector<const MSLane*> lanes;
345  for (const MSEdge* in : edge->getPredecessors()) {
346  if (!in->isTazConnector()) {
347  lanes.push_back(getSidewalk<MSEdge, MSLane>(in));
348  }
349  }
350  for (const MSEdge* out : edge->getSuccessors()) {
351  if (!out->isTazConnector()) {
352  lanes.push_back(getSidewalk<MSEdge, MSLane>(out));
353  }
354  }
355  // build all combinations
356  for (int j = 0; j < (int)lanes.size(); ++j) {
357  for (int k = 0; k < (int)lanes.size(); ++k) {
358  if (j != k) {
359  // build the walkingArea
360  const MSLane* const from = lanes[j];
361  const MSLane* const to = lanes[k];
362  const int fromDir = from->getLinkTo(walkingArea) != nullptr ? FORWARD : BACKWARD;
363  const int toDir = walkingArea->getLinkTo(to) != nullptr ? FORWARD : BACKWARD;
364  PositionVector shape;
365  Position fromPos = from->getShape()[fromDir == FORWARD ? -1 : 0];
366  Position toPos = to->getShape()[toDir == FORWARD ? 0 : -1];
367  const double maxExtent = fromPos.distanceTo2D(toPos) / 4; // prevent sharp corners
368  const double extrapolateBy = MIN2(maxExtent, walkingArea->getWidth() / 2);
369  // assemble shape
370  shape.push_back(fromPos);
371  if (extrapolateBy > POSITION_EPS) {
372  PositionVector fromShp = from->getShape();
373  fromShp.extrapolate(extrapolateBy);
374  shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
375  PositionVector nextShp = to->getShape();
376  nextShp.extrapolate(extrapolateBy);
377  shape.push_back_noDoublePos(toDir == FORWARD ? nextShp.front() : nextShp.back());
378  }
379  shape.push_back_noDoublePos(toPos);
380  if (shape.size() < 2) {
381  PositionVector fromShp = from->getShape();
382  fromShp.extrapolate(1.5 * POSITION_EPS); // noDoublePos requires a difference of POSITION_EPS in at least one coordinate
383  shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
384  assert(shape.size() == 2);
385  }
386  if (fromDir == BACKWARD) {
387  // will be walking backward on walkingArea
388  shape = shape.reverse();
389  }
390  WalkingAreaPath wap = WalkingAreaPath(from, walkingArea, to, shape, fromDir);
391  myWalkingAreaPaths.insert(std::make_pair(std::make_pair(from, to), wap));
392  myMinNextLengths[walkingArea] = MIN2(myMinNextLengths[walkingArea], wap.length);
393  }
394  }
395  }
396  }
397  }
398 }
399 
400 
403  assert(walkingArea->isWalkingArea());
404  std::vector<const MSLane*> lanes;
405  for (const MSEdge* const pred : walkingArea->getPredecessors()) {
406  lanes.push_back(getSidewalk<MSEdge, MSLane>(pred));
407  }
408  for (const MSEdge* const succ : walkingArea->getSuccessors()) {
409  lanes.push_back(getSidewalk<MSEdge, MSLane>(succ));
410  }
411  if (lanes.size() < 1) {
412  throw ProcessError("Invalid walkingarea '" + walkingArea->getID() + "' does not allow continuation.");
413  }
414  return &myWalkingAreaPaths.find(std::make_pair(lanes.front(), lanes.back()))->second;
415 }
416 
418 MSPModel_Striping::guessPath(const MSEdge* walkingArea, const MSEdge* before, const MSEdge* after) {
419  assert(walkingArea->isWalkingArea());
420  const MSLane* swBefore = getSidewalk<MSEdge, MSLane>(before);
421  const MSLane* swAfter = getSidewalk<MSEdge, MSLane>(after);
422  const auto pathIt = myWalkingAreaPaths.find(std::make_pair(swBefore, swAfter));
423  if (pathIt != myWalkingAreaPaths.end()) {
424  return &pathIt->second;
425  }
426  const MSEdgeVector& preds = walkingArea->getPredecessors();
427  const MSEdgeVector& succs = walkingArea->getSuccessors();
428  bool useBefore = swBefore != nullptr && std::find(preds.begin(), preds.end(), before) != preds.end();
429  bool useAfter = swAfter != nullptr && std::find(succs.begin(), succs.end(), after) != succs.end();
430  if (useBefore) {
431  if (useAfter) {
432  return getWalkingAreaPath(walkingArea, swBefore, swAfter);
433  } else if (succs.size() > 0) {
434  // could also try to exploit direction
435  return getWalkingAreaPath(walkingArea, swBefore, getSidewalk<MSEdge, MSLane>(succs.front()));
436  }
437  } else if (useAfter && preds.size() > 0) {
438  // could also try to exploit direction
439  return getWalkingAreaPath(walkingArea, getSidewalk<MSEdge, MSLane>(preds.front()), swAfter);
440  }
441  return getArbitraryPath(walkingArea);
442 }
443 
444 
446 MSPModel_Striping::getWalkingAreaPath(const MSEdge* walkingArea, const MSLane* before, const MSLane* after) {
447  assert(walkingArea->isWalkingArea());
448  const auto pathIt = myWalkingAreaPaths.find(std::make_pair(before, after));
449  if (pathIt != myWalkingAreaPaths.end()) {
450  return &pathIt->second;
451  } else {
452  // this can happen in case of moveToXY where before can point anywhere
453  const MSEdgeVector& preds = walkingArea->getPredecessors();
454  if (preds.size() > 0) {
455  const MSEdge* const pred = walkingArea->getPredecessors().front();
456  const auto pathIt2 = myWalkingAreaPaths.find(std::make_pair(getSidewalk<MSEdge, MSLane>(pred), after));
457  assert(pathIt2 != myWalkingAreaPaths.end());
458  return &pathIt2->second;
459  } else {
460  return getArbitraryPath(walkingArea);
461  }
462  }
463 }
464 
465 
466 
468 MSPModel_Striping::getNextLane(const PState& ped, const MSLane* currentLane, const MSLane* prevLane) {
469  const MSEdge* currentEdge = &currentLane->getEdge();
470  const MSJunction* junction = ped.myDir == FORWARD ? currentEdge->getToJunction() : currentEdge->getFromJunction();
471  const MSEdge* nextRouteEdge = ped.myStage->getNextRouteEdge();
472  const MSLane* nextRouteLane = getSidewalk<MSEdge, MSLane>(nextRouteEdge);
473  // result values
474  const MSLane* nextLane = nextRouteLane;
475  const MSLink* link = nullptr;
476  int nextDir = UNDEFINED_DIRECTION;
477 
478  //if DEBUGCOND(ped) {
479  // std::cout << " nextRouteLane=" << Named::getIDSecure(nextRouteLane) << " junction=" << junction->getID() << "\n";
480  //}
481  if (nextRouteLane == nullptr && nextRouteEdge != nullptr) {
482  std::string error = "Person '" + ped.myPerson->getID() + "' could not find sidewalk on edge '" + nextRouteEdge->getID() + "', time="
483  + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".";
484  if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
485  WRITE_WARNING(error);
486  nextRouteLane = nextRouteEdge->getLanes().front();
487  } else {
488  throw ProcessError(error);
489  }
490  }
491 
492  if (nextRouteLane != nullptr) {
493  if (currentEdge->isInternal()) {
494  assert(junction == currentEdge->getFromJunction());
495  nextDir = junction == nextRouteEdge->getFromJunction() ? FORWARD : BACKWARD;
496  if (nextDir == FORWARD) {
497  nextLane = currentLane->getLinkCont()[0]->getViaLaneOrLane();
498  } else {
499  nextLane = currentLane->getLogicalPredecessorLane();
500  }
501  if DEBUGCOND(ped) {
502  std::cout << " internal\n";
503  }
504  } else if (currentEdge->isCrossing()) {
505  nextDir = ped.myDir;
506  if (ped.myDir == FORWARD) {
507  nextLane = currentLane->getLinkCont()[0]->getLane();
508  } else {
509  nextLane = currentLane->getLogicalPredecessorLane();
510  }
511  if DEBUGCOND(ped) {
512  std::cout << " crossing\n";
513  }
514  } else if (currentEdge->isWalkingArea()) {
515  ConstMSEdgeVector crossingRoute;
516  // departPos can be 0 because the direction of the walkingArea does not matter
517  // for the arrivalPos, we need to make sure that the route does not deviate across other junctions
518  const int nextRouteEdgeDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
519  const double arrivalPos = (nextRouteEdge == ped.myStage->getRoute().back()
520  ? ped.myStage->getArrivalPos()
521  : (nextRouteEdgeDir == FORWARD ? 0 : nextRouteEdge->getLength()));
522  MSEdgeVector prohibited;
523  if (prevLane != nullptr) {
524  prohibited.push_back(&prevLane->getEdge());
525  }
526  MSNet::getInstance()->getPedestrianRouter(0, prohibited).compute(currentEdge, nextRouteEdge, 0, arrivalPos, ped.myStage->getMaxSpeed(ped.myPerson), 0, junction, crossingRoute, true);
527  if DEBUGCOND(ped) {
528  std::cout
529  << " nre=" << nextRouteEdge->getID()
530  << " nreDir=" << nextRouteEdgeDir
531  << " aPos=" << arrivalPos
532  << " crossingRoute=" << toString(crossingRoute)
533  << "\n";
534  }
535  if (crossingRoute.size() > 1) {
536  const MSEdge* nextEdge = crossingRoute[1];
537  nextLane = getSidewalk<MSEdge, MSLane>(crossingRoute[1]);
538  assert((nextEdge->getFromJunction() == junction || nextEdge->getToJunction() == junction));
539  assert(nextLane != prevLane);
540  nextDir = connectedDirection(currentLane, nextLane);
541  if DEBUGCOND(ped) {
542  std::cout << " nextDir=" << nextDir << "\n";
543  }
544  assert(nextDir != UNDEFINED_DIRECTION);
545  if (nextDir == FORWARD) {
546  link = currentLane->getLinkTo(nextLane);
547  } else {
548  link = nextLane->getLinkTo(currentLane);
549  if (nextEdge->isCrossing() && link->getTLLogic() == nullptr) {
550  const MSLane* oppositeWalkingArea = nextLane->getLogicalPredecessorLane();
551  link = oppositeWalkingArea->getLinkTo(nextLane);
552  }
553  }
554  assert(link != nullptr);
555  } else {
556  if DEBUGCOND(ped) {
557  std::cout << SIMTIME
558  << " no route from '" << (currentEdge == nullptr ? "NULL" : currentEdge->getID())
559  << "' to '" << (nextRouteEdge == nullptr ? "NULL" : nextRouteEdge->getID())
560  << "\n";
561  }
562  WRITE_WARNING("Person '" + ped.myPerson->getID() + "' could not find route across junction '" + junction->getID()
563  + "' from walkingArea '" + currentEdge->getID()
564  + "' to edge '" + nextRouteEdge->getID() + "', time=" +
565  time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
566  // error indicated by nextDir == UNDEFINED_DIRECTION
567  nextLane = nextRouteLane;
568  }
569  } else if (currentEdge == nextRouteEdge) {
570  // strange loop in this route. No need to use walkingArea
571  nextDir = -ped.myDir;
572  } else {
573  // normal edge. by default use next / previous walking area
574  nextDir = ped.myDir;
575  nextLane = getNextWalkingArea(currentLane, ped.myDir, link);
576  if (nextLane != nullptr) {
577  // walking area found
578  if DEBUGCOND(ped) {
579  std::cout << " next walkingArea " << (nextDir == FORWARD ? "forward" : "backward") << "\n";
580  }
581  } else {
582  // walk forward by default
583  nextDir = junction == nextRouteEdge->getToJunction() ? BACKWARD : FORWARD;
584  // try to use a direct link as fallback
585  // direct links only exist if built explicitly. They are used to model tl-controlled links if there are no crossings
586  if (ped.myDir == FORWARD) {
587  link = currentLane->getLinkTo(nextRouteLane);
588  if (link != nullptr) {
589  if DEBUGCOND(ped) {
590  std::cout << " direct forward\n";
591  }
592  nextLane = currentLane->getInternalFollowingLane(nextRouteLane);
593  }
594  } else {
595  link = nextRouteLane->getLinkTo(currentLane);
596  if (link != nullptr) {
597  if DEBUGCOND(ped) {
598  std::cout << " direct backward\n";
599  }
600  nextLane = nextRouteLane->getInternalFollowingLane(currentLane);
601  if (nextLane != nullptr) {
602  // advance to the end of consecutive internal lanes
603  while (nextLane->getLinkCont()[0]->getViaLaneOrLane()->isInternal()) {
604  nextLane = nextLane->getLinkCont()[0]->getViaLaneOrLane();
605  }
606  }
607  }
608  }
609  }
610  if (nextLane == nullptr) {
611  // no internal lane found
612  nextLane = nextRouteLane;
613  if DEBUGCOND(ped) {
614  std::cout << SIMTIME << " no next lane found for " << currentLane->getID() << " dir=" << ped.myDir << "\n";
615  }
616  if (usingInternalLanesStatic() && currentLane->getLinkCont().size() > 0 && MSNet::getInstance()->hasPedestrianNetwork()) {
617  WRITE_WARNING("Person '" + ped.myPerson->getID() + "' could not find route across junction '" + junction->getID()
618  + "' from edge '" + currentEdge->getID()
619  + "' to edge '" + nextRouteEdge->getID() + "', time=" +
620  time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
621  }
622  } else if (nextLane->getLength() <= POSITION_EPS) {
623  // internal lane too short
624  // most often this is due to a zero-size junction. However, if
625  // the person needs to pass a crossing we cannot skip ahead
626  if ((nextLane->getCanonicalSuccessorLane() == nullptr
627  || !nextLane->getCanonicalSuccessorLane()->getEdge().isCrossing())
628  && (nextLane->getLogicalPredecessorLane() == nullptr ||
629  !nextLane->getLogicalPredecessorLane()->getEdge().isCrossing())) {
630  //WRITE_WARNING("Person '" + ped.getID()
631  // + "' skips short lane '" + nextLane->getID()
632  // + "' length=" + toString(nextLane->getLength())
633  // + " time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
634  nextLane = nextRouteLane;
635  nextDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
636  }
637  }
638  }
639  }
640  if DEBUGCOND(ped) {
641  std::cout << SIMTIME
642  << " p=" << ped.myPerson->getID()
643  << " l=" << currentLane->getID()
644  << " nl=" << (nextLane == nullptr ? "NULL" : nextLane->getID())
645  << " nrl=" << (nextRouteLane == nullptr ? "NULL" : nextRouteLane->getID())
646  << " d=" << nextDir
647  << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
648  << " pedDir=" << ped.myDir
649  << "\n";
650  }
651  assert(nextLane != 0 || nextRouteLane == 0);
652  return NextLaneInfo(nextLane, link, nextDir);
653 }
654 
655 
656 const MSLane*
657 MSPModel_Striping::getNextWalkingArea(const MSLane* currentLane, const int dir, const MSLink*& link) {
658  if (dir == FORWARD) {
659  for (const MSLink* const l : currentLane->getLinkCont()) {
660  if (l->getLane()->getEdge().isWalkingArea()) {
661  link = l;
662  return l->getLane();
663  }
664  }
665  } else {
666  const std::vector<MSLane::IncomingLaneInfo>& laneInfos = currentLane->getIncomingLanes();
667  for (std::vector<MSLane::IncomingLaneInfo>::const_iterator it = laneInfos.begin(); it != laneInfos.end(); ++it) {
668  if ((*it).lane->getEdge().isWalkingArea()) {
669  link = (*it).viaLink;
670  return (*it).lane;
671  }
672  }
673  }
674  return nullptr;
675 }
676 
677 
679 MSPModel_Striping::getNeighboringObstacles(const Pedestrians& pedestrians, int egoIndex, int stripes) {
680  const PState& ego = *pedestrians[egoIndex];
681  const int egoStripe = ego.stripe();
682  Obstacles obs(stripes, Obstacle(ego.myDir));
683  std::vector<bool> haveBlocker(stripes, false);
684  for (int index = egoIndex + 1; index < (int)pedestrians.size(); index++) {
685  const PState& p = *pedestrians[index];
686  if DEBUGCOND(ego) {
687  std::cout << SIMTIME << " ped=" << ego.getID() << " cur=" << egoStripe << " checking neighbor " << p.getID()
688  << " nCur=" << p.stripe() << " nOth=" << p.otherStripe();
689  }
690  if (!p.myWaitingToEnter && !p.myAmJammed) {
691  const Obstacle o(p);
692  if DEBUGCOND(ego) {
693  std::cout << " dist=" << ego.distanceTo(o) << std::endl;
694  }
695  if (ego.distanceTo(o) == DIST_BEHIND) {
696  break;
697  }
698  if (ego.distanceTo(o) == DIST_OVERLAP) {
699  if (p.stripe() != egoStripe || p.myDir != ego.myDir) {
700  obs[p.stripe()] = o;
701  haveBlocker[p.stripe()] = true;
702  } else {
703  //std::cout << SIMTIME << " ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe=" << egoStripe << "\n";
704  }
705  if (p.otherStripe() != egoStripe || p.myDir != ego.myDir) {
706  obs[p.otherStripe()] = o;
707  haveBlocker[p.otherStripe()] = true;
708  } else {
709  //std::cout << SIMTIME << " ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe2=" << egoStripe << "\n";
710  }
711  } else {
712  if (!haveBlocker[p.stripe()]) {
713  obs[p.stripe()] = o;
714  }
715  if (!haveBlocker[p.otherStripe()]) {
716  obs[p.otherStripe()] = o;
717  }
718  }
719  }
720  }
721  if DEBUGCOND(ego) {
722  std::cout << SIMTIME << " ped=" << ego.myPerson->getID() << " neighObs=";
723  DEBUG_PRINT(obs);
724  }
725  return obs;
726 }
727 
728 
729 int
730 MSPModel_Striping::getStripeOffset(int origStripes, int destStripes, bool addRemainder) {
731  int offset = (destStripes - origStripes) / 2;
732  if (addRemainder) {
733  offset += (destStripes - origStripes) % 2;
734  }
735  return offset;
736 }
737 
738 
741  MSLane* lane, const MSLane* nextLane, int stripes, int nextDir,
742  double currentLength, int currentDir) {
743  if (nextLanesObs.count(nextLane) == 0) {
744  const double nextLength = nextLane->getEdge().isWalkingArea() ? myMinNextLengths[nextLane] : nextLane->getLength();
745  // figure out the which pedestrians are ahead on the next lane
746  const int nextStripes = numStripes(nextLane);
747  // do not move past the end of the next lane in a single step
748  Obstacles obs(stripes, Obstacle(nextDir == FORWARD ? nextLength : 0, 0, OBSTACLE_NEXTEND, "nextEnd", 0));
749 
750  const int offset = getStripeOffset(nextStripes, stripes, currentDir != nextDir && nextStripes > stripes);
751  //std::cout << SIMTIME << " getNextLaneObstacles"
752  // << " nextLane=" << nextLane->getID()
753  // << " nextLength=" << nextLength
754  // << " nextDir=" << nextDir
755  // << " currentLength=" << currentLength
756  // << " currentDir=" << currentDir
757  // << " stripes=" << stripes
758  // << " nextStripes=" << nextStripes
759  // << " offset=" << offset
760  // << "\n";
761  if (nextStripes < stripes) {
762  // some stripes do not continue
763  for (int ii = 0; ii < stripes; ++ii) {
764  if (ii < offset || ii >= nextStripes + offset) {
765  obs[ii] = Obstacle(nextDir == FORWARD ? 0 : nextLength, 0, OBSTACLE_END, "stripeEnd", 0);
766  }
767  }
768  }
769  Pedestrians& pedestrians = getPedestrians(nextLane);
770  if (nextLane->getEdge().isWalkingArea()) {
771  transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
772  // complex transformation into the coordinate system of the current lane
773  // (pedestrians on next lane may walk at arbitrary angles relative to the current lane)
774  double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
775  if ((stripes - nextStripes) % 2 != 0) {
776  lateral_offset += 0.5 * stripeWidth;
777  }
778  nextDir = currentDir;
779  // transform pedestrians into the current coordinate system
780  for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
781  PState& p = *pedestrians[ii];
782  if (p.myWaitingToEnter || p.myAmJammed) {
783  continue;
784  }
785  Position relPos = lane->getShape().transformToVectorCoordinates(p.getPosition(*p.myStage, -1), true);
786  const double newY = relPos.y() + lateral_offset;
787  //if (p.myPerson->getID() == "ped200") std::cout << " ped=" << p.myPerson->getID() << " relX=" << relPos.x() << " relY=" << newY << " latOff=" << lateral_offset << " s=" << p.stripe(newY) << " os=" << p.otherStripe(newY) << "\n";
788  if ((currentDir == FORWARD && relPos.x() >= lane->getLength()) || (currentDir == BACKWARD && relPos.x() < 0)) {
789  addCloserObstacle(obs, relPos.x(), p.stripe(newY), stripes, p.myPerson->getID(), p.myPerson->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
790  addCloserObstacle(obs, relPos.x(), p.otherStripe(newY), stripes, p.myPerson->getID(), p.myPerson->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
791  }
792  }
793  } else {
794  // simple transformation into the coordinate system of the current lane
795  // (only need to worry about currentDir and nextDir)
796  // XXX consider waitingToEnter on nextLane
797  sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(nextDir));
798  for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
799  const PState& p = *pedestrians[ii];
800  if (p.myWaitingToEnter || p.myAmJammed) {
801  continue;
802  }
803  double newY = p.myRelY;
804  Obstacle pObs(p);
805  if (nextDir != currentDir) {
806  newY = (nextStripes - 1) * stripeWidth - newY;
807  pObs.speed *= -1;
808  }
809  newY += offset * stripeWidth;
810  const int stripe = p.stripe(newY);
811  if (stripe >= 0 && stripe < stripes) {
812  obs[stripe] = pObs;
813  }
814  const int otherStripe = p.otherStripe(newY);
815  if (otherStripe >= 0 && otherStripe < stripes) {
816  obs[otherStripe] = pObs;
817  }
818  }
819  if (nextLane->getEdge().isCrossing()) {
820  // add vehicle obstacles
821  const MSLink* crossingEntryLink = nextLane->getIncomingLanes().front().viaLink;
822  const bool prio = crossingEntryLink->havePriority() || crossingEntryLink->getTLLogic() != nullptr;
823  addCrossingVehs(nextLane, stripes, offset, nextDir, obs, prio);
824  }
825  if (nextLane->getVehicleNumberWithPartials() > 0) {
826  Obstacles vehObs = getVehicleObstacles(nextLane, nextDir);
827  PState::mergeObstacles(obs, vehObs, nextDir, offset);
828  }
829  transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
830  }
831  nextLanesObs[nextLane] = obs;
832  }
833  return nextLanesObs[nextLane];
834 }
835 
836 void
837 MSPModel_Striping::transformToCurrentLanePositions(Obstacles& obs, int currentDir, int nextDir, double currentLength, double nextLength) {
838  for (int ii = 0; ii < (int)obs.size(); ++ii) {
839  Obstacle& o = obs[ii];
840  if (currentDir == FORWARD) {
841  if (nextDir == FORWARD) {
842  o.xFwd += currentLength;
843  o.xBack += currentLength;
844  } else {
845  const double tmp = o.xFwd;
846  o.xFwd = currentLength + nextLength - o.xBack;
847  o.xBack = currentLength + nextLength - tmp;
848  }
849  } else {
850  if (nextDir == FORWARD) {
851  const double tmp = o.xFwd;
852  o.xFwd = -o.xBack;
853  o.xBack = -tmp;
854  } else {
855  o.xFwd -= nextLength;
856  o.xBack -= nextLength;
857  }
858  }
859  }
860 }
861 
862 
863 void
864 MSPModel_Striping::addCloserObstacle(Obstacles& obs, double x, int stripe, int numStripes, const std::string& id, double width, int dir, ObstacleType type) {
865  if (stripe >= 0 && stripe < numStripes) {
866  if ((dir == FORWARD && x - width / 2. < obs[stripe].xBack) || (dir == BACKWARD && x + width / 2. > obs[stripe].xFwd)) {
867  obs[stripe] = Obstacle(x, 0, type, id, width);
868  }
869  }
870 }
871 
872 void
873 MSPModel_Striping::moveInDirection(SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
874  for (ActiveLanes::iterator it_lane = myActiveLanes.begin(); it_lane != myActiveLanes.end(); ++it_lane) {
875  const MSLane* lane = it_lane->first;
876  Pedestrians& pedestrians = it_lane->second;
877  if (pedestrians.size() == 0) {
878  continue;
879  }
880  //std::cout << SIMTIME << ">>> lane=" << lane->getID() << " numPeds=" << pedestrians.size() << "\n";
881  if (lane->getEdge().isWalkingArea()) {
882  const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
883  const double minY = stripeWidth * - 0.5 + NUMERICAL_EPS;
884  const double maxY = stripeWidth * (numStripes(lane) - 0.5) - NUMERICAL_EPS;
885  const WalkingAreaPath* debugPath = nullptr;
886  // need to handle each walkingAreaPath separately and transform
887  // coordinates beforehand
888  std::set<const WalkingAreaPath*, walkingarea_path_sorter> paths;
889  for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
890  const PState* p = *it;
891  assert(p->myWalkingAreaPath != 0);
892  if (p->myDir == dir) {
893  paths.insert(p->myWalkingAreaPath);
894  if DEBUGCOND(*p) {
895  debugPath = p->myWalkingAreaPath;
896  std::cout << SIMTIME << " debugging WalkingAreaPath from=" << debugPath->from->getID() << " to=" << debugPath->to->getID() << "\n";
897  }
898  }
899  }
900  const double usableWidth = (numStripes(lane) - 1) * stripeWidth;
901  for (std::set<const WalkingAreaPath*, walkingarea_path_sorter>::iterator it = paths.begin(); it != paths.end(); ++it) {
902  const WalkingAreaPath* path = *it;
903  Pedestrians toDelete;
904  Pedestrians transformedPeds;
905  transformedPeds.reserve(pedestrians.size());
906  for (Pedestrians::iterator it_p = pedestrians.begin(); it_p != pedestrians.end(); ++it_p) {
907  PState* p = *it_p;
908  if (p->myWalkingAreaPath == path) {
909  transformedPeds.push_back(p);
910  if (path == debugPath) std::cout << " ped=" << p->myPerson->getID() << " relX=" << p->myRelX << " relY=" << p->myRelY << " (untransformed), vecCoord="
911  << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
912  } else if (p->myWalkingAreaPath->from == path->to && p->myWalkingAreaPath->to == path->from) {
913  if (p->myWalkingAreaPath->dir != path->dir) {
914  // opposite direction is already in the correct coordinate system
915  transformedPeds.push_back(p);
916  if (path == debugPath) std::cout << " ped=" << p->myPerson->getID() << " relX=" << p->myRelX << " relY=" << p->myRelY << " (untransformed), vecCoord="
917  << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
918  } else {
919  // x position must be reversed
920  PState* tp = new PState(*p);
921  tp->myRelX = path->length - p->myRelX;
922  tp->myRelY = usableWidth - p->myRelY;
923  tp->myDir = !path->dir;
924  tp->mySpeed = -p->mySpeed;
925  toDelete.push_back(tp);
926  transformedPeds.push_back(tp);
927  if (path == debugPath) std::cout << " ped=" << p->myPerson->getID() << " relX=" << p->myRelX << " relY=" << p->myRelY << " (semi-transformed), vecCoord="
928  << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
929  }
930  } else {
931  const Position relPos = path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1));
932  const double newY = relPos.y() + lateral_offset;
933  if (relPos != Position::INVALID && newY >= minY && newY <= maxY) {
934  PState* tp = new PState(*p);
935  tp->myRelX = relPos.x();
936  tp->myRelY = newY;
937  // only an obstacle, speed may be orthogonal to dir
938  tp->myDir = !dir;
939  tp->mySpeed = 0;
940  toDelete.push_back(tp);
941  transformedPeds.push_back(tp);
942  if (path == debugPath) {
943  std::cout << " ped=" << p->myPerson->getID() << " relX=" << relPos.x() << " relY=" << newY << " (transformed), vecCoord=" << relPos << "\n";
944  }
945  } else {
946  if (path == debugPath) {
947  std::cout << " ped=" << p->myPerson->getID() << " relX=" << relPos.x() << " relY=" << newY << " (invalid), vecCoord=" << relPos << "\n";
948  }
949  }
950  }
951  }
952  auto itFoe = myWalkingAreaFoes.find(&lane->getEdge());
953  if (itFoe != myWalkingAreaFoes.end()) {
954  // add vehicle foes on paths which cross this walkingarea
955  // translate the vehicle into a number of dummy-pedestrians
956  // that occupy the same space
957  for (const MSLane* foeLane : itFoe->second) {
958  for (auto itVeh = foeLane->anyVehiclesBegin(); itVeh != foeLane->anyVehiclesEnd(); ++itVeh) {
959  const MSVehicle* veh = *itVeh;
960  const Position relPos = path->shape.transformToVectorCoordinates(veh->getPosition());
961  const Position relPos2 = path->shape.transformToVectorCoordinates(veh->getBackPosition());
962  //std::cout << " pos=" << veh->getPosition() << " back=" << veh->getBackPosition() << " relPos=" << relPos << " relPos2=" << relPos2 << " shape=" << path->shape << "\n";
963  if (addVehicleFoe(veh, lane, relPos, lateral_offset, minY, maxY, toDelete, transformedPeds)
964  && addVehicleFoe(veh, lane, relPos2, lateral_offset, minY, maxY, toDelete, transformedPeds)) {
965  // add in-between positions
966  const double length = veh->getVehicleType().getLength();
967  for (double dist = stripeWidth; dist < length; dist += stripeWidth) {
968  const double relDist = dist / length;
969  Position between = (relPos * relDist) + (relPos2 * (1 - relDist));
970  addVehicleFoe(veh, lane, between, lateral_offset, minY, maxY, toDelete, transformedPeds);
971  }
972  }
973  }
974  }
975  }
976  moveInDirectionOnLane(transformedPeds, lane, currentTime, changedLane, dir);
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);
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 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);
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 = pedestrians[i];
1015  if (p->isRemoteControlled()) {
1016  continue;
1017  }
1018  if (p->myDir == 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->myLane != nullptr) {
1025  changedLane.insert(p->myPerson);
1026  myActiveLanes[p->myLane].push_back(p);
1027  } else {
1028  // end walking stage and destroy PState
1029  p->myStage->moveToNextEdge(p->myPerson, currentTime);
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) {
1039  const int stripes = numStripes(lane);
1040  //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
1041  Obstacles obs(stripes, Obstacle(dir)); // continously updated
1042  NextLanesObstacles nextLanesObs; // continously 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 = *pedestrians[ii];
1054  //std::cout << SIMTIME << "CHECKING" << p.myPerson->getID() << "\n";
1055  Obstacles currentObs = obs;
1056  if (p.myDir != dir || changedLane.count(p.myPerson) != 0 || p.myRemoteXYPos != Position::INVALID) {
1057  if (!p.myWaitingToEnter && !p.myAmJammed) {
1058  //if DEBUGCOND(p) {
1059  // std::cout << " obs=" << p.myPerson->getID() << " y=" << p.myRelY << " stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
1060  //}
1061  Obstacle o(p);
1062  if (p.myDir != dir && p.mySpeed == 0) {
1063  // ensure recognition of oncoming
1064  o.speed = (p.myDir == FORWARD ? 0.1 : -0.1);
1065  }
1066  obs[p.stripe()] = o;
1067  obs[p.otherStripe()] = o;
1068  }
1069  continue;
1070  }
1071  if DEBUGCOND(p) {
1072  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " currentObs=";
1073  gDebugFlag1 = true;
1074  DEBUG_PRINT(currentObs);
1075  }
1076  const MSLane* nextLane = p.myNLI.lane;
1077  const MSLink* link = p.myNLI.link;
1078  const double dist = p.distToLaneEnd();
1079  const double speed = p.myStage->getMaxSpeed(p.myPerson);
1080  if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING) {
1081  const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
1082  const Obstacles& nextObs = getNextLaneObstacles(
1083  nextLanesObs, lane, nextLane, stripes,
1084  p.myNLI.dir, currentLength, dir);
1085 
1086  if DEBUGCOND(p) {
1087  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " nextObs=";
1088  DEBUG_PRINT(nextObs);
1089  }
1090  p.mergeObstacles(currentObs, nextObs);
1091  }
1092  if DEBUGCOND(p) {
1093  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " obsWithNext=";
1094  DEBUG_PRINT(currentObs);
1095  }
1096  p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
1097  if DEBUGCOND(p) {
1098  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " obsWithNeigh=";
1099  DEBUG_PRINT(currentObs);
1100  }
1101  // time gap to pass the intersection ahead of a vehicle.
1102  const double passingClearanceTime = 2;
1103  const double passingLength = p.getLength() + passingClearanceTime * speed;
1104  // check link state
1105  if DEBUGCOND(p) {
1106  gDebugFlag1 = true; // get debug output from MSLink
1107  std::cout << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
1108  << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
1109  }
1110  if (link != nullptr
1111  // only check close before junction, @todo we should take deceleration into account here
1112  && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
1113  // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
1114  && !link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(currentTime), speed, 0, 0, nullptr, p.ignoreRed(link), p.myPerson)) {
1115  // prevent movement passed a closed link
1116  Obstacles closedLink(stripes, Obstacle(p.myRelX + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
1117  p.mergeObstacles(currentObs, closedLink);
1118  if DEBUGCOND(p) {
1119  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " obsWithTLS=";
1120  DEBUG_PRINT(currentObs);
1121  }
1122  // consider rerouting over another crossing
1123  if (p.myWalkingAreaPath != nullptr) {
1124  // @todo actually another path would be needed starting at the current position
1126  }
1127  }
1128  if DEBUGCOND(p) {
1129  gDebugFlag1 = false;
1130  }
1131  if (&lane->getEdge() == p.myStage->getDestination() && p.myStage->getDestinationStop() != nullptr) {
1132  Obstacles arrival(stripes, Obstacle(p.myStage->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
1133  p.mergeObstacles(currentObs, arrival);
1134  }
1135 
1136  if (lane->getVehicleNumberWithPartials() > 0) {
1137  // react to vehicles on the same lane
1138  // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
1139  Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
1140  p.mergeObstacles(currentObs, vehObs);
1141  if DEBUGCOND(p) {
1142  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " obsWithVehs=";
1143  DEBUG_PRINT(currentObs);
1144  }
1145  }
1146  if (hasCrossingVehObs) {
1147  p.mergeObstacles(currentObs, crossingVehs);
1148  if DEBUGCOND(p) {
1149  std::cout << SIMTIME << " ped=" << p.myPerson->getID() << " obsWithVehs2=";
1150  DEBUG_PRINT(currentObs);
1151  }
1152  }
1153 
1154  // walk, taking into account all obstacles
1155  p.walk(currentObs, currentTime);
1156  gDebugFlag1 = false;
1157  if (!p.myWaitingToEnter && !p.myAmJammed) {
1158  Obstacle o(p);
1159  obs[p.stripe()] = o;
1160  obs[p.otherStripe()] = o;
1161  if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.myAmJammed) {
1162  for (int coll = 0; coll < ii; ++coll) {
1163  PState& c = *pedestrians[coll];
1164  if (!c.myWaitingToEnter && c.myWalkingAreaPath == nullptr && !c.myAmJammed) {
1165  if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
1166  Obstacle cObs(c);
1167  // we check only for real collisions, no min gap violations
1168  if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
1169  WRITE_WARNING("Collision of person '" + p.myPerson->getID() + "' and person '" + c.myPerson->getID()
1170  + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
1171  }
1172  }
1173  }
1174  }
1175  }
1176  }
1177  //std::cout << SIMTIME << p.myPerson->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
1178  }
1179 }
1180 
1181 bool
1182 MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio) {
1183  bool hasCrossingVehObs = false;
1184  const MSLink* crossingExitLink = crossing->getLinkCont().front();
1185  gDebugFlag1 = DEBUGCOND2(crossing);
1186  const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
1187  gDebugFlag1 = false;
1188  if (linkLeaders.size() > 0) {
1189  for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
1190  // the vehicle to enter the junction first has priority
1191  const MSVehicle* veh = (*it).vehAndGap.first;
1192  if (veh != nullptr) {
1193  Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * MINGAP_TO_VEHICLE);
1194  // block entry to the crossing in walking direction but allow leaving it
1195  Obstacle voBlock = vo;
1196  if (dir == FORWARD) {
1197  voBlock.xBack = NUMERICAL_EPS;
1198  } else {
1199  voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
1200  }
1201  // when approaching a priority crossings, vehicles must be able
1202  // to brake, otherwise the person must be able to cross in time
1203  const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
1204  const double bGap = (prio
1205  ? veh->getCarFollowModel().brakeGap(veh->getSpeed(), veh->getCarFollowModel().getMaxDecel(), 0)
1206  : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
1207  double vehYmin;
1208  double vehYmax;
1209  // relY increases from left to right (the other way around from vehicles)
1210  if ((*it).fromLeft) {
1211  vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
1212  vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + MINGAP_TO_VEHICLE;
1213  vehYmin -= MINGAP_TO_VEHICLE;
1214  } else {
1215  vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
1216  vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - MINGAP_TO_VEHICLE;
1217  vehYmax += MINGAP_TO_VEHICLE;
1218 
1219  }
1220  for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
1221  if ((dir == FORWARD && obs[s].xBack > vo.xBack)
1222  || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
1223  if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
1224  // do not enter the crossing
1225  obs[s] = voBlock;
1226  } else {
1227  obs[s] = vo;
1228  }
1229  hasCrossingVehObs = true;
1230  }
1231  }
1232  if (DEBUGCOND2(crossing)) {
1233  std::cout << SIMTIME
1234  << " crossingVeh=" << veh->getID()
1235  << " lane=" << crossing->getID()
1236  << " prio=" << prio
1237  << " latOffset=" << lateral_offset
1238  << " dir=" << dir
1239  << " stripes=" << stripes
1240  << " dist=" << (*it).distToCrossing
1241  << " gap=" << (*it).vehAndGap.second
1242  << " brakeGap=" << bGap
1243  << " fromLeft=" << (*it).fromLeft
1244  << " distToCrossBefore=" << distToCrossBeforeVeh
1245  << " ymin=" << vehYmin
1246  << " ymax=" << vehYmax
1247  << " smin=" << PState::stripe(vehYmin)
1248  << " smax=" << PState::stripe(vehYmax)
1249  << "\n";
1250  DEBUG_PRINT(obs);
1251  }
1252  }
1253  }
1254  }
1255  return hasCrossingVehObs;
1256 }
1257 
1258 
1261  const int stripes = numStripes(lane);
1262  Obstacles vehObs(stripes, Obstacle(dir));
1263  int current = -1;
1264  double minX = 0.;
1265  double maxX = 0.;
1266  double pRelY = -1.;
1267  double pWidth = 0.;
1268  std::string pID;
1269  bool debug = DEBUGCOND2(lane);
1270  if (ped != nullptr) {
1271  current = ped->stripe();
1272  minX = ped->getMinX();
1273  maxX = ped->getMaxX();
1274  pRelY = ped->myRelY;
1275  pWidth = ped->myPerson->getVehicleType().getWidth();
1276  pID = ped->myPerson->getID();
1277  debug = DEBUGCOND(*ped);
1278  } else if (dir == BACKWARD) {
1279  // checking vehicles on the next lane. Use entry point as reference
1280  minX = lane->getLength();
1281  maxX = lane->getLength();
1282  }
1283  MSLane::AnyVehicleIterator begin = (dir == FORWARD ? lane->anyVehiclesUpstreamBegin() : lane->anyVehiclesBegin());
1284  MSLane::AnyVehicleIterator end = (dir == FORWARD ? lane->anyVehiclesUpstreamEnd() : lane->anyVehiclesEnd());
1285  for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
1286  const MSVehicle* veh = *it;
1287  const double vehBack = veh->getBackPositionOnLane(lane);
1288  const double vehFront = vehBack + veh->getVehicleType().getLength();
1289  // ensure that vehicles are not blocked
1290  const double vehNextSpeed = MAX2(veh->getSpeed(), 1.0);
1291  const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
1292  if ((dir == FORWARD && vehFront + clearance > minX && vehBack <= maxX + LOOKAHEAD_SAMEDIR)
1293  || (dir == BACKWARD && vehBack < maxX && vehFront >= minX - LOOKAROUND_VEHICLES)) {
1294  Obstacle vo(vehBack, veh->getSpeed(), OBSTACLE_VEHICLE, veh->getID(), 0);
1295  // moving vehicles block space along their path
1296  vo.xFwd += veh->getVehicleType().getLength() + clearance;
1297  vo.xBack -= SAFETY_GAP;
1298  // relY increases from left to right (the other way around from vehicles)
1299  // XXX lateral offset for partial vehicles
1300  const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - veh->getLateralPositionOnLane();
1301  const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
1302  for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
1303  Obstacle prior = vehObs[s];
1304  vehObs[s] = vo;
1305  if (s == current && vehFront + SAFETY_GAP < minX) {
1306  // ignore if aleady overlapping while vehicle is still behind
1307  if (pRelY - pWidth < vehYmax &&
1308  pRelY + pWidth > vehYmin && dir == FORWARD) {
1309  if (debug) {
1310  std::cout << " ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
1311  }
1312  if (dir == FORWARD) {
1313  vehObs[s] = prior;
1314  } else {
1315  vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
1316  }
1317  }
1318  }
1319  }
1320  if (debug) {
1321  std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
1322  << "\n"
1323  << " ymin=" << vehYmin
1324  << " ymax=" << vehYmax
1325  << " smin=" << PState::stripe(vehYmin)
1326  << " smax=" << PState::stripe(vehYmax)
1327  << " relY=" << pRelY
1328  << " current=" << current
1329  << " vo.xFwd=" << vo.xFwd
1330  << " vo.xBack=" << vo.xBack
1331  << "\n";
1332  }
1333  }
1334  }
1335  return vehObs;
1336 }
1337 
1338 
1339 // ===========================================================================
1340 // MSPModel_Striping::Obstacle method definitions
1341 // ===========================================================================
1343  xFwd(dir * dist), // by default, far away when seen in dir
1344  xBack(dir * dist), // by default, far away when seen in dir
1345  speed(0),
1346  type(OBSTACLE_NONE),
1347  description("") {
1348 }
1349 
1350 
1352  xFwd(ped.getMaxX()),
1353  xBack(ped.getMinX()),
1354  speed(ped.myDir * ped.mySpeed),
1355  type(OBSTACLE_PED),
1356  description(ped.getID()) {
1357  assert(!ped.myWaitingToEnter);
1358 }
1359 
1360 
1361 // ===========================================================================
1362 // MSPModel_Striping::PState method definitions
1363 // ===========================================================================
1365  myPerson(person),
1366  myStage(stage),
1367  myLane(lane),
1368  myRelX(stage->getDepartPos()),
1369  myRelY(stage->getDepartPosLat()),
1370  myDir(FORWARD),
1371  mySpeed(0),
1372  myWaitingToEnter(true),
1373  myWaitingTime(0),
1374  myWalkingAreaPath(nullptr),
1375  myAmJammed(false),
1376  myRemoteXYPos(Position::INVALID),
1377  myAngle(std::numeric_limits<double>::max()) {
1378  const MSEdge* currentEdge = &lane->getEdge();
1379  const ConstMSEdgeVector& route = myStage->getRoute();
1380  assert(!route.empty());
1381  if (route.size() == 1) {
1382  // only a single edge, move towards end pos
1384  } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
1385  // start on an intersection
1386  myDir = FORWARD;
1387  if (route.front()->isWalkingArea()) {
1388  myWalkingAreaPath = getArbitraryPath(route.front());
1389  }
1390  } else {
1391  const bool mayStartForward = canTraverse(FORWARD, route) != UNDEFINED_DIRECTION;
1392  const bool mayStartBackward = canTraverse(BACKWARD, route) != UNDEFINED_DIRECTION;
1393  if DEBUGCOND(*this) {
1394  std::cout << " initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
1395  }
1396  if (mayStartForward && mayStartBackward) {
1397  // figure out the best direction via routing
1398  ConstMSEdgeVector crossingRoute;
1399  MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myRelX, myStage->getArrivalPos(), myStage->getMaxSpeed(person), 0, nullptr, crossingRoute, true);
1400  if (crossingRoute.size() > 1) {
1401  // route found
1402  const MSEdge* nextEdge = crossingRoute[1];
1403  if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
1404  myDir = BACKWARD;
1405  }
1406  }
1407  if DEBUGCOND(*this) {
1408  std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
1409  }
1410  } else {
1411  myDir = !mayStartBackward ? FORWARD : BACKWARD;
1412  }
1413  }
1414  if (lane->getVehicleNumberWithPartials() > 0 && myRelY == 0) {
1415  // better start next to the road if nothing was specified
1416  myRelY -= stripeWidth;
1417  }
1418  if (myDir == FORWARD) {
1419  // start at the right side of the sidewalk
1420  myRelY = stripeWidth * (numStripes(lane) - 1) - myRelY;
1421  }
1422  if DEBUGCOND(*this) {
1423  std::cout << " added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myRelX=" << myRelX << " myRelY=" << myRelY << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
1424  }
1425 
1426  myNLI = getNextLane(*this, lane, nullptr);
1427 }
1428 
1430  myPerson(nullptr),
1431  myStage(nullptr),
1432  myLane(nullptr),
1433  myRelX(0),
1434  myRelY(0),
1435  myDir(UNDEFINED_DIRECTION),
1436  mySpeed(0),
1437  myWaitingToEnter(false),
1438  myWaitingTime(0),
1439  myWalkingAreaPath(nullptr),
1440  myAmJammed(false),
1441  myRemoteXYPos(Position::INVALID),
1442  myAngle(std::numeric_limits<double>::max()) {
1443 }
1444 
1445 
1446 double
1447 MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
1448  // @todo speed should have an influence here because faster persons need more space
1449  if (myDir == FORWARD) {
1450  return myRelX - getLength();
1451  }
1452  return myRelX - (includeMinGap ? getMinGap() : 0.);
1453 }
1454 
1455 
1456 double
1457 MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
1458  // @todo speed should have an influence here because faster persons need more space
1459  if (myDir == FORWARD) {
1460  return myRelX + (includeMinGap ? getMinGap() : 0.);
1461  }
1462  return myRelX + getLength();
1463 }
1464 
1465 
1466 double
1468  return myPerson->getVehicleType().getLength();
1469 }
1470 
1471 
1472 double
1474  return myPerson->getVehicleType().getMinGap();
1475 }
1476 
1477 
1478 int
1480  return (int)floor(relY / stripeWidth + 0.5);
1481 }
1482 
1483 
1484 int
1486  const int s = stripe(relY);
1487  const double offset = relY - s * stripeWidth;
1488  const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
1489  int result;
1490  if (offset > threshold) {
1491  result = s + 1;
1492  } else if (offset < -threshold) {
1493  result = s - 1;
1494  } else {
1495  result = s;
1496  }
1497  //std::cout.setf(std::ios::fixed , std::ios::floatfield);
1498  //std::cout << std::setprecision(5);
1499  //if DEBUGCOND(*this) std::cout << " otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
1500  return result;
1501 }
1502 
1503 int
1505  return MIN2(MAX2(0, stripe(myRelY)), numStripes(myLane) - 1);
1506 }
1507 
1508 
1509 int
1511  return MIN2(MAX2(0, otherStripe(myRelY)), numStripes(myLane) - 1);
1512 }
1513 
1514 
1515 double
1517  if (myStage->getNextRouteEdge() == nullptr) {
1518  return myDir * (myStage->getArrivalPos() - myRelX) - POSITION_EPS;
1519  } else {
1520  const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
1521  return myDir == FORWARD ? length - myRelX : myRelX;
1522  }
1523 }
1524 
1525 
1526 bool
1528  double dist = distToLaneEnd();
1529  if (DEBUGCOND(*this)) {
1530  std::cout << SIMTIME << " ped=" << myPerson->getID() << " myRelX=" << myRelX << " dist=" << dist << "\n";
1531  }
1532  if (dist <= 0) {
1533  //if (ped.myPerson->getID() == DEBUG1) {
1534  // std::cout << SIMTIME << " addToLane x=" << ped.myRelX << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
1535  //}
1536  //std::cout << " changing to " << newLane->getID() << " myRelY=" << ped.myRelY << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
1537  //std::cout << " newY=" << ped.myRelY << " myDir=" << ped.myDir << " newDir=" << newDir;
1538  const int oldDir = myDir;
1539  const MSLane* oldLane = myLane;
1540  myLane = myNLI.lane;
1541  myDir = myNLI.dir;
1542  const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
1543  if DEBUGCOND(*this) {
1544  std::cout << SIMTIME
1545  << " ped=" << myPerson->getID()
1546  << " moveToNextLane old=" << oldLane->getID()
1547  << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
1548  << " oldDir=" << oldDir
1549  << " newDir=" << myDir
1550  << " myRelX=" << myRelX
1551  << " dist=" << dist
1552  << "\n";
1553  }
1554  if (myLane == nullptr) {
1555  myRelX = myStage->getArrivalPos();
1556  }
1557  // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
1558  if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
1559  myLane = nullptr;
1560  } else {
1561  const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, normalLane ? nullptr : &myLane->getEdge());
1562  UNUSED_PARAMETER(arrived);
1563  assert(!arrived);
1564  assert(myDir != UNDEFINED_DIRECTION);
1565  myNLI = getNextLane(*this, myLane, oldLane);
1566  assert(myNLI.lane != oldLane); // do not turn around
1567  if DEBUGCOND(*this) {
1568  std::cout << " nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
1569  }
1570  if (myLane->getEdge().isWalkingArea()) {
1571  if (myNLI.dir != UNDEFINED_DIRECTION) {
1572  myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
1573  assert(myWalkingAreaPath->shape.size() >= 2);
1574  if DEBUGCOND(*this) {
1575  std::cout << " mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
1576  }
1577  } else {
1578  // disconnnected route. move to the next edge
1579  if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
1580  // try to determine direction from topology, otherwise maintain current direction
1581  const MSEdge* currRouteEdge = *myStage->getRouteStep();
1582  const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
1583  if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
1584  || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
1585  myDir = BACKWARD;
1586  } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
1587  || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
1588  myDir = FORWARD;
1589  }
1590  myStage->moveToNextEdge(myPerson, currentTime, nullptr);
1591  myLane = myNLI.lane;
1592  assert(myLane != 0);
1593  assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
1594  myNLI = getNextLane(*this, myLane, oldLane);
1595  myWalkingAreaPath = nullptr;
1596  } else {
1597  throw ProcessError("Disconnected walk for person '" + myPerson->getID() + "'.");
1598  }
1599  }
1600  } else {
1601  myWalkingAreaPath = nullptr;
1602  }
1603  // adapt x to fit onto the new lane
1604  // (make sure we do not move past the end of the new lane since that
1605  // lane was not checked for obstacles)
1606  const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
1607  if (-dist > newLength) {
1608  assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
1609  // should not happen because the end of myLane should have been an obstacle as well
1610  // (only when the route is broken)
1611  dist = -newLength;
1612  }
1613  if (myDir == BACKWARD) {
1614  myRelX = newLength + dist;
1615  } else {
1616  myRelX = -dist;
1617  }
1618  if DEBUGCOND(*this) {
1619  std::cout << SIMTIME << " update myRelX ped=" << myPerson->getID()
1620  << " newLength=" << newLength
1621  << " dist=" << dist
1622  << " myRelX=" << myRelX
1623  << "\n";
1624  }
1625  // adjust to change in direction
1626  if (myDir != oldDir) {
1627  myRelY = (numStripes(oldLane) - 1) * stripeWidth - myRelY;
1628  }
1629  // adjust to differences in sidewalk width
1630  const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
1631  myRelY += offset * stripeWidth;
1632  if DEBUGCOND(*this) {
1633  std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
1634  << " newLane=" << Named::getIDSecure(myLane)
1635  << " newY=" << myRelY
1636  << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
1637  << " od=" << oldDir << " nd=" << myDir
1638  << " offset=" << offset << "\n";
1639  }
1640  }
1641  return true;
1642  } else {
1643  return false;
1644  }
1645 }
1646 
1647 void
1649  myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
1650  const int stripes = (int)obs.size();
1651  const int sMax = stripes - 1;
1652  assert(stripes == numStripes(myLane));
1653  const double vMax = myStage->getMaxSpeed(myPerson);
1654  // ultimate goal is to choose the prefered stripe (chosen)
1655  const int current = stripe();
1656  const int other = otherStripe();
1657  // compute distances
1658  std::vector<double> distance(stripes);
1659  for (int i = 0; i < stripes; ++i) {
1660  distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
1661  }
1662  // compute utility for all stripes
1663  std::vector<double> utility(stripes, 0);
1664  // forbid stripes which are blocked and also all stripes behind them
1665  for (int i = 0; i < stripes; ++i) {
1666  if (distance[i] == DIST_OVERLAP) {
1667  if (i == current && (!myWaitingToEnter || stripe() != stripe(myRelY))) {
1668  utility[i] += OBSTRUCTED_PENALTY;
1669  }
1670  if (i < current) {
1671  for (int j = 0; j <= i; ++j) {
1672  utility[j] += OBSTRUCTED_PENALTY;
1673  }
1674  }
1675  if (i > current) {
1676  for (int j = i; j < stripes; ++j) {
1677  utility[j] += OBSTRUCTED_PENALTY;
1678  }
1679  }
1680  }
1681  }
1682  // forbid a portion of the leftmost stripes (in walking direction).
1683  // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
1684  // may still deadlock in heavy pedestrian traffic
1685  const bool onJunction = myLane->getEdge().isWalkingArea() || myLane->getEdge().isCrossing();
1686  const int reserved = (int)floor(stripes * (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
1687  if (myDir == FORWARD) {
1688  for (int i = 0; i < reserved; ++i) {
1689  utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1690  }
1691  } else {
1692  for (int i = sMax; i > sMax - reserved; --i) {
1693  utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
1694  }
1695  }
1696  // adapt utility based on obstacles
1697  for (int i = 0; i < stripes; ++i) {
1698  if (obs[i].speed * myDir < 0) {
1699  // penalize evasion to the left
1700  if (myDir == FORWARD && i > 0) {
1701  utility[i - 1] -= 0.5;
1702  } else if (myDir == BACKWARD && i < sMax) {
1703  utility[i + 1] -= 0.5;
1704  }
1705  }
1706  // compute expected distance achievable by staying on this stripe for a time horizon
1707  const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
1708  const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
1709  const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
1710  if (DEBUGCOND(*this)) {
1711  std::cout << " util=" << utility[i] << " exp=" << expectedDist << " dist=" << distance[i] << "\n";
1712  }
1713  if (expectedDist >= 0) {
1714  utility[i] += expectedDist;
1715  } else {
1716  // let only the distance count
1717  utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
1718  }
1719  }
1720  // discourage use of the leftmost lane (in walking direction) if there are oncoming
1721  if (myDir == FORWARD && obs[0].speed < 0) {
1722  utility[0] += ONCOMING_CONFLICT_PENALTY;
1723  } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
1724  utility[sMax] += ONCOMING_CONFLICT_PENALTY;
1725  }
1726  // penalize lateral movement (if the current stripe permits walking)
1727  if (distance[current] > 0 && myWaitingTime == 0) {
1728  for (int i = 0; i < stripes; ++i) {
1729  utility[i] += abs(i - current) * LATERAL_PENALTY;
1730  }
1731  }
1732 
1733  // select best stripe
1734  int chosen = current;
1735  for (int i = 0; i < stripes; ++i) {
1736  if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
1737  chosen = i;
1738  }
1739  }
1740  // compute speed components along both axes
1741  const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
1742  double xDist = MIN3(distance[current], distance[other], distance[next]);
1743  if (next != chosen) {
1744  // ensure that we do not collide with an obstacle in the stripe beyond
1745  // next as this might become the 'other' stripe in the next step
1746  const int nextOther = chosen < current ? current - 2 : current + 2;
1747  xDist = MIN2(xDist, distance[nextOther]);
1748  }
1749  // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
1750  const double preferredGap = NUMERICAL_EPS;
1751  double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
1752  if (xSpeed < NUMERICAL_EPS) {
1753  xSpeed = 0.;
1754  }
1755  if (DEBUGCOND(*this)) {
1756  std::cout << " xSpeedPotential=" << xSpeed << "\n";
1757  }
1758  // avoid tiny steps
1759  // XXX pressure from behind?
1760  if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
1761  // unless walking towards a short lane
1762  !(
1763  (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
1764  || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
1765  || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
1766  ) {
1767  xSpeed = 0;
1768  }
1769  if (xSpeed == 0) {
1770  if (myWaitingTime > (myLane->getEdge().isCrossing() ? jamTimeCrossing : jamTime)
1771  || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
1772  || myAmJammed) {
1773  // squeeze slowly through the crowd ignoring others
1774  if (!myAmJammed) {
1776  WRITE_WARNING("Person '" + myPerson->getID()
1777  + "' is jammed on edge '" + myStage->getEdge()->getID()
1778  + "', time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
1779  myAmJammed = true;
1780  }
1781  xSpeed = vMax / 4;
1782  }
1783  } else if (stripe(myRelY) >= 0 && stripe(myRelY) <= sMax) {
1784  myAmJammed = false;
1785  }
1786  // dawdling
1787  const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
1788  xSpeed -= dawdle;
1789 
1790  // XXX ensure that diagonal speed <= vMax
1791  // avoid deadlocks on narrow sidewalks
1792  //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
1793  // if DEBUGCOND(*this) std::cout << " stepping asside to resolve oncoming deadlock\n";
1794  // xSpeed = POSITION_EPS; // reset myWaitingTime
1795  // if (myDir == FORWARD && chosen < sMax) {
1796  // chosen += 1;
1797  // } else if (myDir == BACKWARD && chosen > 0) {
1798  // chosen -= 1;
1799  // }
1800  //}
1801  const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
1802  double ySpeed = 0;
1803  double yDist = 0;
1804  if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
1805  // don't move laterally if the stripes are blocked
1806  yDist = (chosen * stripeWidth) - myRelY;
1807  if (fabs(yDist) > NUMERICAL_EPS) {
1808  ySpeed = (yDist > 0 ?
1809  MIN2(maxYSpeed, DIST2SPEED(yDist)) :
1810  MAX2(-maxYSpeed, DIST2SPEED(yDist)));
1811  }
1812  } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
1813  // still on the road
1814  && stripe() == stripe(myRelY)
1815  // only when the vehicle is moving on the same lane
1816  && !myLane->getEdge().isCrossing()) {
1817  // step aside to let the vehicle pass
1818  myRelY += myDir * vMax;
1819  }
1820  // DEBUG
1821  if DEBUGCOND(*this) {
1822  std::cout << SIMTIME
1823  << " ped=" << myPerson->getID()
1824  << " edge=" << myStage->getEdge()->getID()
1825  << " x=" << myRelX
1826  << " y=" << myRelY
1827  << " d=" << myDir
1828  << " pvx=" << mySpeed
1829  << " cur=" << current
1830  << " cho=" << chosen
1831  << " oth=" << other
1832  << " nxt=" << next
1833  << " vx=" << xSpeed
1834  << " dawdle=" << dawdle
1835  << " vy=" << ySpeed
1836  << " xd=" << xDist
1837  << " yd=" << yDist
1838  << " vMax=" << myStage->getMaxSpeed(myPerson)
1839  << " wTime=" << myStage->getWaitingTime(currentTime)
1840  << " jammed=" << myAmJammed
1841  << "\n distance=" << toString(distance)
1842  << "\n utility=" << toString(utility)
1843  << "\n";
1844  DEBUG_PRINT(obs);
1845  }
1846  myRelX += SPEED2DIST(xSpeed * myDir);
1847  myRelY += SPEED2DIST(ySpeed);
1848  mySpeed = xSpeed;
1849  if (xSpeed >= SUMO_const_haltingSpeed) {
1850  myWaitingToEnter = false;
1851  myWaitingTime = 0;
1852  } else {
1853  myWaitingTime += DELTA_T;
1854  }
1855 }
1856 
1857 
1858 double
1860  return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
1861  + STEPS2TIME(myStage->getWaitingTime(now)) / MAX_WAIT_TOLERANCE));
1862 }
1863 
1864 
1865 double
1867  return myRelX;
1868 }
1869 
1870 
1871 Position
1873  if (myRemoteXYPos != Position::INVALID) {
1874  return myRemoteXYPos;
1875  }
1876  if (myLane == nullptr) {
1877  // pedestrian has already finished
1878  return Position::INVALID;
1879  }
1880  const double lateral_offset = myRelY + (stripeWidth - myLane->getWidth()) * 0.5;
1881  if (myWalkingAreaPath == nullptr) {
1882  return stage.getLanePosition(myLane, myRelX, lateral_offset);
1883  } else {
1884  //if DEBUGCOND(*this) {
1885  // std::cout << SIMTIME
1886  // << " getPosition (walkingArea)"
1887  // << " p=" << myPerson->getID()
1888  // << " x=" << myRelX
1889  // << " y=" << myRelY
1890  // << " latOffset=" << lateral_offset
1891  // << " shape=" << myWalkingAreaPath->shape
1892  // << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myRelX, lateral_offset)
1893  // << "\n";
1894  //}
1895  return myWalkingAreaPath->shape.positionAtOffset(myRelX, lateral_offset);
1896  }
1897 }
1898 
1899 
1900 double
1902  if (myAngle != std::numeric_limits<double>::max()) {
1903  return myAngle;
1904  }
1905  if (myLane == nullptr) {
1906  // pedestrian has already finished
1907  return 0;
1908  }
1909  const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
1910  double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myRelX) : myRelX;
1911  double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
1912  if (angle > M_PI) {
1913  angle -= 2 * M_PI;
1914  }
1915  myAngle = angle;
1916  return angle;
1917 }
1918 
1919 
1920 SUMOTime
1922  return myWaitingTime;
1923 }
1924 
1925 
1926 double
1928  return mySpeed;
1929 }
1930 
1931 
1932 const MSEdge*
1934  return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
1935 }
1936 
1937 void
1939  double lanePosLat, double angle, int routeOffset,
1940  const ConstMSEdgeVector& edges, SUMOTime t) {
1942  assert(p == myPerson);
1943  assert(pm != nullptr);
1944  const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
1945  myAngle = GeomHelper::fromNaviDegree(angle);
1946 #ifdef DEBUG_MOVETOXY
1947  std::cout << SIMTIME << " ped=" << p->getID()
1948  << " moveToXY"
1949  << " pos=" << pos
1950  << " lane=" << lane->getID()
1951  << " lanePos=" << lanePos
1952  << " lanePosLat=" << lanePosLat
1953  << " angle=" << angle
1954  << " routeOffset=" << routeOffset
1955  << " edges=" << toString(edges)
1956  << " oldLane=" << Named::getIDSecure(myLane)
1957  << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
1958 #endif
1959 
1960  if (lane != myLane && myLane != nullptr) {
1961  pm->remove(this);
1962  pm->registerActive();
1963  }
1964  if (lane != nullptr &&
1965  fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
1966  myRemoteXYPos = Position::INVALID;
1967  const MSEdge* old = myStage->getEdge();
1968  const MSLane* oldLane = myLane;
1969  if (lane != myLane) {
1970  // implicitly adds new active lane if necessary
1971  pm->myActiveLanes[lane].push_back(this);
1972  }
1973  if (edges.empty()) {
1974  // map within route
1975  myStage->setRouteIndex(myPerson, routeOffset);
1976  } else {
1977  myStage->replaceRoute(myPerson, edges, routeOffset);
1978  }
1979  if (!lane->getEdge().isNormal()) {
1980  myStage->moveToNextEdge(myPerson, t, &lane->getEdge());
1981  }
1982 
1983  myLane = lane;
1984  const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
1985  if (lane->getEdge().isWalkingArea()) {
1986  if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
1987  // entered new walkingarea. Determine path
1988  myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
1989 #ifdef DEBUG_MOVETOXY
1990  std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
1991  << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
1992 #endif
1993  }
1994  // lanePos and lanePosLat are matched onto the circumference of the
1995  // walkingarea. Use pos instead
1996  const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
1997  if (relPos == Position::INVALID) {
1998  WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID() + "'");
1999  myRemoteXYPos = pos;
2000  } else {
2001  myRelX = relPos.x();
2002  myRelY = lateral_offset + relPos.y();
2003  }
2004  } else {
2005  myWalkingAreaPath = nullptr;
2006  myRelX = lanePos;
2007  myRelY = lateral_offset - lanePosLat;
2008  }
2009  // guess direction
2010  const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
2011  if (myStage->getNextRouteEdge() != nullptr) {
2012  if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
2013  myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
2014  myDir = FORWARD;
2015  } else {
2016  myDir = BACKWARD;
2017  }
2018  } else {
2019  // guess from angle
2020  if (angleDiff <= 90) {
2021  // keep direction
2022  if (myDir == UNDEFINED_DIRECTION) {
2023  myDir = FORWARD;
2024  }
2025  } else {
2026  // change direction
2027  myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
2028  }
2029  }
2030  // update next lane info (after guessing direction)
2031  if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
2032  const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge());
2033  // assume that we will eventually move back onto the sidewalk if
2034  // there is one
2035  myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
2036 #ifdef DEBUG_MOVETOXY
2037  std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
2038 #endif
2039  }
2040 #ifdef DEBUG_MOVETOXY
2041  std::cout << " newRelPos=" << Position(myRelX, myRelY) << " edge=" << myPerson->getEdge()->getID() << " newPos=" << myPerson->getPosition()
2042  << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
2043 #endif
2044  } else {
2045  // map outside the network
2046  myRemoteXYPos = pos;
2047  }
2048 
2049 }
2050 
2051 
2052 bool
2054  return myAmJammed;
2055 }
2056 
2057 const MSLane*
2059  return myLane;
2060 }
2061 
2062 double
2063 MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
2064  // check for overlap
2065  const double maxX = getMaxX(includeMinGap);
2066  const double minX = getMinX(includeMinGap);
2067  //if (DEBUGCOND(*this)) {
2068  // std::cout << std::setprecision(2) << " distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
2069  //}
2070  if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
2071  // avoid blocking by itself on looped route
2072  return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
2073  }
2074  if (myDir == FORWARD) {
2075  return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
2076  } else {
2077  return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
2078  }
2079 }
2080 
2081 
2082 void
2084  for (int i = 0; i < (int)into.size(); ++i) {
2085  if (gDebugFlag1) {
2086  std::cout << " i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
2087  << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
2088  << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
2089  }
2090  const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
2091  const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
2092  if (dO < dI) {
2093  into[i] = obs2[i];
2094  } else if (dO == dI
2095  && into[i].type != OBSTACLE_PED
2096  && into[i].type != OBSTACLE_VEHICLE
2097  && (obs2[i].type == OBSTACLE_PED ||
2098  obs2[i].type == OBSTACLE_VEHICLE)) {
2099  into[i] = obs2[i];
2100  }
2101  }
2102 }
2103 
2104 void
2105 MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
2106  for (int i = 0; i < (int)into.size(); ++i) {
2107  int i2 = i + offset;
2108  if (i2 >= 0 && i2 < (int)obs2.size()) {
2109  if (dir == FORWARD) {
2110  if (obs2[i2].xBack < into[i].xBack) {
2111  into[i] = obs2[i2];
2112  }
2113  } else {
2114  if (obs2[i2].xFwd > into[i].xFwd) {
2115  into[i] = obs2[i2];
2116  }
2117  }
2118  }
2119  }
2120 }
2121 
2122 
2123 bool
2125  if (link->haveRed()) {
2126  const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
2127  if (ignoreRedTime >= 0) {
2128  const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
2129  if (DEBUGCOND(*this)) {
2130  std::cout << SIMTIME << " ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
2131  }
2132  return ignoreRedTime > redDuration;
2133  } else {
2134  return false;
2135  }
2136  } else {
2137  return false;
2138  }
2139 }
2140 
2141 const std::string&
2143  return myPerson->getID();
2144 }
2145 
2146 double
2148  return myPerson->getVehicleType().getWidth();
2149 }
2150 
2151 
2152 bool
2154  return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
2155 }
2156 
2157 // ===========================================================================
2158 // MSPModel_Striping::PStateVehicle method definitions
2159 // ===========================================================================
2160 
2161 MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY):
2162  myVehicle(veh) {
2163  myLane = walkingarea; // to ensure correct limits when calling otherStripe()
2164  myRelX = relX;
2165  myRelY = relY;
2166 }
2167 
2168 const std::string&
2170  return myVehicle->getID();
2171 }
2172 
2173 double
2175  return myVehicle->getVehicleType().getWidth();
2176 }
2177 
2178 double
2179 MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
2180  return myRelX - myVehicle->getVehicleType().getWidth() / 2 - SAFETY_GAP ;
2181 }
2182 
2183 double
2184 MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
2185  return myRelX + myVehicle->getVehicleType().getWidth() / 2 + SAFETY_GAP;
2186 }
2187 
2188 // ===========================================================================
2189 // MSPModel_Striping::MovePedestrians method definitions
2190 // ===========================================================================
2191 
2192 SUMOTime
2194  std::set<MSPerson*> changedLane;
2195  myModel->moveInDirection(currentTime, changedLane, FORWARD);
2196  myModel->moveInDirection(currentTime, changedLane, BACKWARD);
2197  // DEBUG
2198 #ifdef LOG_ALL
2199  for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
2200  const MSLane* lane = it_lane->first;
2201  Pedestrians pedestrians = it_lane->second;
2202  if (pedestrians.size() == 0) {
2203  continue;
2204  }
2205  sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
2206  std::cout << SIMTIME << " lane=" << lane->getID();
2207  for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
2208  const PState& p = *pedestrians[ii];
2209  std::cout << " (" << p.myPerson->getID() << " " << p.myRelX << "," << p.myRelY << " " << p.myDir << ")";
2210  }
2211  std::cout << "\n";
2212  }
2213 #endif
2214  return DELTA_T;
2215 }
2216 
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:73
std::pair< const MSPerson *, double > PersonDist
Definition: MSPModel.h:39
#define DEBUGCOND2(LANE)
#define DEBUGCOND(PED)
#define MINGAP_TO_VEHICLE
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define SPEED2DIST(x)
Definition: SUMOTime.h:43
#define SUMOTime_MAX
Definition: SUMOTime.h:32
#define SIMTIME
Definition: SUMOTime.h:60
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
#define DIST2SPEED(x)
Definition: SUMOTime.h:45
long long int SUMOTime
Definition: SUMOTime.h:31
@ SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:31
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:29
T MIN3(T a, T b, T c)
Definition: StdDefs.h:86
T MIN2(T a, T b)
Definition: StdDefs.h:73
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:60
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:192
static double fromNaviDegree(const double angle)
Definition: GeomHelper.cpp:209
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:173
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:311
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:216
A road/street connecting two junctions.
Definition: MSEdge.h:77
static const MSEdgeVector & getAllEdges()
Returns all edges with a numerical id.
Definition: MSEdge.cpp:847
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition: MSEdge.h:261
const MSEdgeVector & getPredecessors() const
Definition: MSEdge.h:383
bool isWalkingArea() const
return whether this edge is walking area
Definition: MSEdge.h:275
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:251
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:166
const MSJunction * getFromJunction() const
Definition: MSEdge.h:388
double getLength() const
return the length of the edge
Definition: MSEdge.h:630
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:256
const MSJunction * getToJunction() const
Definition: MSEdge.h:392
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:1013
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gCheck4Accidents
Definition: MSGlobals.h:73
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:66
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:102
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:640
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction
Definition: MSLane.h:438
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition: MSLane.h:407
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition: MSLane.cpp:2128
double getLength() const
Returns the lane's length.
Definition: MSLane.h:539
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:2140
MSLane * getCanonicalSuccessorLane() const
Definition: MSLane.cpp:2612
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:825
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:2542
AnyVehicleIterator anyVehiclesUpstreamEnd() const
end iterator for iterating over all vehicles touching this lane in upstream direction
Definition: MSLane.h:450
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:673
const PositionVector & getShape() const
Returns this lane's shape.
Definition: MSLane.h:476
AnyVehicleIterator anyVehiclesUpstreamBegin() const
begin iterator for iterating over all vehicles touching this lane in upstream direction
Definition: MSLane.h:444
AnyVehicleIterator anyVehiclesBegin() const
begin iterator for iterating over all vehicles touching this lane in downstream direction
Definition: MSLane.h:432
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:555
The simulated network and simulation perfomer.
Definition: MSNet.h:89
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:313
bool hasPedestrianNetwork() const
return whether the network contains walkingareas and crossings
Definition: MSNet.h:705
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:464
MSPedestrianRouter & getPedestrianRouter(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition: MSNet.cpp:1227
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:986
bool hasInternalLinks() const
return whether the network contains internal links
Definition: MSNet.h:695
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
bool isJammed() const
whether the transportable is jammed
bool myAmJammed
whether the person is jammed
Position myRemoteXYPos
remote-controlled position
bool myWaitingToEnter
whether the pedestrian is waiting to start its walk
const WalkingAreaPath * myWalkingAreaPath
the current walkingAreaPath or 0
SUMOTime getWaitingTime(const MSStageMoving &stage, SUMOTime now) const
return the time the transportable spent standing
PState()
constructor for PStateVehicle
double myRelX
the advancement along the current lane
double distToLaneEnd() const
the absolute distance to the end of the lane in walking direction (or to the arrivalPos)
int myDir
the walking direction on the current lane (1 forward, -1 backward)
double myRelY
the orthogonal shift on the current lane
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
void walk(const Obstacles &obs, SUMOTime currentTime)
perform position update
virtual double getWidth() const
return the person width
double mySpeed
the current walking speed
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
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
double getSpeed(const MSStageMoving &stage) const
return the current speed of the transportable
Position getPosition(const MSStageMoving &stage, SUMOTime now) const
return the network coordinate of the transportable
NextLaneInfo myNLI
information about the upcoming lane
const MSLane * myLane
the current lane of this pedestrian
double getAngle(const MSStageMoving &stage, SUMOTime now) const
return the direction in which the transportable faces in degrees
virtual const std::string & getID() const
return the person id
double getImpatience(SUMOTime now) const
returns the impatience
SUMOTime myWaitingTime
the consecutive time spent at speed 0
double distanceTo(const Obstacle &obs, const bool includeMinGap=true) const
const MSLane * getLane() const
whether the transportable is jammed
double getEdgePos(const MSStageMoving &stage, SUMOTime now) const
abstract methods inherited from PedestrianState
double getLength() const
return the length of the pedestrian
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 the person id
PStateVehicle(const MSVehicle *veh, const MSLane *walkingarea, double relX, double relY)
sorts the persons by position on the lane. If dir is forward, higher x positions come first.
The pedestrian following model.
static const double MIN_STARTUP_DIST
static double RESERVE_FOR_ONCOMING_FACTOR
static MinNextLengths myMinNextLengths
static SUMOTime jamTimeCrossing
bool hasPedestrians(const MSLane *lane)
whether the given lane has pedestrians on it
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 const double LOOKAHEAD_SAMEDIR
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 void initWalkingAreaPaths(const MSNet *net)
std::vector< PState * > Pedestrians
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
static const double LOOKAROUND_VEHICLES
static const double SQUEEZE
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)
bool myAmActive
whether an event for pedestrian processing was added
static const WalkingAreaPath * guessPath(const MSEdge *walkingArea, const MSEdge *before, const MSEdge *after)
static SUMOTime jamTime
static double stripeWidth
model parameters
bool blockedAtDist(const MSLane *lane, double vehSide, double vehWidth, double oncomingGap, std::vector< const MSPerson * > *collectBlockers)
whether a pedestrian is blocking the crossing of lane for the given vehicle bondaries
static const double MAX_WAIT_TOLERANCE
static Obstacles getVehicleObstacles(const MSLane *lane, int dir, PState *ped=0)
retrieve vehicle obstacles on the given lane
static const double OBSTRUCTED_PENALTY
std::map< const MSLane *, Obstacles, lane_by_numid_sorter > NextLanesObstacles
static const MSLane * getNextWalkingArea(const MSLane *currentLane, const int dir, const MSLink *&link)
return the next walkingArea in the given direction
PersonDist nextBlocking(const MSLane *lane, double minPos, double minRight, double maxLeft, double stopTime=0)
returns the next pedestrian beyond minPos that is laterally between minRight and maxLeft or 0
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
std::vector< Obstacle > Obstacles
void remove(MSTransportableStateAdapter *state)
remove the specified person from the pedestrian simulation
static const double DIST_BEHIND
bool usingInternalLanes()
whether movements on intersections are modelled /
void moveInDirectionOnLane(Pedestrians &pedestrians, const MSLane *lane, SUMOTime currentTime, std::set< MSPerson * > &changedLane, int dir)
move pedestrians forward on one lane
MSPModel_Striping(const OptionsCont &oc, MSNet *net)
Constructor (it should not be necessary to construct more than one instance)
static bool addVehicleFoe(const MSVehicle *veh, const MSLane *walkingarea, const Position &relPos, double lateral_offset, double minY, double maxY, Pedestrians &toDelete, Pedestrians &transformedPeds)
static bool usingInternalLanesStatic()
static Obstacles getNeighboringObstacles(const Pedestrians &pedestrians, int egoIndex, int stripes)
static Pedestrians noPedestrians
empty pedestrian vector
static void addCloserObstacle(Obstacles &obs, double x, int stripe, int numStripes, const std::string &id, double width, int dir, ObstacleType type)
Pedestrians & getPedestrians(const MSLane *lane)
retrieves the pedestian vector for the given lane (may be empty)
static double dawdling
static int numStripes(const MSLane *lane)
return the maximum number of pedestrians walking side by side
static const double OBSTRUCTION_THRESHOLD
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
static const double INAPPROPRIATE_PENALTY
static const double ONCOMING_CONFLICT_PENALTY
int myNumActivePedestrians
the total number of active pedestrians
static const double LOOKAHEAD_ONCOMING
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:106
static int canTraverse(int dir, const ConstMSEdgeVector &route)
Definition: MSPModel.cpp:52
static const int FORWARD
Definition: MSPModel.h:105
static const double SIDEWALK_OFFSET
the offset for computing person positions when walking on edges without a sidewalk
Definition: MSPModel.h:113
static const int UNDEFINED_DIRECTION
Definition: MSPModel.h:107
static const double SAFETY_GAP
Definition: MSPModel.h:110
const MSEdge * getDestination() const
returns the destination edge
Definition: MSStage.cpp:70
virtual double getArrivalPos() const
Definition: MSStage.h:89
MSStoppingPlace * getDestinationStop() const
returns the destination stop (if any)
Definition: MSStage.h:80
Position getLanePosition(const MSLane *lane, double at, double offset) const
get position on lane at length at with orthogonal offset
Definition: MSStage.cpp:147
virtual const MSEdge * getNextRouteEdge() const =0
virtual bool moveToNextEdge(MSTransportable *transportable, SUMOTime currentTime, MSEdge *nextInternal=0)=0
move forward and return whether the transportable arrived
const std::vector< const MSEdge * > & getRoute() const
Definition: MSStage.h:505
virtual double getMaxSpeed(const MSTransportable *const transportable=nullptr) const =0
the maximum speed of the transportable
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
void registerJammed()
register a jammed transportable
const MSVehicleType & getVehicleType() const
Returns the object's "vehicle" type.
bool isPerson() const
Whether it is a person.
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:130
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
Definition: MSVehicle.cpp:1122
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition: MSVehicle.cpp:4046
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition: MSVehicle.h:411
const Position getBackPosition() const
Definition: MSVehicle.cpp:1347
double getSpeed() const
Returns the vehicle's current speed.
Definition: MSVehicle.h:458
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition: MSVehicle.h:930
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getMaxSpeed() const
Get vehicle's maximum speed [m/s].
double getLength() const
Get vehicle's length [m].
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:66
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
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:36
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:282
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:241
double x() const
Returns the x-position.
Definition: Position.h:54
double y() const
Returns the y-position.
Definition: Position.h:59
A list of positions.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
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(std::mt19937 *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.h:51
#define M_PI
Definition: odrSpiral.cpp:40
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
std::string description
the id / description of the obstacle
ObstacleType type
whether this obstacle denotes a border or a pedestrian
double xBack
maximal position on the current lane in backward direction