Eclipse SUMO - Simulation of Urban MObility
MSLink.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // A connection between lanes
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <iostream>
26 #include <algorithm>
27 #include <limits>
31 #include "MSNet.h"
32 #include "MSJunction.h"
33 #include "MSJunctionLogic.h"
34 #include "MSLink.h"
35 #include "MSLane.h"
38 #include "MSEdge.h"
39 #include "MSGlobals.h"
40 #include "MSVehicle.h"
43 
44 //#define MSLink_DEBUG_CROSSING_POINTS
45 //#define MSLink_DEBUG_CROSSING_POINTS_DETAILS
46 //#define MSLink_DEBUG_OPENED
47 //#define DEBUG_APPROACHING
48 //#define DEBUG_ZIPPER
49 //#define DEBUG_WALKINGAREA
50 //#define DEBUG_COND (myLane->getID()=="43[0]_0" && myLaneBefore->getID()==":33_0_0")
51 //#define DEBUG_COND (myLane->getID()=="end_0")
52 //#define DEBUG_COND (true)
53 #define DEBUG_COND2(obj) (obj->isSelected())
54 //#define DEBUG_COND2(obj) (obj->getID() == "train2")
55 //#define DEBUG_COND_ZIPPER (gDebugFlag1)
56 //#define DEBUG_COND_ZIPPER (true)
57 #define DEBUG_COND_ZIPPER (ego->isSelected())
58 
59 // ===========================================================================
60 // static member variables
61 // ===========================================================================
62 
63 #define INVALID_TIME -1000
64 
65 // the default safety gap when passing before oncoming pedestrians
66 #define JM_CROSSING_GAP_DEFAULT 10
67 
68 // minimim width between sibling lanes to qualify as non-overlapping
69 #define DIVERGENCE_MIN_WIDTH 2.5
70 
72 // additional caution is needed when approaching a zipper link
74 std::set<std::pair<MSLink*, MSLink*> > MSLink::myRecheck;
75 const double MSLink::NO_INTERSECTION(10000);
76 
77 // ===========================================================================
78 // ConflictInfo member method definitions
79 // ===========================================================================
80 
81 double
83  if (flag == CONFLICT_DUMMY_MERGE) {
84  return 0;
85  } else if (foeConflictIndex >= 0) {
86  return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
87  } else {
88  return -NO_INTERSECTION;
89  }
90 }
91 
92 double
94  if (foeConflictIndex >= 0) {
95  return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
96  } else {
97  return 0;
98  }
99 }
100 
101 double
104  return exitLink->getInternalLaneBefore()->getLength();
105  } else {
106  return lengthBehindCrossing;
107  }
108 }
109 
110 // ===========================================================================
111 // member method definitions
112 // ===========================================================================
113 MSLink::MSLink(MSLane* predLane, MSLane* succLane, MSLane* via, LinkDirection dir, LinkState state,
114  double length, double foeVisibilityDistance, bool keepClear,
115  MSTrafficLightLogic* logic, int tlIndex,
116  bool indirect) :
117  myLane(succLane),
118  myLaneBefore(predLane),
119  myApproachingPersons(nullptr),
120  myIndex(-1),
121  myTLIndex(tlIndex),
122  myLogic(logic),
123  myState(state),
125  myOffState(state),
126  myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
127  myDirection(dir),
128  myLength(length),
129  myFoeVisibilityDistance(foeVisibilityDistance),
130  myDistToFoePedCrossing(std::numeric_limits<double>::max()),
131  myHasFoes(false),
132  myAmCont(false),
133  myAmContOff(false),
135  myInternalLane(via),
136  myInternalLaneBefore(nullptr),
137  myMesoTLSPenalty(0),
138  myGreenFraction(1),
139  myLateralShift(0),
140  myOffFoeLinks(nullptr),
141  myWalkingAreaFoe(nullptr),
142  myWalkingAreaFoeExit(nullptr),
144  myParallelRight(nullptr),
145  myParallelLeft(nullptr),
146  myAmIndirect(indirect),
147  myRadius(std::numeric_limits<double>::max()),
148  myPermissions(myLaneBefore->getPermissions() & myLane->getPermissions() & (via == nullptr ? SVCAll : via->getPermissions())),
149  myJunction(nullptr) {
150 
152  // detect lateral shift from lane geometries
153  //std::cout << "DEBUG link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " hasInternal=" << MSNet::getInstance()->hasInternalLinks() << " shapeBefore=" << myLaneBefore->getShape().back() << " shapeFront=" << getViaLaneOrLane()->getShape().front() << "\n";
154  if ((myInternalLane != nullptr || predLane->isInternal())
155  && myLaneBefore->getShape().back() != getViaLaneOrLane()->getShape().front()) {
157  const PositionVector& to = getViaLaneOrLane()->getShape();
158  const double dist = from.back().distanceTo2D(to.front());
159  // figure out direction of shift
160  try {
161  from.move2side(dist);
162  } catch (InvalidArgument&) {
163  }
164  myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
165  if (MSGlobals::gLefthand) {
166  myLateralShift *= -1;
167  }
168  //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
169  }
170  }
171 }
172 
173 
175  delete myOffFoeLinks;
176  delete myApproachingPersons;
177 }
178 
179 
180 void
181 MSLink::addCustomConflict(const MSLane* from, const MSLane* to, double startPos, double endPos) {
182  myCustomConflicts.push_back(CustomConflict(from, to, startPos, endPos));
183 }
184 
186 MSLink::getCustomConflict(const MSLane* foeLane) const {
187  if (myCustomConflicts.size() > 0) {
188  const MSLane* foeFrom = foeLane->getNormalPredecessorLane();
189  const MSLane* foeTo = foeLane->getNormalSuccessorLane();
190  for (const CustomConflict& cc : myCustomConflicts) {
191  if (cc.from == foeFrom && cc.to == foeTo) {
192  return &cc;
193  }
194  }
195 
196  }
197  return nullptr;
198 }
199 
200 void
201 MSLink::setRequestInformation(int index, bool hasFoes, bool isCont,
202  const std::vector<MSLink*>& foeLinks,
203  const std::vector<MSLane*>& foeLanes,
204  MSLane* internalLaneBefore) {
205 //#ifdef MSLink_DEBUG_CROSSING_POINTS
206 // std::cout << " setRequestInformation() for junction " << getViaLaneOrLane()->getEdge().getFromJunction()->getID()
207 // << "\nInternalLanes = " << toString(getViaLaneOrLane()->getEdge().getFromJunction()->getInternalLanes())
208 // << std::endl;
209 //#endif
210  myIndex = index;
211  myHasFoes = hasFoes;
212  myAmCont = isCont;
213  myFoeLinks = foeLinks;
214  for (MSLane* foeLane : foeLanes) {
215  // cannot assign vector due to const-ness
216  myFoeLanes.push_back(foeLane);
217  }
218  myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
219  myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
220  myInternalLaneBefore = internalLaneBefore;
221  MSLane* lane = nullptr;
222  if (internalLaneBefore != nullptr) {
223  // this is an exit link. compute crossing points with all foeLanes
224  lane = internalLaneBefore;
225  //} else if (myLane->getEdge().isCrossing()) {
226  // // this is the link to a pedestrian crossing. compute crossing points with all foeLanes
227  // // @note not currently used by pedestrians
228  // lane = myLane;
229  }
230  const MSLink* entryLink = getCorrespondingEntryLink();
231  if (entryLink->getOffState() == LinkState::LINKSTATE_ALLWAY_STOP && entryLink->getTLLogic() != nullptr) {
232  // TLS has "normal" right of way rules but all conflicting links are foes when switching TLS off
233  // (unless it's an internal junction link which should ignore all foes and should be ignored by all foes
234  myOffFoeLinks = new std::vector<MSLink*>();
235  if (isEntryLink()) {
236  for (MSLane* foeLane : foeLanes) {
237  assert(foeLane->isInternal() || foeLane->isCrossing());
238  MSLink* viaLink = foeLane->getIncomingLanes().front().viaLink;
239  if (viaLink->getLaneBefore()->isNormal()) {
240  myOffFoeLinks->push_back(viaLink);
241  }
242  }
243  }
244  }
245 #ifdef MSLink_DEBUG_CROSSING_POINTS
246  std::cout << "link " << myIndex << " to " << getViaLaneOrLane()->getID() << " internalLaneBefore=" << (lane == 0 ? "NULL" : lane->getID()) << " has foes: " << toString(foeLanes) << "\n";
247 #endif
248  if (lane != nullptr) {
249  const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
250  if (lane->getIncomingLanes().size() != 1) {
251  throw ProcessError("Internal lane '" + lane->getID() + "' has " + toString(lane->getIncomingLanes().size()) + " predecessors");
252  }
253  const MSLink* junctionEntryLink = lane->getEntryLink();
254  const bool isSecondPart = isExitLinkAfterInternalJunction();
255  // compute crossing points
256  for (const MSLane* foeLane : myFoeLanes) {
257  const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
258  if (cc != nullptr) {
259  // handle custom conflict definition
260  double startPos = cc->startPos;
261  const double conflictSize = cc->endPos - cc->startPos;
262  if (isSecondPart) {
263  startPos -= junctionEntryLink->getViaLane()->getLength();
264  }
265  // the foe connection may be split at an internal
266  // junction, we need to figure out whether the current
267  // foeLane is the intended target for the custom conflict
268  // There are two possibilities:
269  // a) We have no custom conflict for the reverse pair of connections
270  // -> just check whether lane and foeLane intersect
271  // b) We have a "reverse" custom conflict
272  // -> check whether it covers the foeLane
273  const CustomConflict* rcc = foeLane->getEntryLink()->getCustomConflict(lane);
274  bool haveIntersection = false;
275  if (rcc == nullptr) {
276  // a)
277  haveIntersection = lane->getShape().intersectsAtLengths2D(foeLane->getShape()).size() > 0;
278  } else {
279  // b)
280  const bool foeIsSecondPart = foeLane->getLogicalPredecessorLane()->isInternal();
281  double foeStartPos = rcc->startPos;
282  const double foeConflictSize = rcc->endPos - rcc->startPos;
283  if (foeIsSecondPart) {
284  foeStartPos -= foeLane->getLogicalPredecessorLane()->getLength();
285  }
286  const double foeEndPos = foeStartPos + foeConflictSize;
287  haveIntersection = ((foeStartPos > 0 && foeStartPos < foeLane->getLength())
288  || (foeEndPos > 0 && foeEndPos < foeLane->getLength()));
289  }
290  if (haveIntersection) {
291  myConflicts.push_back(ConflictInfo(lane->getLength() - startPos, conflictSize));
292  } else {
293  myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0));
294  }
295 #ifdef MSLink_DEBUG_CROSSING_POINTS
296  std::cout << " " << lane->getID() << " custom conflict with " << foeLane->getID() << " customReverse=" << (rcc != nullptr)
297  << " haveIntersection=" << haveIntersection
298  << " startPos=" << startPos << " conflictSize=" << conflictSize
299  << " lbc=" << myConflicts.back().lengthBehindCrossing
300  << "\n";
301 #endif
302  continue;
303  }
304  myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->getEdge().isCrossing();
305  const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
306  if (sameTarget && !beforeInternalJunction && !contIntersect(lane, foeLane)) {
307  //if (myLane == foeLane->getLinkCont()[0]->getLane()) {
308  // this foeLane has the same target and merges at the end (lane exits the junction)
309  const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
310  if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
311  // account for lateral shift by the entry links
312  if (foeLane->getEntryLink()->isIndirect()) {
313  myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0)); // dummy value, never used
314 #ifdef MSLink_DEBUG_CROSSING_POINTS
315  std::cout << " " << lane->getID() << " dummy merge with indirect" << foeLane->getID() << "\n";
316 #endif
317  } else {
318  myConflicts.push_back(ConflictInfo(0, foeLane->getWidth(), CONFLICT_DUMMY_MERGE)); // dummy value, never used
319 #ifdef MSLink_DEBUG_CROSSING_POINTS
320  std::cout << " " << lane->getID() << " dummy merge with " << foeLane->getID() << "\n";
321 #endif
322  }
323  } else {
324  const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
325  const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
326  myConflicts.push_back(ConflictInfo(lbcLane, foeLane->getWidth()));
327 #ifdef MSLink_DEBUG_CROSSING_POINTS
328  std::cout
329  << " " << lane->getID()
330  << " merges with " << foeLane->getID()
331  << " nextLane " << lane->getLinkCont()[0]->getViaLaneOrLane()->getID()
332  << " dist1=" << myConflicts.back().lengthBehindCrossing
333  << "\n";
334 #endif
335  }
336  } else {
337  std::vector<double> intersections1 = lane->getShape().intersectsAtLengths2D(foeLane->getShape());
338 #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
339  std::cout << " intersections1=" << toString(intersections1) << "\n";
340 #endif
341  bool haveIntersection = true;
342  if (intersections1.size() == 0) {
343  intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
344  haveIntersection = false;
345  } else if (intersections1.size() > 1) {
346  std::sort(intersections1.begin(), intersections1.end());
347  }
348  std::vector<double> intersections2 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
349 #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
350  std::cout << " intersections2=" << toString(intersections2) << "\n";
351 #endif
352  if (intersections2.size() == 0) {
353  intersections2.push_back(0);
354  } else if (intersections2.size() > 1) {
355  std::sort(intersections2.begin(), intersections2.end());
356  }
357  double conflictSize = foeLane->getWidth();
359  if (haveIntersection) {
360  flag = CONFLICT_DEFAULT;
361  const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
362  const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
363  const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
364  //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
365  // GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
366  const double widthFactor = 1 / MAX2(sin(DEG2RAD(angleDiff)), 0.2) * 2 - 1;
367  //std::cout << " intersection of " << lane->getID() << " with " << foeLane->getID() << " angle1=" << angle1 << " angle2=" << angle2 << " angleDiff=" << angleDiff << " widthFactor=" << widthFactor << "\n";
368  conflictSize *= widthFactor;
369  conflictSize = MIN2(conflictSize, lane->getLength());
370  // lane width affects the crossing point
371  intersections1.back() -= conflictSize / 2;
372  // ensure non-negative offset for weird geometries
373  intersections1.back() = MAX2(0.0, intersections1.back());
374 
375  // also length/geometry factor. (XXX: Why subtract width/2 *before* converting geometric position to lane pos? refs #3031)
376  intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
377 
378  if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->getEdge().isCrossing()) {
380  }
381 
382  if (foeLane->getEdge().isCrossing()) {
383  const_cast<MSLink*>(getCorrespondingEntryLink())->updateDistToFoePedCrossing(intersections1.back());
384  };
385  }
386 
387  myConflicts.push_back(ConflictInfo(
388  lane->getLength() - intersections1.back(),
389  conflictSize, flag));
390 
391 #ifdef MSLink_DEBUG_CROSSING_POINTS
392  std::cout
393  << " intersection of " << lane->getID()
394  << " totalLength=" << lane->getLength()
395  << " with " << foeLane->getID()
396  << " totalLength=" << foeLane->getLength()
397  << " dist1=" << myConflicts.back().lengthBehindCrossing
398  << " widthFactor=" << myConflicts.back().conflictSize / foeLane->getWidth()
399  << "\n";
400 #endif
401  }
402  }
403  // check for overlap with internal lanes from the same source lane
404  const MSLane* pred = lane->getLogicalPredecessorLane();
405  // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
406  // we add all other internal lanes from pred as foeLanes
407  for (const MSLink* const link : pred->getLinkCont()) {
408  const MSLane* const sibling = link->getViaLane();
409  if (sibling != lane && sibling != nullptr) {
410  const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
411  if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
412  // account for lateral shift by the entry links
413  continue;
414  }
415  const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
416  double lbcLane;
417  if (lane->getLength() == sibling->getLength() && &lane->getEdge() == &sibling->getEdge()) {
418  // for parallel lanes, avoid inconsistency in distance estimation (#10988)
419  // between forward distance (getLeaderInfo)
420  // and backward distance used in lane-changing (getFollowersOnConsecutive)
421  lbcLane = lane->getLength() - distToDivergence;
422  } else {
423  lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
424  }
425  ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
426  auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
427  if (it != myFoeLanes.end()) {
428  // avoid duplicate foeLane
429  const int replacedIndex = (int)(it - myFoeLanes.begin());
430  myConflicts[replacedIndex] = ci;
431  } else {
432  myConflicts.push_back(ci);
433  myFoeLanes.push_back(sibling);
434  }
435 #ifdef MSLink_DEBUG_CROSSING_POINTS
436  std::cout << " adding same-origin foe" << sibling->getID()
437  << " dist1=" << myConflicts.back().lengthBehindCrossing
438  << "\n";
439 #endif
440  }
441  }
442  // init points for the symmetrical conflict
443  // for each pair of conflicting lanes, the link that gets second, sets the pointers
444  for (int i = 0; i < (int)myFoeLanes.size(); i++) {
445  const MSLane* foeLane = myFoeLanes[i];
446  MSLink* foeExitLink = foeLane->getLinkCont()[0];
447  int foundIndex = -1;
448  for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
449  if (foeExitLink->myFoeLanes[i2] == lane) {
450  myConflicts[i].foeConflictIndex = i2;
451  foeExitLink->myConflicts[i2].foeConflictIndex = i;
452  myRecheck.erase({foeExitLink, this});
453  foundIndex = i2;
454  break;
455  }
456  }
457 #ifdef MSLink_DEBUG_CROSSING_POINTS
458  std::cout << lane->getID() << " foeLane=" << foeLane->getID() << " index=" << i << " foundIndex=" << foundIndex << "\n";
459 #endif
460  if (foundIndex < 0) {
461  if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
462  myRecheck.insert({this, foeExitLink});
463  }
464  }
465  }
466  }
468  // check for links with the same origin lane and the same destination edge
469  const MSEdge* myTarget = &myLane->getEdge();
470  // save foes for entry links
471  for (MSLink* const it : myLaneBefore->getLinkCont()) {
472  const MSEdge* target = &(it->getLane()->getEdge());
473  if (it == this) {
474  continue;
475  }
476  if (target == myTarget) {
477  mySublaneFoeLinks.push_back(it);
478 #ifdef MSLink_DEBUG_CROSSING_POINTS
479  std::cout << " sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
480 #endif
481  } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
482  // potential turn conflict
483  mySublaneFoeLinks2.push_back(it);
484 #ifdef MSLink_DEBUG_CROSSING_POINTS
485  std::cout << " sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
486 #endif
487  }
488  }
489  // save foes for exit links
490  if (fromInternalLane()) {
491  //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
492  for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
493  if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
494  //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
495  mySublaneFoeLanes.push_back(link->getViaLane());
496  }
497  }
498  }
499  }
500  if (myInternalLaneBefore != nullptr
502  // for right turns, the curvature helps rather than restricts the linkLeader check
503  && (
506  const double angle = fabs(GeomHelper::angleDiff(
508  myLane->getShape().angleAt2D(0)));
509  if (angle > 0) {
510  double length = myInternalLaneBefore->getShape().length2D();
511  if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
512  myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
513  length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
514  } else if (myInternalLane != nullptr) {
515  length += myInternalLane->getShape().length2D();
516  }
517  myRadius = length / angle;
518  //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
519  }
520  }
521 }
522 
523 
524 void
526  for (auto item : myRecheck) {
527 #ifdef MSLink_DEBUG_CROSSING_POINTS
528  std::cout << " recheck l1=" << item.first->getDescription() << " l2=" << item.second->getDescription() << "\n";
529 #endif
530  MSLink* link = item.first;
531  MSLink* foeExitLink = item.second;
532  const MSLane* lane = link->getInternalLaneBefore();
533  const MSLane* foeLane = foeExitLink->getInternalLaneBefore();
534  int conflictIndex = -1;
535  for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
536  if (link->myFoeLanes[i] == foeLane) {
537  conflictIndex = i;
538  break;
539  }
540  }
541  if (conflictIndex == -1) {
542  WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
543  continue;
544  }
545  ConflictInfo& ci = link->myConflicts[conflictIndex];
546  std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
547  if (intersections1.size() == 0) {
548 #ifdef MSLink_DEBUG_CROSSING_POINTS
549  std::cout << " no intersection\n";
550 #endif
551  continue;
552  }
553  const double widthFactor = ci.conflictSize / foeLane->getWidth();
554  const double conflictSize2 = lane->getWidth() * widthFactor;
555  std::sort(intersections1.begin(), intersections1.end());
556  intersections1.back() -= conflictSize2 / 2;
557  intersections1.back() = MAX2(0.0, intersections1.back());
558  ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
559  foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
560 #ifdef MSLink_DEBUG_CROSSING_POINTS
561  std::cout << " ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
562 #endif
563  }
564  myRecheck.clear();
565 }
566 
567 double
568 MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource) const {
569  double lbcSibling = 0;
570  double lbcLane = 0;
571 
572  PositionVector l = lane->getShape();
573  PositionVector s = sibling->getShape();
574  double length = l.length2D();
575  double sibLength = s.length2D();
576  if (!sameSource) {
577  l = l.reverse();
578  s = s.reverse();
579  } else if (sibling->getEntryLink()->myAmIndirect) {
580  // ignore final waiting position since it may be quite close to the lane
581  // shape but the waiting position is perpendicular (so the minDist
582  // requirement is not necessary
583  lbcSibling += s[-1].distanceTo2D(s[-2]);
584  s.pop_back();
585  } else if (lane->getEntryLink()->myAmIndirect) {
586  // ignore final waiting position since it may be quite close to the lane
587  // shape but the waiting position is perpendicular (so the minDist
588  // requirement is not necessary
589  lbcLane += l[-1].distanceTo2D(l[-2]);
590  l.pop_back();
591  }
592 
593 #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
594  std::cout << " sameSource=" << sameSource << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
595 #endif
596  if (l.back().distanceTo2D(s.back()) > minDist) {
597  // compute the final divergence point
598  // this position serves two purposes:
599  // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
600  // 2) both vehicles are put into a cf-relationship while before the point.
601  // Since the actual crossing point is at the start of the junction,
602  // we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
603  std::vector<double> distances = l.distances(s);
604 #ifdef MSLink_DEBUG_CROSSING_POINTS
605  std::cout << " distances=" << toString(distances) << "\n";
606 #endif
607  assert(distances.size() == l.size() + s.size());
608  if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
609  // do a pairwise check between lane and sibling to make because we do not know which of them bends more
610  for (int j = (int)s.size() - 2; j >= 0; j--) {
611  const int i = j + (int)l.size();
612  const double segLength = s[j].distanceTo2D(s[j + 1]);
613  if (distances[i] > minDist) {
614  lbcSibling += segLength;
615  } else {
616  // assume no sharp bends and just interpolate the last segment
617  lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
618  break;
619  }
620  }
621  for (int i = (int)l.size() - 2; i >= 0; i--) {
622  const double segLength = l[i].distanceTo2D(l[i + 1]);
623  if (distances[i] > minDist) {
624  lbcLane += segLength;
625  } else {
626  // assume no sharp bends and just interpolate the last segment
627  lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
628  break;
629  }
630  }
631  }
632  assert(lbcSibling >= -NUMERICAL_EPS);
633  assert(lbcLane >= -NUMERICAL_EPS);
634  }
635  const double distToDivergence1 = sibling->getLength() - lbcSibling;
636  const double distToDivergence2 = lane->getLength() - lbcLane;
637  const double distToDivergence = MIN3(
638  MAX2(distToDivergence1, distToDivergence2),
639  sibLength, length);
640 #ifdef MSLink_DEBUG_CROSSING_POINTS
641  std::cout << " distToDivergence=" << distToDivergence
642  << " distTD1=" << distToDivergence1
643  << " distTD2=" << distToDivergence2
644  << " length=" << length
645  << " sibLength=" << sibLength
646  << "\n";
647 #endif
648  return distToDivergence;
649 }
650 
651 
652 bool
653 MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
654  if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
655  std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
656  return intersections.size() > 0;
657  }
658  return false;
659 }
660 
661 
662 void
663 MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
664  const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
665  const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
666 #ifdef DEBUG_APPROACHING
667  if (DEBUG_COND2(approaching)) {
668  std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
669  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
670  std::cout << "'" << i->first->getID() << "'" << std::endl;
671  }
672  }
673 #endif
674  myApproachingVehicles.emplace(approaching,
675  ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
676  arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
677 }
678 
679 
680 void
682 
683 #ifdef DEBUG_APPROACHING
684  if (DEBUG_COND2(approaching)) {
685  std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
686  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
687  std::cout << "'" << i->first->getID() << "'" << std::endl;
688  }
689  }
690 #endif
691  myApproachingVehicles.emplace(approaching, ai);
692 }
693 
694 void
695 MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
696  if (myApproachingPersons == nullptr) {
698  }
699  myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
700 }
701 
702 void
704 
705 #ifdef DEBUG_APPROACHING
706  if (DEBUG_COND2(veh)) {
707  std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
708  std::cout << "' Removing approaching vehicle '" << veh->getID() << "'\nCurrently registered vehicles:" << std::endl;
709  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
710  std::cout << "'" << i->first->getID() << "'" << std::endl;
711  }
712  }
713 #endif
714  myApproachingVehicles.erase(veh);
715 }
716 
717 
718 void
720  if (myApproachingPersons == nullptr) {
721  WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
722  return;
723  }
724 #ifdef DEBUG_APPROACHING
725  if (DEBUG_COND2(person)) {
726  std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
727  std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
728  for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
729  std::cout << "'" << i->first->getID() << "'" << std::endl;
730  }
731  }
732 #endif
733  myApproachingPersons->erase(person);
734 }
735 
736 
739  auto i = myApproachingVehicles.find(veh);
740  if (i != myApproachingVehicles.end()) {
741  return i->second;
742  } else {
743  return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
744  }
745 }
746 
747 
748 void
750  myApproachingVehicles.clear();
751 }
752 
753 
754 SUMOTime
755 MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
756  const double leaveSpeed, const double vehicleLength) const {
757  return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
758 }
759 
760 
761 bool
762 MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
763  double impatience, double decel, SUMOTime waitingTime, double posLat,
764  BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
765 #ifdef MSLink_DEBUG_OPENED
766  if (gDebugFlag1) {
767  std::cout << SIMTIME << " opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
768  }
769 #endif
770  if (haveRed() && !ignoreRed) {
771  return false;
772  }
774  return true;
775  }
776  const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
778  // check for foes on the same lane with the same target edge
779  for (const MSLink* foeLink : mySublaneFoeLinks) {
780  assert(myLane != foeLink->getLane());
781  for (const auto& it : foeLink->myApproachingVehicles) {
782  const SUMOVehicle* foe = it.first;
783  if (
784  // there only is a conflict if the paths cross
785  ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
786  || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
787  // the vehicle that arrives later must yield
788  && (arrivalTime > it.second.arrivalTime
789  // if both vehicles arrive at the same time, the one
790  // to the left must yield
791  || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
792  if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
793  impatience, decel, waitingTime, ego)) {
794 #ifdef MSLink_DEBUG_OPENED
795  if (gDebugFlag1) {
796  std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
797  }
798 #endif
799  if (collectFoes == nullptr) {
800 #ifdef MSLink_DEBUG_OPENED
801  if (gDebugFlag1) {
802  std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
803  }
804 #endif
805  return false;
806  } else {
807  collectFoes->push_back(it.first);
808  }
809  }
810  }
811  }
812  }
813  // check for foes on the same lane with a different target edge
814  // (straight movers take precedence if the paths cross)
815  const int lhSign = MSGlobals::gLefthand ? -1 : 1;
816  for (const MSLink* foeLink : mySublaneFoeLinks2) {
818  for (const auto& it : foeLink->myApproachingVehicles) {
819  const SUMOVehicle* foe = it.first;
820  // there only is a conflict if the paths cross
821  // and if the vehicles are not currently in a car-following relationship
822  const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
823  if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
825  && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
827  && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
828  if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
829  impatience, decel, waitingTime, ego)) {
830 #ifdef MSLink_DEBUG_OPENED
831  if (gDebugFlag1) {
832  std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
833  }
834 #endif
835  if (collectFoes == nullptr) {
836 #ifdef MSLink_DEBUG_OPENED
837  if (gDebugFlag1) {
838  std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
839  }
840 #endif
841  return false;
842  } else {
843  collectFoes->push_back(it.first);
844  }
845  }
846  }
847  }
848  }
849  }
851  // priority usually means the link is open but there are exceptions:
852  // zipper still needs to collect foes
853  // sublane model could have detected a conflict
854  return collectFoes == nullptr || collectFoes->size() == 0;
855  }
857  return false;
859  return false;
860  }
861 
862  const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
863 #ifdef MSLink_DEBUG_OPENED
864  if (gDebugFlag1) {
865  std::cout << SIMTIME << " opened link=" << getViaLaneOrLane()->getID() << " foeLinks=" << foeLinks.size() << "\n";
866  }
867 #endif
868 
869  if (MSGlobals::gUseMesoSim && impatience == 1) {
870  return true;
871  }
872  const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
873  for (const MSLink* const link : foeLinks) {
875  if (link->haveRed()) {
876  continue;
877  }
878  }
879 #ifdef MSLink_DEBUG_OPENED
880  if (gDebugFlag1) {
881  std::cout << SIMTIME << " foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
882  if (link->getLane()->isCrossing()) {
883  std::cout << SIMTIME << " approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
884  }
885  }
886 #endif
887  if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
888  impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
889  return false;
890  }
891  }
892  if (collectFoes != nullptr && collectFoes->size() > 0) {
893  return false;
894  }
895  return true;
896 }
897 
898 
899 bool
900 MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
901  bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
902  BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
903  for (const auto& it : myApproachingVehicles) {
904 #ifdef MSLink_DEBUG_OPENED
905  if (gDebugFlag1) {
906  if (ego != nullptr
907  && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
909  std::stringstream stream; // to reduce output interleaving from different threads
910  stream << SIMTIME << " " << myApproachingVehicles.size() << " foe link=" << getViaLaneOrLane()->getID()
911  << " foeVeh=" << it.first->getID() << " (below ignore speed)"
912  << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
913  << "\n";
914  std::cout << stream.str();
915  }
916  }
917 #endif
918  if (it.first != ego
919  && (ego == nullptr
921  || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
923  && !ignoreFoe(ego, it.first)
924  && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
925  && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
926  impatience, decel, waitingTime, ego)) {
927  if (collectFoes == nullptr) {
928  return true;
929  } else {
930  collectFoes->push_back(it.first);
931  }
932  }
933  }
934  if (myApproachingPersons != nullptr && !haveRed()) {
935  for (const auto& it : *myApproachingPersons) {
936  if ((ego == nullptr
938  || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
940  && !ignoreFoe(ego, it.first)
941  && !((arrivalTime > it.second.leavingTime) || (leaveTime < it.second.arrivalTime))) {
942  // check whether braking is feasible (ego might have started to accelerate already)
943  const auto& cfm = ego->getVehicleType().getCarFollowModel();
944 #ifdef MSLink_DEBUG_OPENED
945  if (gDebugFlag1) {
946  std::cout << SIMTIME << ": " << ego->getID() << " conflict with person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime << " dist=" << dist << " bGap=" << cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0) << "\n";
947  }
948 #endif
949  if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
950 #ifdef MSLink_DEBUG_OPENED
951  if (gDebugFlag1) {
952  std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
953  }
954 #endif
955  if (collectFoes == nullptr) {
956  return true;
957  } else {
958  collectFoes->push_back(it.first);
959  }
960  }
961  }
962  }
963  }
964  return false;
965 }
966 
967 
968 bool
970  SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
971  bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
972  const SUMOTrafficObject* ego) const {
973 #ifdef MSLink_DEBUG_OPENED
974  if (gDebugFlag1) {
975  std::stringstream stream; // to reduce output interleaving from different threads
976  stream << " link=" << getDescription()
977  << " foeVeh=" << veh->getID()
978  << " req=" << avi.willPass
979  << " aT=" << avi.arrivalTime
980  << " lT=" << avi.leavingTime
981  << "\n";
982  std::cout << stream.str();
983  }
984 #endif
985  if (!avi.willPass) {
986  return false;
987  }
989  assert(waitingTime > 0);
990 #ifdef MSLink_DEBUG_OPENED
991  if (gDebugFlag1) {
992  std::stringstream stream; // to reduce output interleaving from different threads
993  stream << " foeDist=" << avi.dist
994  << " foeBGap=" << veh->getBrakeGap(false)
995  << " foeWait=" << avi.waitingTime
996  << " wait=" << waitingTime
997  << "\n";
998  std::cout << stream.str();
999  }
1000 #endif
1001  // when using actionSteps, the foe waiting time may be outdated
1002  const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
1003  if (waitingTime > avi.waitingTime + actionDelta) {
1004  return false;
1005  }
1006  if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
1007  return false;
1008  }
1009  }
1010  SUMOTime foeArrivalTime = avi.arrivalTime;
1011  double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
1012  if (impatience > 0 && arrivalTime < avi.arrivalTime) {
1013 #ifdef MSLink_DEBUG_OPENED
1014  gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
1015 #endif
1016  const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
1017  foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
1018 #ifdef MSLink_DEBUG_OPENED
1019  if (gDebugFlag6) {
1020  std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
1021  << " at=" << STEPS2TIME(arrivalTime)
1022  << " fat=" << STEPS2TIME(avi.arrivalTime)
1023  << " fatb=" << STEPS2TIME(fatb)
1024  << " fat2=" << STEPS2TIME(foeArrivalTime)
1025  << "\n";
1026  }
1027 #endif
1028  }
1029 
1030 
1031  const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
1033  : (ego == nullptr
1034  ? myLookaheadTime
1036  //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
1037 #ifdef MSLink_DEBUG_OPENED
1038  if (gDebugFlag1 || gDebugFlag6) {
1039  std::stringstream stream; // to reduce output interleaving from different threads
1040  stream << " imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
1041  std::cout << stream.str();
1042  }
1043 #endif
1044  if (avi.leavingTime < arrivalTime) {
1045  // ego wants to be follower
1046  if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
1047  || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
1048  veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
1049 #ifdef MSLink_DEBUG_OPENED
1050  if (gDebugFlag1 || gDebugFlag6) {
1051  std::cout << " blocked (cannot follow)\n";
1052  }
1053 #endif
1054  return true;
1055  }
1056  } else if (foeArrivalTime > leaveTime + lookAhead) {
1057  // ego wants to be leader.
1058  if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
1059  decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
1060 #ifdef MSLink_DEBUG_OPENED
1061  if (gDebugFlag1 || gDebugFlag6) {
1062  std::cout << " blocked (cannot lead)\n";
1063  }
1064 #endif
1065  return true;
1066  }
1067  } else {
1068  // even without considering safeHeadwayTime there is already a conflict
1069 #ifdef MSLink_DEBUG_OPENED
1070  if (gDebugFlag1 || gDebugFlag6) {
1071  std::cout << " blocked (hard conflict)\n";
1072  }
1073 #endif
1074  return true;
1075  }
1076  return false;
1077 }
1078 
1079 
1080 SUMOTime
1081 MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
1082  // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
1083  // b: distance driven past foeArrivalTime
1084  // m: permitted decceleration
1085  // d: total deceleration until foeArrivalTime
1086  // dist2: distance of foe at arrivalTime
1087  // actual arrivalTime must fall on a simulation step
1088  if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
1089  // foe enters the junction in the same step
1090  return foeArrivalTime;
1091  }
1092  if (arrivalTime % DELTA_T > 0) {
1093  arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
1094  }
1095  //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
1096  const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
1097  const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
1098  const double d = dt * m;
1099  const double a = dt * d / 2;
1100  const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
1101  const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
1102  if (0.5 * v * v / m <= dist2) {
1103  if (gDebugFlag6) {
1104  std::cout << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " a=" << a << " canBrakeToStop\n";
1105  }
1106  fasb = 0;
1107  return foeArrivalTime + TIME2STEPS(30);
1108  }
1109  // a = b (foe reaches the original distance to the stop line)
1110  // x: time driven past foeArrivalTime
1111  // v: foe speed without braking
1112  // v2: average foe speed after foeArrivalTime (braking continues for time x)
1113  // v2 = (v - d - x * m / 2)
1114  // b = v2 * x
1115  // solving for x gives:
1116  const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
1117 
1118 #ifdef MSLink_DEBUG_OPENED
1119  const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
1120  if (gDebugFlag6 || std::isnan(x)) {
1121  std::cout << SIMTIME << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
1122  }
1123 #endif
1124  fasb = v - (dt + x) * m;
1125  return foeArrivalTime + TIME2STEPS(x);
1126 }
1127 
1128 
1129 bool
1130 MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
1131  for (const MSLink* const link : myFoeLinks) {
1132  if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
1133  return true;
1134  }
1135  }
1136  for (const MSLane* const lane : myFoeLanes) {
1137  if (lane->getVehicleNumberWithPartials() > 0) {
1138  return true;
1139  }
1140  }
1141  return false;
1142 }
1143 
1144 
1145 std::pair<const SUMOVehicle*, const MSLink*>
1146 MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
1147  double closetDist = std::numeric_limits<double>::max();
1148  const SUMOVehicle* closest = nullptr;
1149  const MSLink* foeLink = nullptr;
1150  for (MSLink* link : myFoeLinks) {
1151  for (const auto& it : link->myApproachingVehicles) {
1152  //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
1153  if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
1154  return std::make_pair(nullptr, wrapAround);
1155  } else if (it.second.dist < closetDist) {
1156  closetDist = it.second.dist;
1157  if (it.second.willPass) {
1158  closest = it.first;
1159  foeLink = link;
1160  }
1161  }
1162  }
1163  }
1164  return std::make_pair(closest, foeLink);
1165 }
1166 
1167 
1168 void
1170  if (myState != state) {
1171  myLastStateChange = t;
1172  }
1173  myState = state;
1174  if (haveGreen()) {
1176  }
1177 }
1178 
1179 
1180 void
1182  myLogic = logic;
1183 }
1184 
1185 
1186 bool
1188  // when a traffic light is switched off minor roads have their cont status revoked
1190 }
1191 
1192 
1193 bool
1195  if (myInternalLane == nullptr || myAmCont) {
1196  return false;
1197  } else {
1199  if (!pred->getEdge().isInternal()) {
1200  return false;
1201  } else {
1202  const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1203  assert(pred2 != nullptr);
1204  const MSLink* const predLink = pred2->getLinkTo(pred);
1205  assert(predLink != nullptr);
1206  if (predLink->havePriority()) {
1207  return true;
1208  }
1210  return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
1211  } else {
1212  return predLink->haveYellow();
1213  }
1214  }
1215  }
1216 }
1217 
1218 
1219 bool
1221  if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
1222  return false;
1223  } else {
1225  if (!pred->getEdge().isInternal()) {
1226  return false;
1227  } else {
1228  const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1229  assert(pred2 != nullptr);
1230  const MSLink* const predLink = pred2->getLinkTo(pred);
1231  assert(predLink != nullptr);
1232  return predLink->getState() == linkState;
1233  }
1234  }
1235 }
1236 
1237 
1238 void
1239 MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
1240  if (myApproachingVehicles.size() > 0) {
1241  od.openTag("link");
1242  od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
1243  const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
1244  od.writeAttr(SUMO_ATTR_VIA, via);
1245  od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
1246  std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
1247  for (auto it : myApproachingVehicles) {
1248  toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
1249  }
1250  std::sort(toSort.begin(), toSort.end());
1251  for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
1252  od.openTag("approaching");
1253  const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
1254  od.writeAttr(SUMO_ATTR_ID, it->second->getID());
1255  od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
1256  od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
1257  od.writeAttr("leaveTime", time2string(avi.leavingTime));
1258  od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
1259  od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
1260  od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
1261  od.writeAttr("willPass", toString(avi.willPass));
1262  od.closeTag();
1263  }
1264  od.closeTag();
1265  }
1266 }
1267 
1268 
1269 double
1271  double len = 0.;
1272  MSLane* lane = myInternalLane;
1273 
1274  while (lane != nullptr && lane->isInternal()) {
1275  len += lane->getLength();
1276  lane = lane->getLinkCont()[0]->getViaLane();
1277  }
1278  return len;
1279 }
1280 
1281 double
1283  double len = 0.;
1284  const MSLane* lane = myInternalLane;
1285 
1286  while (lane != nullptr && lane->isInternal()) {
1287  len += lane->getLength();
1288  if (lane->getIncomingLanes().size() == 1) {
1289  lane = lane->getIncomingLanes()[0].lane;
1290  } else {
1291  break;
1292  }
1293  }
1294  return len;
1295 }
1296 
1297 
1298 double
1300  MSLane* via = myInternalLane;
1301  double totalDist = 0.;
1302  bool foundCrossing = false;
1303  while (via != nullptr) {
1304  MSLink* link = via->getLinkCont()[0];
1305  double dist = link->getLengthBeforeCrossing(foeLane);
1306  if (dist != INVALID_DOUBLE) {
1307  // found conflicting lane
1308  totalDist += dist;
1309  foundCrossing = true;
1310  break;
1311  } else {
1312  totalDist += via->getLength();
1313  via = link->getViaLane();
1314  }
1315  }
1316  if (foundCrossing) {
1317  return totalDist;
1318  } else {
1319  return INVALID_DOUBLE;
1320  }
1321 }
1322 
1323 
1324 double
1326  int foe_ix;
1327  for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
1328  if (myFoeLanes[foe_ix] == foeLane) {
1329  break;
1330  }
1331  }
1332  if (foe_ix == (int)myFoeLanes.size()) {
1333  // no conflict with the given lane, indicate by returning -1
1334 #ifdef MSLink_DEBUG_CROSSING_POINTS
1335  std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
1336 #endif
1337  return INVALID_DOUBLE;
1338  } else {
1339  // found conflicting lane index
1340  double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
1341  if (dist == -10000.) {
1342  // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
1343  return INVALID_DOUBLE;
1344  }
1345 #ifdef MSLink_DEBUG_CROSSING_POINTS
1346  std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
1347  << "' at distance " << dist << " (approach along '"
1348  << myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
1349 #endif
1350  return dist;
1351  }
1352 }
1353 
1354 
1355 bool
1358  return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
1359  } else {
1360  return false;
1361  }
1362 }
1363 
1364 bool
1366  // either a non-cont entry link or the link after a cont-link
1367  return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
1368 }
1369 
1370 bool
1373  return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
1374  } else {
1375  return false;
1376  }
1377 }
1378 
1379 bool
1382  return (getInternalLaneBefore() != nullptr
1383  && myInternalLaneBefore->getIncomingLanes().size() == 1
1384  && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
1385  } else {
1386  return false;
1387  }
1388 }
1389 
1390 
1391 const MSLink*
1393  MSLane* lane = myInternalLane;
1394  const MSLink* link = this;
1395  while (lane != nullptr) {
1396  link = lane->getLinkCont()[0];
1397  lane = link->getViaLane();
1398  }
1399  return link;
1400 }
1401 
1402 
1403 const MSLink*
1405  const MSLink* link = this;
1406  while (link->myLaneBefore->isInternal()) {
1407  assert(myLaneBefore->getIncomingLanes().size() == 1);
1408  link = link->myLaneBefore->getIncomingLanes().front().viaLink;
1409  }
1410  return link;
1411 }
1412 
1413 
1414 bool
1416  return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
1417 }
1418 
1419 
1420 const MSLink::LinkLeaders
1421 MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
1422  LinkLeaders result;
1423  // this link needs to start at an internal lane (either an exit link or between two internal lanes)
1424  // or it must be queried by the pedestrian model (ego == 0)
1425  if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
1426  // ignore link leaders
1427  return result;
1428  }
1429  //gDebugFlag1 = true;
1430  if (gDebugFlag1) {
1431  std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
1432  }
1433  if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
1434  const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
1435  if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
1436  // check oncoming on bidiLane during laneChanging
1437  && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
1438  if (gDebugFlag1) {
1439  std::cout << " ignore linkLeaders beyond red light\n";
1440  }
1441  return result;
1442  }
1443  }
1444  // this is an exit link
1445  for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
1446  const MSLane* foeLane = myFoeLanes[i];
1447  const MSLink* foeExitLink = foeLane->getLinkCont()[0];
1448  // distance from the querying vehicle to the crossing point with foeLane
1449  double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
1450  const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
1451  const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
1452  const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getLogicalPredecessorLane() == foeLane->getLogicalPredecessorLane());
1453  const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
1454  const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
1455  // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
1456  const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
1458  if (gDebugFlag1) {
1459  std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
1460  << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
1461  << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
1462  << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
1463  << " cw=" << crossingWidth
1464  << " fcw=" << foeCrossingWidth
1465  << " contLane=" << contLane
1466  << " state=" << toString(myState)
1467  << " foeState=" << toString(foeExitLink->getState())
1468  << "\n";
1469  }
1470  if (distToCrossing + crossingWidth < 0 && !sameTarget
1471  && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
1472  continue; // vehicle is behind the crossing point, continue with next foe lane
1473  }
1474  bool ignoreGreenCont = false;
1475  bool foeIndirect = false;
1476  if (contLane) {
1477  const MSLink* entry = getLaneBefore()->getEntryLink();
1478  const MSLink* foeEntry = foeLane->getEntryLink();
1479  foeIndirect = foeEntry->myAmIndirect;
1480  if (entry != nullptr && entry->haveGreen()
1481  && foeEntry != nullptr && foeEntry->haveGreen()
1482  && entry->myLaneBefore != foeEntry->myLaneBefore) {
1483  // ignore vehicles before an internaljunction as long as they are still in green minor mode
1484  ignoreGreenCont = true;
1485  }
1486  }
1487  if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
1488  if (gDebugFlag1) {
1489  std::cout << " ignore:noIntersection\n";
1490  }
1491  continue;
1492  }
1493  // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
1494  // therefore we return all vehicles on the lane
1495  //
1496  // special care must be taken for continuation lanes. (next lane is also internal)
1497  // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
1498  // and should block (gap = -1) unless they are part of an indirect turn
1499  MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
1500  for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1501  MSVehicle* leader = (MSVehicle*)*it_veh;
1502  const double leaderBack = leader->getBackPositionOnLane(foeLane);
1503  const double leaderBackDist = foeDistToCrossing - leaderBack;
1504  const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
1505  const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
1506  const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
1507  const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
1508  const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
1509  && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
1510  const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
1511  const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || sameSource) && ego != nullptr;
1512  const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
1513  && enteredTheCrossingPoint
1514  && (!foeExitLink->isInternalJunctionLink() || foeIsBicycleTurn))
1515  || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
1516  const bool isOpposite = leader->getLaneChangeModel().isOpposite();
1517  const auto avi = foeExitLink->getApproaching(leader);
1518  // if leader is not found, assume that it performed a lane change in the last step
1519  const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
1520  if (gDebugFlag1) {
1521  std::cout << " candidate leader=" << leader->getID()
1522  << " cannotIgnore=" << cannotIgnore
1523  << " fdtc=" << foeDistToCrossing
1524  << " lb=" << leaderBack
1525  << " lbd=" << leaderBackDist
1526  << " fcwidth=" << foeCrossingWidth
1527  << " r=" << myRadius
1528  << " sagitta=" << sagitta
1529  << " foePastCP=" << pastTheCrossingPoint
1530  << " foeEnteredCP=" << enteredTheCrossingPoint
1531  << " inTheWay=" << inTheWay
1532  << " willPass=" << willPass
1533  << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
1534  << " ignoreGreenCont=" << ignoreGreenCont
1535  << " foeIndirect=" << foeIndirect
1536  << " foeBikeTurn=" << foeIsBicycleTurn
1537  << " isOpposite=" << isOpposite << "\n";
1538  }
1539  if (leader == ego) {
1540  continue;
1541  }
1542  // ignore greenCont foe vehicles that are not in the way
1543  if (!inTheWay && ignoreGreenCont) {
1544  if (gDebugFlag1) {
1545  std::cout << " ignoreGreenCont\n";
1546  }
1547  continue;
1548  }
1549  // after entering the conflict area, ignore foe vehicles that are not in the way
1550  if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
1551  && distToCrossing < -POSITION_EPS && !inTheWay
1552  && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
1553  if (gDebugFlag1) {
1554  std::cout << " ego entered conflict area\n";
1555  }
1556  continue;
1557  }
1559  && sameSource
1560  && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
1561  && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
1562  // ego is already on the junction and clearly ahead of foe
1563  if (gDebugFlag1) {
1564  std::cout << " ego ahead of same-source foe\n";
1565  }
1566  continue;
1567  }
1568 
1569  // ignore foe vehicles that will not pass
1570  if ((!cannotIgnore || leader->isStopped() || sameTarget)
1571  && !willPass
1572  && leader->isFrontOnLane(foeLane)
1573  && !isOpposite
1574  && !inTheWay
1575  // willPass is false if the vehicle is already on the stopping edge
1576  && !leader->willStop()) {
1577  if (gDebugFlag1) {
1578  std::cout << " foe will not pass\n";
1579  }
1580  continue;
1581  }
1582  if (leader->isBidiOn(foeLane)) {
1583  // conflict resolved via forward lane of the foe
1584  continue;
1585  }
1586  // check whether foe is blocked and might need to change before leaving the junction
1587  const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
1588  leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
1589  const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
1590 
1591  const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
1592  if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
1593  && (!foeStrategicBlocked || sameInternalEdge)) {
1594  if (ego->getLane() == leader->getLane()) {
1595  continue;
1596  }
1597  // ignore vehicles if not in conflict sublane-wise
1598  const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
1599  const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
1600  double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1601  if (foeLaneIsBidi) {
1602  // leader is oncoming
1603  posLatLeader = foeLane->getWidth() - posLatLeader;
1604  }
1605  const double latGap = (fabs(posLat - posLatLeader)
1606  - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
1607  const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
1608  if (gDebugFlag1) {
1609  std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
1610  << " sameSource=" << sameSource
1611  << " sameTarget=" << sameTarget
1612  << " foeLaneIsBidi=" << foeLaneIsBidi
1613  << " foeLane=" << foeLane->getID()
1614  << " leader=" << leader->getID()
1615  << " egoLane=" << ego->getLane()->getID()
1616  << " leaderLane=" << leader->getLane()->getID()
1617  << " egoLat=" << posLat
1618  << " egoLatOffset=" << egoLatOffset
1619  << " leaderLat=" << posLatLeader
1620  << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1621  << " latGap=" << latGap
1622  << " maneuverDist=" << maneuverDist
1623  << " computeLC=" << MSGlobals::gComputeLC
1624  << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
1625  << "\n";
1626  }
1627  if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
1628  // do not perform sublane changes that interfere with the leader vehicle
1629  && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
1630  const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
1631  if (sameSource) {
1632  // for lanes from the same edge, higer index implies a
1633  // connection further to the left
1634  const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
1635  if ((posLat > posLatLeader) == leaderFromRight) {
1636  // ignore speed since lanes diverge
1637  if (gDebugFlag1) {
1638  std::cout << " ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
1639  }
1640  continue;
1641  }
1642  } else if (sameTarget) {
1643  // for lanes from different edges we cannot rely on the
1644  // index due to wrap-around issues
1645  if (myDirection != foeEntryLink->getDirection()) {
1646  bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
1647  // leader vehicle should not move towards ego
1648  if (MSGlobals::gLefthand) {
1649  leaderFromRight = !leaderFromRight;
1650  }
1651  if ((posLat > posLatLeader) == leaderFromRight
1652  // leader should keep lateral position or move away from ego
1653  && (leader->getLaneChangeModel().getSpeedLat() == 0
1654  || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
1655  && (ego->getLaneChangeModel().getSpeedLat() == 0
1656  || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > latGap))) {
1657  if (gDebugFlag1) {
1658  std::cout << " ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
1659  }
1660  continue;
1661  }
1662  } else {
1663  // XXX figure out relative direction somehow
1664  }
1665  } else {
1666  if (gDebugFlag1) {
1667  std::cout << " ignored oncoming bidi leader\n";
1668  }
1669  continue;
1670  }
1671  }
1672  }
1674  // compute distance between vehicles on the the superimposition of both lanes
1675  // where the crossing point is the common point
1676  double gap;
1677  bool fromLeft = true;
1678  if (ego == nullptr) {
1679  // request from pedestrian model. return distance between leaderBack and crossing point
1680  //std::cout << " foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
1681  gap = leaderBackDist;
1682  // distToCrossing should not take into account the with of the foe lane
1683  // (which was subtracted in setRequestInformation)
1684  // Instead, the width of the foe vehicle is used directly by the caller.
1685  distToCrossing += myConflicts[i].conflictSize / 2;
1686  if (gap + foeCrossingWidth < 0) {
1687  // leader is completely past the crossing point
1688  // or there is no crossing point
1689  continue; // next vehicle
1690  }
1691  // we need to determine whether the vehicle passes the
1692  // crossing from the left or the right (heuristic)
1693  fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
1694  } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
1695  gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
1696  } else {
1697  if (pastTheCrossingPoint && !sameTarget) {
1698  // leader is completely past the crossing point
1699  // or there is no crossing point
1700  if (gDebugFlag1) {
1701  std::cout << " foePastCP ignored\n";
1702  }
1703  continue;
1704  }
1705  double leaderBackDist2 = leaderBackDist;
1706  if (sameTarget && leaderBackDist2 < 0) {
1707  const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
1708  if (mismatch > 0) {
1709  leaderBackDist2 += mismatch;
1710  }
1711  }
1712  if (gDebugFlag1) {
1713  std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
1714  << " backDist=" << leaderBackDist
1715  << " backDist2=" << leaderBackDist2
1716  << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
1717  << "\n";
1718  }
1719  gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
1720  }
1721  // if the foe is already moving off the intersection, we may
1722  // advance up to the crossing point unless we have the same target or same source
1723  // (for sameSource, the crossing point indicates the point of divergence)
1724  const bool stopAsap = leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource);
1725  if (gDebugFlag1) {
1726  std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
1727  }
1728  if (ignoreFoe(ego, leader)) {
1729  continue;
1730  }
1731  const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
1732  (inTheWay ? LL_IN_THE_WAY : 0) |
1733  (sameSource ? LL_SAME_SOURCE : 0) |
1734  (sameTarget ? LL_SAME_TARGET : 0));
1735  result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
1736  }
1737 
1738  }
1739  if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
1740  // check for crossing pedestrians (keep driving if already on top of the crossing
1741  const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
1742  const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
1744  // @check lefthand?!
1745  const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
1746  const double vehSideOffset = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5 - vehWidth * 0.5
1747  + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
1748  // can access the movement model here since we already checked for existing persons above
1749  if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehSideOffset, vehWidth,
1751  collectBlockers)) {
1752  result.emplace_back(nullptr, -1, distToPeds);
1753  } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
1754  const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
1755  if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
1756  // a person might step on the crossing at any moment, since ego
1757  // is already on the junction, the opened() check is not done anymore
1758  const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
1759  for (const auto& item : (*crossingLink->myApproachingPersons)) {
1760  if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
1761  if (gDebugFlag1) {
1762  std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
1763  //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1764  << "\n";
1765  }
1766  result.emplace_back(nullptr, -1, distToPeds);
1767  break;
1768  //} else {
1769  // if (gDebugFlag1) {
1770  // std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
1771  // << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1772  // << "\n";
1773  // }
1774  }
1775  }
1776  }
1777  }
1778  }
1779  }
1780 
1781  //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
1782  if (ego != nullptr) {
1783  checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
1784  checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
1785  }
1786 
1787  if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
1788  // check for foes on the same edge
1789  for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
1790  const MSLane* foeLane = *it;
1791  MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
1792  for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1793  MSVehicle* leader = (MSVehicle*)*it_veh;
1794  if (leader == ego) {
1795  continue;
1796  }
1797  if (leader->getLane()->isNormal()) {
1798  // leader is past the conflict point
1799  continue;
1800  }
1801  const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
1802  const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane);
1803  if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
1804  // ego is ahead of leader
1805  continue;
1806  }
1807  const double posLat = ego->getLateralPositionOnLane();
1808  const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1809  if (gDebugFlag1) {
1810  std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
1811  << " foeLane=" << foeLane->getID()
1812  << " leader=" << leader->getID()
1813  << " egoLane=" << ego->getLane()->getID()
1814  << " leaderLane=" << leader->getLane()->getID()
1815  << " gap=" << gap
1816  << " egoLat=" << posLat
1817  << " leaderLat=" << posLatLeader
1818  << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1819  << " egoIndex=" << myInternalLaneBefore->getIndex()
1820  << " foeIndex=" << foeLane->getIndex()
1821  << " dist=" << dist
1822  << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
1823  << "\n";
1824  }
1825  // there only is a conflict if the paths cross
1826  if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
1827  || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
1828  if (gDebugFlag1) {
1829  std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
1830  }
1831  if (ignoreFoe(ego, leader)) {
1832  continue;
1833  }
1834  result.emplace_back(leader, gap, -1);
1835  }
1836  }
1837  }
1838  }
1839  return result;
1840 }
1841 
1842 
1843 void
1844 MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
1845  if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
1846  // pedestrians may be on an arbitrary path across this
1847  // walkingarea. make sure to keep enough distance.
1848  // This is a simple but conservative solution that could be improved
1849  // by ignoring pedestrians that are "obviously" not on a collision course
1850  double distToPeds = std::numeric_limits<double>::max();
1851  assert(myInternalLaneBefore != nullptr);
1853  if (ego->getLateralPositionOnLane() != 0) {
1854  egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
1855  }
1856  for (MSTransportable* t : foeLane->getEdge().getPersons()) {
1857  MSPerson* p = static_cast<MSPerson*>(t);
1858  double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
1859  const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
1860  if (inFront) {
1861  dist -= ego->getVehicleType().getMinGap();
1862  }
1863 #ifdef DEBUG_WALKINGAREA
1864  if (ego->isSelected()) {
1865  std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
1866  << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
1867  << " futurePedPos=" << getFuturePosition(p)
1868  << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
1869  << " inFront=" << inFront
1870  << " dist=" << dist << "\n";
1871  }
1872 #endif
1873  if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
1874  if (inFront) {
1875  const double oncomingFactor = isOnComingPed(ego, p);
1876  if (oncomingFactor > 0) {
1877  // account for pedestrian movement while closing in
1878  const double timeToStop = sqrt(dist) / 2;
1879  const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
1880  dist = MAX2(0.0, dist - pedDist);
1881 #ifdef DEBUG_WALKINGAREA
1882  if (ego->isSelected()) {
1883  std::cout << " timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
1884  }
1885 #endif
1886  }
1887  }
1888  if (ignoreFoe(ego, p)) {
1889  continue;
1890  }
1891  distToPeds = MIN2(distToPeds, dist);
1892  if (collectBlockers != nullptr) {
1893  collectBlockers->push_back(p);
1894  }
1895  }
1896  }
1897  if (distToPeds != std::numeric_limits<double>::max()) {
1898  // leave extra space in front
1899  result.emplace_back(nullptr, -1, distToPeds);
1900  }
1901  }
1902 }
1903 
1904 bool
1905 MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
1906  const double pedAngle = ego->getPosition().angleTo2D(pPos);
1907  const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
1908 #ifdef DEBUG_WALKINGAREA
1909  if (ego->isSelected()) {
1910  std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
1911  }
1912 #endif
1913  if (angleDiff < DEG2RAD(75)) {
1914  return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
1915  }
1916  return false;
1917 }
1918 
1919 
1920 double
1921 MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
1922  const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
1923  const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
1924 #ifdef DEBUG_WALKINGAREA
1925  if (ego->isSelected()) {
1926  std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
1927  }
1928 #endif
1929  if (angleDiff <= DEG2RAD(90)) {
1930  ;
1931  return cos(angleDiff);
1932  } else {
1933  return 0;
1934  }
1935 }
1936 
1937 
1938 Position
1939 MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
1940  const double a = p->getAngle();
1941  const double dist = timeHorizon * p->getMaxSpeed();
1942 
1943  const Position offset(cos(a) * dist, sin(a) * dist);
1944  return p->getPosition() + offset;
1945 }
1946 
1947 
1948 MSLink*
1949 MSLink::getParallelLink(int direction) const {
1950  if (direction == -1) {
1951  return myParallelRight;
1952  } else if (direction == 1) {
1953  return myParallelLeft;
1954  } else {
1955  assert(false || myLane->getOpposite() != nullptr);
1956  return nullptr;
1957  }
1958 }
1959 
1960 MSLink*
1962  if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
1963  for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
1964  if (cand->getLane() == myLaneBefore->getOpposite()) {
1965  return cand;
1966  }
1967  }
1968  }
1969  return nullptr;
1970 }
1971 
1972 
1973 MSLink*
1975  const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
1976  const MSLane* const after = getLane()->getParallelLane(direction, false);
1977  if (before != nullptr && after != nullptr) {
1978  for (MSLink* const link : before->getLinkCont()) {
1979  if (link->getLane() == after) {
1980  return link;
1981  }
1982  }
1983  }
1984  return nullptr;
1985 }
1986 
1987 
1988 double
1989 MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
1990  SUMOTime arrivalTime,
1991  const BlockingFoes* foes) const {
1992  if (myFoeLinks.size() == 0) {
1993  // link should have LINKSTATE_MAJOR in this case
1994  assert(false);
1995  return vSafe;
1996  } else if (myFoeLinks.size() > 1) {
1997  throw ProcessError("Zipper junctions with more than two conflicting lanes are not supported (at junction '"
1998  + myJunction->getID() + "')");
1999  }
2000  const double brakeGap = ego->getCarFollowModel().brakeGap(ego->getSpeed(), ego->getCarFollowModel().getMaxDecel(), TS);
2001  if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
2002 #ifdef DEBUG_ZIPPER
2004  DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2005  << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
2006 #endif
2007  return vSafe;
2008  }
2009 #ifdef DEBUG_ZIPPER
2010  DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2011  << " egoAT=" << arrivalTime
2012  << " dist=" << dist
2013  << " brakeGap=" << brakeGap
2014  << " vSafe=" << vSafe
2015  << " numFoes=" << foes->size()
2016  << "\n")
2017 #endif
2018  MSLink* foeLink = myFoeLinks[0];
2019  for (const auto& item : *foes) {
2020  if (!item->isVehicle()) {
2021  continue;
2022  }
2023  const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
2024  assert(foe != 0);
2025  const ApproachingVehicleInformation& avi = foeLink->getApproaching(foe);
2026  const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
2027  STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
2028 
2029  if ( // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
2030  ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
2031  // also ignore vehicles that are behind us and are able to brake for us
2032  couldBrakeForLeader(foeDist, dist, foe, ego) ||
2033  // resolve ties by lane index
2034  (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
2035 #ifdef DEBUG_ZIPPER
2036  if (DEBUG_COND_ZIPPER) std::cout
2037  << " ignoring foe=" << foe->getID()
2038  << " foeAT=" << avi.arrivalTime
2039  << " foeDist=" << avi.dist
2040  << " foeDist2=" << foeDist
2041  << " foeSpeed=" << avi.speed
2042  << " egoSpeed=" << ego->getSpeed()
2043  << " deltaDist=" << foeDist - dist
2044  << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
2045  << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
2046  << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
2047  << "\n";
2048 #endif
2049  continue;
2050  }
2051  // the idea behind speed adaption is three-fold:
2052  // 1) ego needs to be in a car-following relationship with foe eventually
2053  // thus, the ego speed should be equal to the follow speed once the foe enters
2054  // the zipper junction
2055  // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
2056  // achieving this distance can be spread over time but computing
2057  // safeGap is subject to estimation errors of future speeds
2058  // 3) deceleration can be spread out over the time until true
2059  // car-following happens, at the start of speed adaptions, smaller
2060  // decelerations should be sufficient
2061 
2062  // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
2063  // lets try to extrapolate
2064  const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
2065  const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
2066  const double uEnd = MIN2(uMax, uAccel);
2067  const double uAvg = (avi.speed + uEnd) / 2;
2068  const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
2069  const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
2070 
2071  const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
2072  const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
2073  const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxDecel());
2074  const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
2075  const double vAvg = (ego->getSpeed() + vEnd) / 2;
2076  const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
2077  const double te = MAX2(1.0, ceil((te0) / TS) * TS);
2078 
2079  const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
2080  const double safeGap = ego->getCarFollowModel().getSecureGap(ego, foe, vEnd, uEnd, foe->getCarFollowModel().getMaxDecel());
2081  // round t to next step size
2082  // increase gap to safeGap by the time foe reaches link
2083  // gap + u*t - (t * v + a * t^2 / 2) = safeGap
2084  const double deltaGap = gap + tf * uAvg - safeGap - vAvg * tf;
2085  const double a = 2 * deltaGap / (tf * tf);
2086  const double vSafeGap = ego->getSpeed() + ACCEL2SPEED(a);
2087  const double vFollow = ego->getCarFollowModel().followSpeed(
2088  ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
2089 
2090  // scale behavior based on ego time to link (te)
2091  const double w = MIN2(1.0, te / 10);
2092  const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
2093  const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), w * vSafeGap + (1 - w) * vFollow);
2094 
2095  vSafe = MIN2(vSafe, vZipper);
2096 #ifdef DEBUG_ZIPPER
2097  if (DEBUG_COND_ZIPPER) std::cout << " adapting to foe=" << foe->getID()
2098  << " foeDist=" << foeDist
2099  << " foeSpeed=" << avi.speed
2100  << " foeAS=" << avi.arrivalSpeed
2101  << " egoSpeed=" << ego->getSpeed()
2102  << " uMax=" << uMax
2103  << " uAccel=" << uAccel
2104  << " uEnd=" << uEnd
2105  << " uAvg=" << uAvg
2106  << " gap=" << gap
2107  << " safeGap=" << safeGap
2108  << "\n "
2109  << " tf=" << tf
2110  << " te=" << te
2111  << " dg=" << deltaGap
2112  << " aSafeGap=" << a
2113  << " vMax=" << vMax
2114  << " vAccel=" << vAccel
2115  << " vDecel=" << vDecel
2116  << " vEnd=" << vEnd
2117  << " vSafeGap=" << vSafeGap
2118  << " vFollow=" << vFollow
2119  << " w=" << w
2120  << " maxDecel=" << maxDecel
2121  << " vZipper=" << vZipper
2122  << " vSafe=" << vSafe
2123  << "\n";
2124 #endif
2125  }
2126  return vSafe;
2127 }
2128 
2129 
2130 bool
2131 MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
2132  return (// leader is ahead of follower
2133  followDist > leaderDist &&
2134  // and follower could brake for 1 s to stay behind leader
2135  followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
2136 }
2137 
2138 
2139 void
2143 }
2144 
2145 bool
2147  // check whether this link gets to keep its cont status switching the tls off
2148  // @note: this could also be pre-computed in netconvert
2149  // we check whether there is any major link from this edge
2150  for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
2151  for (const MSLink* link : cand->getLinkCont()) {
2152  if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
2153  return true;
2154  }
2155  }
2156  }
2157  return false;
2158 }
2159 
2160 bool
2161 MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
2162  return fabs(posLat2 - posLat) < (width + width2) / 2;
2163 }
2164 
2165 std::string
2167  return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
2168 }
2169 
2170 
2171 bool
2173  if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
2174  return false;
2175  }
2176  const SUMOVehicleParameter& param = ego->getParameter();
2177  for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
2178  if (typeID == foe->getVehicleType().getID()) {
2179  return true;
2180  }
2181  }
2182  for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
2183  if (id == foe->getID()) {
2184  return true;
2185  }
2186  }
2187  return false;
2188 }
2189 
2190 
2191 void
2194 }
2195 
2196 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define RAD2DEG(x)
Definition: GeomHelper.h:36
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
SUMOTime DELTA_T
Definition: SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition: SUMOTime.h:55
#define SIMSTEP
Definition: SUMOTime.h:61
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:51
#define SUMOTime_MAX
Definition: SUMOTime.h:34
#define SUMOTime_MIN
Definition: SUMOTime.h:35
#define TS
Definition: SUMOTime.h:42
#define SIMTIME
Definition: SUMOTime.h:62
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
const SVCPermissions SVCAll
all VClasses are allowed
@ SVC_BICYCLE
vehicle is a bicycle
const int VEHPARS_JUNCTIONMODEL_PARAMS_SET
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_ALLWAY_STOP
This is an uncontrolled, all-way stop link.
@ LINKSTATE_STOP
This is an uncontrolled, minor link, has to stop.
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_ZIPPER
This is an uncontrolled, zipper-merge link.
@ LINKSTATE_TL_OFF_BLINKING
The link is controlled by a tls which is off and blinks, has to brake.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
@ LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
@ SUMO_ATTR_JM_IGNORE_FOE_SPEED
@ SUMO_ATTR_JM_STOPLINE_CROSSING_GAP
@ SUMO_ATTR_JM_STOPSIGN_WAIT
@ SUMO_ATTR_VIA
@ SUMO_ATTR_JM_IGNORE_IDS
@ SUMO_ATTR_JM_IGNORE_TYPES
@ SUMO_ATTR_JM_ALLWAYSTOP_WAIT
@ SUMO_ATTR_JM_IGNORE_FOE_PROB
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_JM_CROSSING_GAP
@ SUMO_ATTR_IMPATIENCE
@ SUMO_ATTR_ID
@ SUMO_ATTR_JM_TIMEGAP_MINOR
bool gDebugFlag6
Definition: StdDefs.cpp:42
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:37
const double INVALID_DOUBLE
invalid double
Definition: StdDefs.h:64
T MIN3(T a, T b, T c)
Definition: StdDefs.h:89
T MIN2(T a, T b)
Definition: StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition: StdDefs.h:58
T MAX2(T a, T b)
Definition: StdDefs.h:82
T MAX3(T a, T b, T c)
Definition: StdDefs.h:96
#define DEBUGOUT(cond, msg)
Definition: StdDefs.h:141
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:191
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:178
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:172
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model)
double getSpeedLat() const
return the lateral speed of the current lane change maneuver
virtual bool isSelected() const
whether this vehicle is selected in the GUI
double getLength() const
Returns the vehicle's length.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
bool isStopped() const
Returns whether the vehicle is at a stop.
double estimateSpeedAfterDistance(const double dist, const double v, const double accel) const
Definition: MSCFModel.cpp:765
double getEmergencyDecel() const
Get the vehicle type's maximal phisically possible deceleration [m/s^2].
Definition: MSCFModel.h:272
virtual double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
Definition: MSCFModel.cpp:166
double getMaxAccel() const
Get the vehicle type's maximum acceleration [m/s^2].
Definition: MSCFModel.h:256
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition: MSCFModel.h:380
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:264
virtual double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0, const CalcReason usage=CalcReason::CURRENT) const =0
Computes the vehicle's follow speed (no dawdling)
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition: MSEdge.h:204
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
const MSJunction * getFromJunction() const
Definition: MSEdge.h:414
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:268
const MSJunction * getToJunction() const
Definition: MSEdge.h:418
static bool gUseMesoSim
Definition: MSGlobals.h:103
static double gLateralResolution
Definition: MSGlobals.h:97
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition: MSGlobals.h:137
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition: MSGlobals.h:171
static SUMOTime gIgnoreJunctionBlocker
Definition: MSGlobals.h:82
static bool gSublane
whether sublane simulation is enabled (sublane model or continuous lanechanging)
Definition: MSGlobals.h:162
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:78
The base class for an intersection.
Definition: MSJunction.h:58
AnyVehicleIterator is a structure, which manages the iteration through all vehicles on the lane,...
Definition: MSLane.h:129
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:716
MSLane * getParallelLane(int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to this one or 0 if it does not exist.
Definition: MSLane.cpp:2754
const MSLane * getNormalSuccessorLane() const
get normal lane following this internal lane, for normal lanes, the lane itself is returned
Definition: MSLane.cpp:3151
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction
Definition: MSLane.h:487
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition: MSLane.cpp:2672
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition: MSLane.cpp:2649
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition: MSLane.h:566
int getIndex() const
Returns the lane's index.
Definition: MSLane.h:634
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:942
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:3116
bool isNormal() const
Definition: MSLane.cpp:2532
bool isCrossing() const
Definition: MSLane.cpp:2538
bool isInternal() const
Definition: MSLane.cpp:2526
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:756
double interpolateGeometryPosToLanePos(double geometryPos) const
Definition: MSLane.h:558
AnyVehicleIterator anyVehiclesBegin() const
begin iterator for iterating over all vehicles touching this lane in downstream direction
Definition: MSLane.h:481
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition: MSLane.cpp:4280
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:4545
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition: MSLane.cpp:3141
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:627
virtual const PositionVector & getShape(bool) const
Definition: MSLane.h:294
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:184
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
bool hasPersons() const
Returns whether persons are simulated.
Definition: MSNet.h:395
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:1182
virtual bool blockedAtDist(const SUMOTrafficObject *ego, 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
Definition: MSPModel.h:98
static const double SAFETY_GAP
Definition: MSPModel.h:59
The parent class for traffic light logics.
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
virtual double getAngle() const
return the current angle of the transportable
const MSVehicleType & getVehicleType() const
Returns the object's "vehicle" type.
Position getPosition(const double) const
Return current position (x/y, cartesian)
double getMaxSpeed() const
Returns the maximum speed (the minimum of desired and physical maximum speed)
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
bool willStop() const
Returns whether the vehicle will stop on the current edge.
Definition: MSVehicle.cpp:1574
SUMOTime getLastActionTime() const
Returns the time of the vehicle's last action point.
Definition: MSVehicle.h:544
bool isActive() const
Returns whether the current simulation step is an action point for the vehicle.
Definition: MSVehicle.h:631
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition: MSVehicle.h:673
bool isFrontOnLane(const MSLane *lane) const
Returns the information whether the front of the vehicle is on the given lane.
Definition: MSVehicle.cpp:5073
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5774
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
Definition: MSVehicle.cpp:1244
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition: MSVehicle.h:401
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
Definition: MSVehicle.cpp:6768
bool isBidiOn(const MSLane *lane) const
whether this vehicle is driving against lane
Definition: MSVehicle.cpp:7064
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition: MSVehicle.h:416
double getSpeed() const
Returns the vehicle's current speed.
Definition: MSVehicle.h:493
bool ignoreRed(const MSLink *link, bool canBrake) const
decide whether a red (or yellow light) may be ignored
Definition: MSVehicle.cpp:7329
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:584
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition: MSVehicle.h:977
double getAngle() const
Returns the vehicle's direction in radians.
Definition: MSVehicle.h:734
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
double getMinGap() const
Get the free space in front of vehicles of this class.
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:91
double getLength() const
Get vehicle's length [m].
const MSCFModel & getCarFollowModel() const
Returns the vehicle type's car following model definition (const version)
const SUMOVTypeParameter & getParameter() const
const std::string & getID() const
Returns the id.
Definition: Named.h:74
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:276
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition: Position.h:286
A list of positions.
double length2D() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
std::vector< double > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
PositionVector reverse() const
reverse position vector
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
Representation of a vehicle, person, or container.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual SumoRNG * getRNG() const =0
Returns the associated RNG for this object.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual bool isSelected() const =0
whether this object is selected in the GUI
double getJMParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.
Representation of a vehicle.
Definition: SUMOVehicle.h:62
virtual double getLateralPositionOnLane() const =0
Get the vehicle's lateral position on the lane.
virtual SUMOTime getLastActionTime() const =0
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
Structure representing possible vehicle parameter.
bool wasSet(int what) const
Returns whether the given parameter was set.
Definition: json.hpp:4471