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