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.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
18 // A connnection between lanes
19 /****************************************************************************/
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include <iostream>
27 #include <algorithm>
28 #include <limits>
31 #include "MSNet.h"
32 #include "MSJunction.h"
33 #include "MSLink.h"
34 #include "MSLane.h"
36 #include "MSEdge.h"
37 #include "MSGlobals.h"
38 #include "MSVehicle.h"
41 
42 //#define MSLink_DEBUG_CROSSING_POINTS
43 //#define MSLink_DEBUG_OPENED
44 //#define DEBUG_APPROACHING
45 //#define DEBUG_ZIPPER
46 //#define DEBUG_COND (myLane->getID()=="43[0]_0" && myLaneBefore->getID()==":33_0_0")
47 //#define DEBUG_COND (myLane->getID()=="end_0")
48 //#define DEBUG_COND (true)
49 //#define DEBUG_COND_ZIPPER (gDebugFlag1)
50 //#define DEBUG_COND_ZIPPER (true)
51 #define DEBUG_COND_ZIPPER (ego->isSelected())
52 
53 // ===========================================================================
54 // static member variables
55 // ===========================================================================
57 // additional caution is needed when approaching a zipper link
59 
60 const double MSLink::ZIPPER_ADAPT_DIST(100);
61 
62 // time to link in seconds below which adaptation should take place
63 #define ZIPPER_ADAPT_TIME 10
64 // the default safety gap when passing before oncoming pedestrians
65 #define JM_CROSSING_GAP_DEFAULT 10
66 
67 // minimim width between sibling lanes to qualify as non-overlapping
68 #define DIVERGENCE_MIN_WIDTH 2.5
69 
70 // ===========================================================================
71 // member method definitions
72 // ===========================================================================
73 MSLink::MSLink(MSLane* predLane, MSLane* succLane, MSLane* via, LinkDirection dir, LinkState state, double length, double foeVisibilityDistance, bool keepClear, MSTrafficLightLogic* logic, int tlIndex) :
74  myLane(succLane),
75  myLaneBefore(predLane),
76  myIndex(-1),
77  myTLIndex(tlIndex),
78  myLogic(logic),
79  myState(state),
80  myOffState(state),
81  myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
82  myDirection(dir),
83  myLength(length),
84  myFoeVisibilityDistance(foeVisibilityDistance),
85  myHasFoes(false),
86  myAmCont(false),
87  myAmContOff(false),
88  myKeepClear(keepClear),
89  myInternalLane(via),
90  myInternalLaneBefore(nullptr),
91  myMesoTLSPenalty(0),
92  myGreenFraction(1),
93  myLateralShift(0),
94  myWalkingAreaFoe(nullptr),
95  myWalkingAreaFoeExit(nullptr),
96  myHavePedestrianCrossingFoe(false),
97  myParallelRight(nullptr),
98  myParallelLeft(nullptr),
99  myJunction(nullptr) {
100 
102  // detect lateral shift from lane geometries
103  //std::cout << "DEBUG link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " hasInternal=" << MSNet::getInstance()->hasInternalLinks() << " shapeBefore=" << myLaneBefore->getShape().back() << " shapeFront=" << getViaLaneOrLane()->getShape().front() << "\n";
104  if ((myInternalLane != nullptr || predLane->isInternal())
105  && myLaneBefore->getShape().back() != getViaLaneOrLane()->getShape().front()) {
107  const PositionVector& to = getViaLaneOrLane()->getShape();
108  const double dist = from.back().distanceTo2D(to.front());
109  // figure out direction of shift
110  try {
111  from.move2side(dist);
112  } catch (InvalidArgument&) {
113  }
114  myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
115  //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
116  }
117  }
118 }
119 
120 
122 
123 
124 void
126  const std::vector<MSLink*>& foeLinks,
127  const std::vector<MSLane*>& foeLanes,
128  MSLane* internalLaneBefore) {
129 //#ifdef MSLink_DEBUG_CROSSING_POINTS
130 // std::cout << " setRequestInformation() for junction " << getViaLaneOrLane()->getEdge().getFromJunction()->getID()
131 // << "\nInternalLanes = " << toString(getViaLaneOrLane()->getEdge().getFromJunction()->getInternalLanes())
132 // << std::endl;
133 //#endif
134  myIndex = index;
135  myHasFoes = hasFoes;
136  myAmCont = isCont;
137  myFoeLinks = foeLinks;
138  for (std::vector<MSLane*>::const_iterator it_lane = foeLanes.begin(); it_lane != foeLanes.end(); ++it_lane) {
139  // cannot assign vector due to const-ness
140  myFoeLanes.push_back(*it_lane);
141  }
142  myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
143  myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
144  myInternalLaneBefore = internalLaneBefore;
145  MSLane* lane = nullptr;
146  if (internalLaneBefore != nullptr) {
147  // this is an exit link. compute crossing points with all foeLanes
148  lane = internalLaneBefore;
149  //} else if (myLane->getEdge().isCrossing()) {
150  // // this is the link to a pedestrian crossing. compute crossing points with all foeLanes
151  // // @note not currently used by pedestrians
152  // lane = myLane;
153  }
154 #ifdef MSLink_DEBUG_CROSSING_POINTS
155  std::cout << " link " << myIndex << " to " << getViaLaneOrLane()->getID() << " internalLaneBefore=" << (lane == 0 ? "NULL" : lane->getID()) << " has foes: " << toString(foeLanes) << "\n";
156 #endif
157  if (lane != nullptr) {
158  const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
159  if (lane->getIncomingLanes().size() != 1) {
160  throw ProcessError("Internal lane '" + lane->getID() + "' has " + toString(lane->getIncomingLanes().size()) + " predecessors");
161  }
162  // compute crossing points
163  for (std::vector<const MSLane*>::const_iterator it_lane = myFoeLanes.begin(); it_lane != myFoeLanes.end(); ++it_lane) {
164  myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || (*it_lane)->getEdge().isCrossing();
165  const bool sameTarget = myLane == (*it_lane)->getLinkCont()[0]->getLane();
166  if (sameTarget && !beforeInternalJunction && !contIntersect(lane, *it_lane)) {
167  //if (myLane == (*it_lane)->getLinkCont()[0]->getLane()) {
168  // this foeLane has the same target and merges at the end (lane exits the junction)
169  myLengthsBehindCrossing.push_back(std::make_pair(0, 0)); // dummy value, never used
170 #ifdef MSLink_DEBUG_CROSSING_POINTS
171  std::cout
172  << " " << lane->getID()
173  << " merges with " << (*it_lane)->getID()
174  << " nextLane " << lane->getLinkCont()[0]->getViaLaneOrLane()->getID()
175  << " dist1=" << myLengthsBehindCrossing.back().first
176  << " dist2=" << myLengthsBehindCrossing.back().second
177  << "\n";
178 #endif
179  } else {
180  std::vector<double> intersections1 = lane->getShape().intersectsAtLengths2D((*it_lane)->getShape());
181 #ifdef MSLink_DEBUG_CROSSING_POINTS
182 // std::cout << " intersections1=" << toString(intersections1) << "\n";
183 #endif
184  bool haveIntersection = true;
185  if (intersections1.size() == 0) {
186  intersections1.push_back(-10000.0); // disregard this foe (using maxdouble leads to nasty problems down the line)
187  haveIntersection = false;
188  } else if (intersections1.size() > 1) {
189  std::sort(intersections1.begin(), intersections1.end());
190  }
191  std::vector<double> intersections2 = (*it_lane)->getShape().intersectsAtLengths2D(lane->getShape());
192 #ifdef MSLink_DEBUG_CROSSING_POINTS
193  //std::cout << " intersections2=" << toString(intersections2) << "\n";
194 #endif
195  if (intersections2.size() == 0) {
196  intersections2.push_back(0);
197  } else if (intersections2.size() > 1) {
198  std::sort(intersections2.begin(), intersections2.end());
199  }
200  if (haveIntersection) {
201  // lane width affects the crossing point
202  intersections1.back() -= (*it_lane)->getWidth() / 2;
203  intersections2.back() -= lane->getWidth() / 2;
204  // ensure negative offset for weird geometries
205  intersections1.back() = MAX2(0.0, intersections1.back());
206  intersections2.back() = MAX2(0.0, intersections2.back());
207 
208  // also length/geometry factor. (XXX: Why subtract width/2 *before* converting geometric position to lane pos? refs #3031)
209  intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
210  intersections2.back() = (*it_lane)->interpolateGeometryPosToLanePos(intersections2.back());
211 
212  if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !(*it_lane)->getEdge().isCrossing()) {
213  // wait at the internal junction
214  // (except for foes that are crossings since there is no internal junction)
215  intersections1.back() = 0;
216  }
217  }
218 
219  myLengthsBehindCrossing.push_back(std::make_pair(
220  lane->getLength() - intersections1.back(),
221  (*it_lane)->getLength() - intersections2.back()));
222 
223 #ifdef MSLink_DEBUG_CROSSING_POINTS
224  std::cout
225  << " intersection of " << lane->getID()
226  << " totalLength=" << lane->getLength()
227  << " with " << (*it_lane)->getID()
228  << " totalLength=" << (*it_lane)->getLength()
229  << " dist1=" << myLengthsBehindCrossing.back().first
230  << " dist2=" << myLengthsBehindCrossing.back().second
231  << "\n";
232 #endif
233  }
234  }
235  // check for overlap with internal lanes from the same source lane
236  const MSLane* pred = lane->getLogicalPredecessorLane();
237  // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
238  // we add all other internal lanes from pred as foeLanes
239  for (const MSLink* const it : pred->getLinkCont()) {
240  const MSLane* sibling = it->getViaLane();
241  if (sibling != lane && sibling != nullptr) {
242  const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
243  const PositionVector& l = lane->getShape();
244  const PositionVector& s = sibling->getShape();
245  if (l.front().distanceTo2D(s.front()) >= minDist) {
246  // account for lateral shift by the entry links
247  continue;
248  }
249  double lbcSibling = 0;
250  double lbcLane = 0;
251  if (l.back().distanceTo2D(s.back()) > minDist) {
252  // compute the final divergence point
253  // this position serves two purposes:
254  // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
255  // 2) both vehicles are put into a cf-relationship while before the point.
256  // Since the actual crossing point is at the start of the junction,
257  // we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
258  std::vector<double> distances = l.distances(s);
259 #ifdef MSLink_DEBUG_CROSSING_POINTS
260  std::cout << " distances=" << toString(distances) << "\n";
261 #endif
262  assert(distances.size() == l.size() + s.size());
263  if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
264  // do a pairwise check between lane and sibling to make because we do not know which of them bends more
265  for (int j = (int)s.size() - 2; j >= 0; j--) {
266  const int i = j + (int)l.size();
267  const double segLength = s[j].distanceTo2D(s[j + 1]);
268  if (distances[i] > minDist) {
269  lbcSibling += segLength;
270  } else {
271  // assume no sharp bends and just interpolate the last segment
272  lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
273  break;
274  }
275  }
276  for (int i = (int)l.size() - 2; i >= 0; i--) {
277  const double segLength = l[i].distanceTo2D(l[i + 1]);
278  if (distances[i] > minDist) {
279  lbcLane += segLength;
280  } else {
281  // assume no sharp bends and just interpolate the last segment
282  lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
283  break;
284  }
285  }
286  }
287  assert(lbcSibling >= -NUMERICAL_EPS);
288  assert(lbcLane >= -NUMERICAL_EPS);
289  }
290  const double distToDivergence1 = sibling->getLength() - lbcSibling;
291  const double distToDivergence2 = lane->getLength() - lbcLane;
292  const double distToDivergence = MIN3(
293  MAX2(distToDivergence1, distToDivergence2),
294  sibling->getLength(), lane->getLength());
295  lbcLane = MAX2(0.0, lane->getLength() - distToDivergence);
296  lbcLane = lane->interpolateGeometryPosToLanePos(lbcLane);
297  lbcSibling = MAX2(0.0, sibling->getLength() - distToDivergence);
298  lbcSibling = lane->interpolateGeometryPosToLanePos(lbcSibling);
299  myLengthsBehindCrossing.push_back(std::make_pair(lbcLane, lbcSibling));
300  myFoeLanes.push_back(sibling);
301 #ifdef MSLink_DEBUG_CROSSING_POINTS
302  std::cout << " distToDivergence=" << distToDivergence
303  << " distTD1=" << distToDivergence1
304  << " distTD2=" << distToDivergence2
305  << " length=" << lane->getLength()
306  << " sibLength=" << sibling->getLength()
307  << "\n";
308  std::cout << " adding same-origin foe" << sibling->getID()
309  << " dist1=" << myLengthsBehindCrossing.back().first
310  << " dist2=" << myLengthsBehindCrossing.back().second
311  << "\n";
312 #endif
313  }
314  }
315  }
317  // check for links with the same origin lane and the same destination edge
318  const MSEdge* myTarget = &myLane->getEdge();
319  // save foes for entry links
320  for (MSLink* const it : myLaneBefore->getLinkCont()) {
321  const MSEdge* target = &(it->getLane()->getEdge());
322  if (it == this) {
323  continue;
324  }
325  if (target == myTarget) {
326  mySublaneFoeLinks.push_back(it);
327 #ifdef MSLink_DEBUG_CROSSING_POINTS
328  std::cout << " sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
329 #endif
330  } else if (myDirection != LINKDIR_STRAIGHT && it->getDirection() == LINKDIR_STRAIGHT) {
331  // potential turn conflicht
332  mySublaneFoeLinks2.push_back(it);
333 #ifdef MSLink_DEBUG_CROSSING_POINTS
334  std::cout << " sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
335 #endif
336  }
337  }
338  // save foes for exit links
339  if (fromInternalLane()) {
340  //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
341  const MSLinkCont& predLinks2 = myLaneBefore->getIncomingLanes().front().lane->getLinkCont();
342  for (MSLinkCont::const_iterator it = predLinks2.begin(); it != predLinks2.end(); ++it) {
343  const MSEdge* target = &((*it)->getLane()->getEdge());
344  if ((*it)->getViaLane() != myInternalLaneBefore && target == myTarget) {
345  //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
346  mySublaneFoeLanes.push_back((*it)->getViaLane());
347  }
348  }
349  }
350  }
351 }
352 
353 
354 bool
355 MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
356  if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
357  std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
358  return intersections.size() > 0;
359  }
360  return false;
361 }
362 
363 
364 void
365 MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
366  const bool setRequest, const SUMOTime arrivalTimeBraking, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist) {
367  const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
368 #ifdef DEBUG_APPROACHING
369  if (DEBUG_COND) {
370  std::cout << SIMTIME << " Link ''" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
371  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
372  std::cout << "'" << i->first->getID() << "'" << std::endl;
373  }
374  }
375 #endif
376  myApproachingVehicles.emplace(approaching,
377  ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
378  arrivalTimeBraking, arrivalSpeedBraking, waitingTime, dist));
379 }
380 
381 
382 void
384 
385 #ifdef DEBUG_APPROACHING
386  if (DEBUG_COND) {
387  std::cout << SIMTIME << " Link ''" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
388  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
389  std::cout << "'" << i->first->getID() << "'" << std::endl;
390  }
391  }
392 #endif
393  myApproachingVehicles.emplace(approaching, ai);
394 }
395 
396 
397 void
399  myBlockedFoeLinks.insert(link);
400 }
401 
402 
403 
404 bool
406  for (std::set<MSLink*>::const_iterator i = myBlockedFoeLinks.begin(); i != myBlockedFoeLinks.end(); ++i) {
407  if ((*i)->isBlockingAnyone()) {
408  return true;
409  }
410  }
411  return false;
412 }
413 
414 
415 void
417 
418 #ifdef DEBUG_APPROACHING
419  if (DEBUG_COND) {
420  std::cout << SIMTIME << " Link ''" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
421  std::cout << "' Removing approaching vehicle '" << veh->getID() << "'\nCurrently registered vehicles:" << std::endl;
422  for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
423  std::cout << "'" << i->first->getID() << "'" << std::endl;
424  }
425  }
426 #endif
427  myApproachingVehicles.erase(veh);
428 }
429 
430 
433  auto i = myApproachingVehicles.find(veh);
434  if (i != myApproachingVehicles.end()) {
435  return i->second;
436  } else {
437  return ApproachingVehicleInformation(-1000, -1000, 0, 0, false, -1000, 0, 0, 0);
438  }
439 }
440 
441 
442 SUMOTime
443 MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
444  const double leaveSpeed, const double vehicleLength) const {
445  return arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
446 }
447 
448 
449 bool
450 MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
451  double impatience, double decel, SUMOTime waitingTime, double posLat,
452  std::vector<const SUMOVehicle*>* collectFoes, bool ignoreRed, const SUMOVehicle* ego) const {
453  if (haveRed() && !ignoreRed) {
454  return false;
455  }
457  return true;
458  }
459  const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
461  // check for foes on the same lane with the same target edge
462  for (const MSLink* foeLink : mySublaneFoeLinks) {
463  assert(myLane != foeLink->getLane());
464  for (auto& it : foeLink->myApproachingVehicles) {
465  const SUMOVehicle* foe = it.first;
466  if (
467  // there only is a conflict if the paths cross
468  ((posLat < foe->getLateralPositionOnLane() && myLane->getIndex() > foeLink->myLane->getIndex())
469  || (posLat > foe->getLateralPositionOnLane() && myLane->getIndex() < foeLink->myLane->getIndex()))
470  // the vehicle that arrives later must yield
471  && (arrivalTime > it.second.arrivalTime
472  // if both vehicles arrive at the same time, the one
473  // to the left must yield
474  || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
475  if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
476  impatience, decel, waitingTime, ego)) {
477 #ifdef MSLink_DEBUG_OPENED
478  if (gDebugFlag1) {
479  std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
480  }
481 #endif
482  if (collectFoes == nullptr) {
483 #ifdef MSLink_DEBUG_OPENED
484  if (gDebugFlag1) {
485  std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
486  }
487 #endif
488  return false;
489  } else {
490  collectFoes->push_back(foe);
491  }
492  }
493  }
494  }
495  }
496  // check for foes on the same lane with a different target edge
497  // (straight movers take precedence if the paths cross)
498  const int lhSign = MSNet::getInstance()->lefthand() ? -1 : 1;
499  for (const MSLink* foeLink : mySublaneFoeLinks2) {
500  assert(myDirection != LINKDIR_STRAIGHT);
501  for (auto& it : foeLink->myApproachingVehicles) {
502  const SUMOVehicle* foe = it.first;
503  // there only is a conflict if the paths cross
505  && (posLat * lhSign > foe->getLateralPositionOnLane() * lhSign))
507  && (posLat * lhSign < foe->getLateralPositionOnLane() * lhSign))) {
508  if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
509  impatience, decel, waitingTime, ego)) {
510 #ifdef MSLink_DEBUG_OPENED
511  if (gDebugFlag1) {
512  std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
513  }
514 #endif
515  if (collectFoes == nullptr) {
516  return false;
517  } else {
518  collectFoes->push_back(foe);
519  }
520  }
521  }
522  }
523  }
524  }
525  if (havePriority() && myState != LINKSTATE_ZIPPER) {
526  // priority usually means the link is open but there are exceptions:
527  // zipper still needs to collect foes
528  // sublane model could have detected a conflict
529  return collectFoes == nullptr || collectFoes->size() == 0;
530  }
531  if ((myState == LINKSTATE_STOP || myState == LINKSTATE_ALLWAY_STOP) && waitingTime == 0) {
532  return false;
533  }
534 
535 #ifdef MSLink_DEBUG_OPENED
536  if (gDebugFlag1) {
537  std::cout << SIMTIME << " opened link=" << getViaLaneOrLane()->getID() << " foeLinks=" << myFoeLinks.size() << "\n";
538  }
539 #endif
540 
541  for (std::vector<MSLink*>::const_iterator i = myFoeLinks.begin(); i != myFoeLinks.end(); ++i) {
543  if ((*i)->haveRed()) {
544  continue;
545  }
546  }
547 #ifdef MSLink_DEBUG_OPENED
548  if (gDebugFlag1) {
549  std::cout << " foeLink=" << (*i)->getViaLaneOrLane()->getID() << " numApproaching=" << (*i)->getApproaching().size() << "\n";
550  }
551 #endif
552  if ((*i)->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == (*i)->getLane(),
553  impatience, decel, waitingTime, collectFoes, ego)) {
554  return false;
555  }
556  }
557  if (collectFoes != nullptr && collectFoes->size() > 0) {
558  return false;
559  }
560  return true;
561 }
562 
563 
564 bool
565 MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
566  bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
567  std::vector<const SUMOVehicle*>* collectFoes, const SUMOVehicle* ego) const {
568  for (auto it : myApproachingVehicles) {
569 #ifdef MSLink_DEBUG_OPENED
570  if (gDebugFlag1) {
571  if (ego != 0
572  && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.first->getSpeed()
574  std::cout << " foe link=" << getViaLaneOrLane()->getID()
575  << " foeVeh=" << it.first->getID() << " (below ignore speed)"
576  << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
577  << "\n";
578  }
579  }
580 #endif
581  if (it.first != ego
582  && (ego == nullptr
584  || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
586  && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
587  impatience, decel, waitingTime, ego)) {
588  if (collectFoes == nullptr) {
589  return true;
590  } else {
591  collectFoes->push_back(it.first);
592  }
593  }
594  }
595  return false;
596 }
597 
598 
599 bool
601  SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
602  bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
603  const SUMOVehicle* ego) const {
604 #ifdef MSLink_DEBUG_OPENED
605  if (gDebugFlag1) {
606  std::cout << " foe link=" << getViaLaneOrLane()->getID()
607  << " foeVeh=" << veh->getID()
608  << " req=" << avi.willPass
609  << " aT=" << avi.arrivalTime
610  << " lT=" << avi.leavingTime
611  << "\n";
612  }
613 #endif
614  if (!avi.willPass) {
615  return false;
616  }
618  assert(waitingTime > 0);
619  if (waitingTime > avi.waitingTime) {
620  return false;
621  }
622  if (waitingTime == avi.waitingTime && arrivalTime < avi.arrivalTime) {
623  return false;
624  }
625  }
626  const SUMOTime foeArrivalTime = (SUMOTime)((1.0 - impatience) * avi.arrivalTime + impatience * avi.arrivalTimeBraking);
627  const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
629  : (ego == nullptr
632  //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
633 #ifdef MSLink_DEBUG_OPENED
634  if (gDebugFlag1) {
635  std::cout << " imp=" << impatience << " fATb=" << avi.arrivalTimeBraking << " fAT2=" << foeArrivalTime << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << "\n";
636  }
637 #endif
638  if (avi.leavingTime < arrivalTime) {
639  // ego wants to be follower
640  if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
641  || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
642  veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
643 #ifdef MSLink_DEBUG_OPENED
644  if (gDebugFlag1) {
645  std::cout << " blocked (cannot follow)\n";
646  }
647 #endif
648  return true;
649  }
650  } else if (foeArrivalTime > leaveTime + lookAhead) {
651  // ego wants to be leader.
652  if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, avi.arrivalSpeedBraking,
653  decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
654 #ifdef MSLink_DEBUG_OPENED
655  if (gDebugFlag1) {
656  std::cout << " blocked (cannot lead)\n";
657  }
658 #endif
659  return true;
660  }
661  } else {
662  // even without considering safeHeadwayTime there is already a conflict
663 #ifdef MSLink_DEBUG_OPENED
664  if (gDebugFlag1) {
665  std::cout << " blocked (hard conflict)\n";
666  }
667 #endif
668  return true;
669  }
670  return false;
671 }
672 
673 
674 bool
676  MSVehicle* veh = lane->getLastAnyVehicle();
677  double distLeft = 0;
678  if (veh == nullptr) {
679  return false;
680  } else {
681  distLeft = lane->getLength() - veh->getBackPositionOnLane(lane);
682  assert(distLeft > 0);
683  // can we be sure that the vehicle leaves this lane in the next step?
684  bool result = distLeft > (veh->getSpeed() - veh->getCarFollowModel().getMaxDecel());
685  return result;
686  }
687 }
688 
689 
690 bool
691 MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
692  for (std::vector<MSLink*>::const_iterator i = myFoeLinks.begin(); i != myFoeLinks.end(); ++i) {
693  if ((*i)->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == (*i)->getLane(), 0, decel, 0)) {
694  return true;
695  }
696  }
697  for (std::vector<const MSLane*>::const_iterator i = myFoeLanes.begin(); i != myFoeLanes.end(); ++i) {
698  if ((*i)->getVehicleNumberWithPartials() > 0) {
699  return true;
700  }
701  }
702  return false;
703 }
704 
705 
708  return myDirection;
709 }
710 
711 
712 void
714  if (myState != state) {
715  myLastStateChange = t;
716  }
717  myState = state;
718 }
719 
720 
721 MSLane*
723  return myLane;
724 }
725 
726 
727 bool
728 MSLink::isCont() const {
729  // when a traffic light is switched off minor roads have their cont status revoked
731 }
732 
733 
734 bool
736  if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
737  return false;
738  } else {
740  if (!pred->getEdge().isInternal()) {
741  return false;
742  } else {
743  MSLane* pred2 = pred->getLogicalPredecessorLane();
744  assert(pred2 != 0);
745  MSLink* predLink = MSLinkContHelper::getConnectingLink(*pred2, *pred);
746  assert(predLink != 0);
747  return predLink->havePriority() || predLink->haveYellow();
748  }
749  }
750 }
751 
752 
753 void
754 MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
755  if (myApproachingVehicles.size() > 0) {
756  od.openTag("link");
757  od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
758  const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
759  od.writeAttr(SUMO_ATTR_VIA, via);
760  od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
761  std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
762  for (auto it : myApproachingVehicles) {
763  toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
764  }
765  std::sort(toSort.begin(), toSort.end());
766  for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
767  od.openTag("approaching");
768  const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
769  od.writeAttr(SUMO_ATTR_ID, it->second->getID());
770  od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
771  od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
772  od.writeAttr("arrivalTimeBraking", time2string(avi.arrivalTimeBraking));
773  od.writeAttr("leaveTime", time2string(avi.leavingTime));
774  od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
775  od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
776  od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
777  od.writeAttr("willPass", toString(avi.willPass));
778  od.closeTag();
779  }
780  od.closeTag();
781  }
782 }
783 
784 
785 double
787  double len = 0.;
788  MSLane* lane = myInternalLane;
789 
790  while (lane != nullptr && lane->isInternal()) {
791  len += lane->getLength();
792  lane = lane->getLinkCont()[0]->getViaLane();
793  }
794  return len;
795 }
796 
797 double
799  double len = 0.;
800  const MSLane* lane = myInternalLane;
801 
802  while (lane != nullptr && lane->isInternal()) {
803  len += lane->getLength();
804  if (lane->getIncomingLanes().size() == 1) {
805  lane = lane->getIncomingLanes()[0].lane;
806  } else {
807  break;
808  }
809  }
810  return len;
811 }
812 
813 
814 double
816  MSLane* via = myInternalLane;
817  double totalDist = 0.;
818  bool foundCrossing = false;
819  while (via != nullptr) {
820  MSLink* link = via->getLinkCont()[0];
821  double dist = link->getLengthBeforeCrossing(foeLane);
822  if (dist != INVALID_DOUBLE) {
823  // found conflicting lane
824  totalDist += dist;
825  foundCrossing = true;
826  break;
827  } else {
828  totalDist += via->getLength();
829  via = link->getViaLane();
830  }
831  }
832  if (foundCrossing) {
833  return totalDist;
834  } else {
835  return INVALID_DOUBLE;
836  }
837 }
838 
839 
840 double
842  int foe_ix;
843  for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
844  if (myFoeLanes[foe_ix] == foeLane) {
845  break;
846  }
847  }
848  if (foe_ix == (int)myFoeLanes.size()) {
849  // no conflict with the given lane, indicate by returning -1
850 #ifdef MSLink_DEBUG_CROSSING_POINTS
851  std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
852 #endif
853  return INVALID_DOUBLE;
854  } else {
855  // found conflicting lane index
856  double dist = myInternalLaneBefore->getLength() - myLengthsBehindCrossing[foe_ix].first;
857  if (dist == -10000.) {
858  // this is the value in myLengthsBehindCrossing, if the relation allows intersection but none is present for the actual geometry.
859  return INVALID_DOUBLE;
860  }
861 #ifdef MSLink_DEBUG_CROSSING_POINTS
862  std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
863  << "' at distance " << dist << " (approach along '"
864  << myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
865 #endif
866  return dist;
867  }
868 }
869 
870 
871 MSLane*
873  return myInternalLane;
874 }
875 
876 
877 bool
880  return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
881  } else {
882  return false;
883  }
884 }
885 
886 bool
888  // either a non-cont entry link or the link after a cont-link
889  return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
890 }
891 
892 bool
895  return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
896  } else {
897  return false;
898  }
899 }
900 
901 bool
904  return (getInternalLaneBefore() != nullptr
905  && myInternalLaneBefore->getIncomingLanes().size() == 1
906  && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
907  } else {
908  return false;
909  }
910 }
911 
912 
913 MSLink*
915  MSLane* lane = myInternalLane;
916  MSLink* link = nullptr;
917  while (lane != nullptr) {
918  link = lane->getLinkCont()[0];
919  lane = link->getViaLane();
920  }
921  return link;
922 }
923 
924 
925 bool
927  return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
928 }
929 
930 bool
932  return myInternalLaneBefore != nullptr;
933 }
934 
936 MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
937  LinkLeaders result;
938  if (ego != nullptr && ego->getLaneChangeModel().isOpposite()) {
939  // ignore link leaders
940  return result;
941  }
942  //gDebugFlag1 = true;
943  // this link needs to start at an internal lane (either an exit link or between two internal lanes)
944  // or it must be queried by the pedestrian model (ego == 0)
945  if (fromInternalLane() || ego == nullptr) {
946  if (gDebugFlag1) {
947  std::cout << SIMTIME << " getLeaderInfo link=" << getViaLaneOrLane()->getID() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
948  }
949  // this is an exit link
950  for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
951  const MSLane* foeLane = myFoeLanes[i];
952  // distance from the querying vehicle to the crossing point with foeLane
953  double distToCrossing = dist - myLengthsBehindCrossing[i].first;
954  const bool sameTarget = (myLane == foeLane->getLinkCont()[0]->getLane()) && !isInternalJunctionLink();
955  const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getLogicalPredecessorLane() == foeLane->getLogicalPredecessorLane());
956  const double crossingWidth = (sameTarget || sameSource) ? 0 : foeLane->getWidth();
957  const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myInternalLaneBefore->getWidth();
958  if (gDebugFlag1) {
959  std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
960  << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
961  << " lbc=" << myLengthsBehindCrossing[i].first
962  << " flbc=" << myLengthsBehindCrossing[i].second
963  << "\n";
964  }
965  // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
966  const bool contLane = (foeLane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal() && !(
968  if (distToCrossing + crossingWidth < 0
969  && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
970  continue; // vehicle is behind the crossing point, continue with next foe lane
971  }
972  const double foeDistToCrossing = foeLane->getLength() - myLengthsBehindCrossing[i].second;
973  // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
974  // therefore we return all vehicles on the lane
975  //
976  // special care must be taken for continuation lanes. (next lane is also internal)
977  // vehicles on these lanes should always block (gap = -1)
978  // vehicles on cont. lanes or on internal lanes with the same target as this link can never be ignored
980  for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
981  MSVehicle* leader = (MSVehicle*)*it_veh;
982  const double leaderBack = leader->getBackPositionOnLane(foeLane);
983  const double leaderBackDist = foeDistToCrossing - leaderBack;
984  const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth < 0;
985  const bool ignoreIndirectBicycleTurn = (pastTheCrossingPoint
986  && leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
987  && foeLane->getIncomingLanes().front().viaLink->getDirection() == LINKDIR_LEFT);
988  const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || sameSource) && ego != nullptr;
989  const bool inTheWay = !pastTheCrossingPoint && leaderBackDist < leader->getVehicleType().getLength();
990  const bool isOpposite = leader->getLaneChangeModel().isOpposite();
991  if (gDebugFlag1) {
992  std::cout << " candiate leader=" << leader->getID()
993  << " cannotIgnore=" << cannotIgnore
994  << " fdtc=" << foeDistToCrossing
995  << " lb=" << leaderBack
996  << " lbd=" << leaderBackDist
997  << " fcwidth=" << foeCrossingWidth
998  << " foePastCP=" << pastTheCrossingPoint
999  << " inTheWay=" << inTheWay
1000  << " willPass=" << foeLane->getLinkCont()[0]->getApproaching(leader).willPass
1001  << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
1002  << " isOpposite=" << isOpposite << "\n";
1003  }
1004  if (leader == ego) {
1005  continue;
1006  }
1007  // after entering the conflict area, ignore foe vehicles that are not in the way
1008  if (distToCrossing < -POSITION_EPS && !inTheWay
1009  && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
1010  continue;
1011  }
1012  // ignore foe vehicles that will not pass
1013  if ((!cannotIgnore || leader->isStopped() || sameTarget)
1014  && !foeLane->getLinkCont()[0]->getApproaching(leader).willPass
1015  && leader->isFrontOnLane(foeLane)
1016  && !isOpposite
1017  && !inTheWay
1018  // willPass is false if the vehicle is already on the stopping edge
1019  && !leader->willStop()) {
1020  continue;
1021  }
1022  if (cannotIgnore || inTheWay || leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
1023  // compute distance between vehicles on the the superimposition of both lanes
1024  // where the crossing point is the common point
1025  double gap;
1026  bool fromLeft = true;
1027  if (ego == nullptr) {
1028  // request from pedestrian model. return distance between leaderBack and crossing point
1029  //std::cout << " foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myLengthsBehindCrossing[i].second << " dist=" << dist << " behind=" << myLengthsBehindCrossing[i].first << "\n";
1030  gap = leaderBackDist;
1031  // distToCrossing should not take into account the with of the foe lane
1032  // (which was subtracted in setRequestInformation)
1033  // Instead, the width of the foe vehicle is used directly by the caller.
1034  distToCrossing += foeLane->getWidth() / 2;
1035  if (gap + foeCrossingWidth < 0) {
1036  // leader is completely past the crossing point
1037  // or there is no crossing point
1038  continue; // next vehicle
1039  }
1040  // we need to determine whether the vehicle passes the
1041  // crossing from the left or the right (heuristic)
1042  fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
1043  } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
1044  gap = -1; // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
1045  } else {
1046  if (gDebugFlag1) {
1047  std::cout << " distToCrossing=" << distToCrossing << " leader back=" << leaderBack << " backDist=" << leaderBackDist
1048  << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
1049  //<< " stateRight=" << toString((LaneChangeAction)leader->getLaneChangeModel().getSavedState(-1).second)
1050  << "\n";
1051  }
1052  if (leaderBackDist + foeCrossingWidth < 0) {
1053  // leader is completely past the crossing point
1054  // or there is no crossing point
1055  continue; // next vehicle
1056  }
1057  gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist - foeCrossingWidth;
1058  if (gap < leader->getVehicleType().getLength() && leader->getLaneChangeModel().isStrategicBlocked()) {
1059  // do not encroach on leader when it tries to change lanes
1060  gap = -1;
1061  }
1062  }
1063  // if the foe is already moving off the intersection, we may
1064  // advance up to the crossing point unless we have the same target or same source
1065  // (for sameSource, the crossing point indicates the point of divergence)
1066  const bool stopAsap = leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource);
1067  if (gDebugFlag1) {
1068  std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << "\n";
1069  }
1070  result.push_back(LinkLeader(leader, gap, stopAsap ? -1 : distToCrossing, fromLeft));
1071  }
1072 
1073  }
1074  if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
1075  // check for crossing pedestrians (keep driving if already on top of the crossing
1076  const double distToPeds = distToCrossing - MSPModel::SAFETY_GAP;
1077  const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
1079  // @check lefthand?!
1080  const bool wayIn = myLengthsBehindCrossing[i].first < myLaneBefore->getLength() * 0.5;
1081  const double vehSideOffset = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5 - vehWidth * 0.5
1082  + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
1083  if (distToPeds >= -MSPModel::SAFETY_GAP && MSPModel::getModel()->blockedAtDist(foeLane, vehSideOffset, vehWidth,
1085  collectBlockers)) {
1086  result.push_back(LinkLeader((MSVehicle*)nullptr, -1, distToPeds));
1087  }
1088  }
1089  }
1090 
1091  //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
1092  if (ego != nullptr) {
1093  checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
1094  checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
1095  }
1096 
1097  if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
1098  // check for foes on the same lane
1099  for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
1100  const MSLane* foeLane = *it;
1101  MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
1102  for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1103  MSVehicle* leader = (MSVehicle*)*it_veh;
1104  if (leader == ego) {
1105  continue;
1106  }
1107  const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
1108  const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane);
1109  if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
1110  // ego is ahead of leader
1111  continue;
1112  }
1113 
1114  const double posLat = ego->getLateralPositionOnLane();
1115  const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1116  if (gDebugFlag1) {
1117  std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
1118  << " foeLane=" << foeLane->getID()
1119  << " leader=" << leader->getID()
1120  << " egoLane=" << ego->getLane()->getID()
1121  << " leaderLane=" << leader->getLane()->getID()
1122  << " egoLat=" << posLat
1123  << " leaderLat=" << posLatLeader
1124  << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1125  << " egoIndex=" << myInternalLaneBefore->getIndex()
1126  << " foeIndex=" << foeLane->getIndex()
1127  << " dist=" << dist
1128  << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
1129  << "\n";
1130  }
1131  // there only is a conflict if the paths cross
1132  if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
1133  || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
1134  if (gDebugFlag1) {
1135  std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
1136  }
1137  result.push_back(LinkLeader(leader, gap, -1));
1138  }
1139  }
1140  }
1141  }
1142  }
1143  return result;
1144 }
1145 
1146 
1147 void
1148 MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
1149  if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
1150  // pedestrians may be on an arbitrary path across this
1151  // walkingarea. make sure to keep enough distance.
1152  // This is a simple but conservative solution that could be improved
1153  // by ignoring pedestrians that are "obviously" not on a collision course
1154  double distToPeds = std::numeric_limits<double>::max();
1155  for (MSTransportable* t : foeLane->getEdge().getPersons()) {
1156  MSPerson* p = static_cast<MSPerson*>(t);
1157  const double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
1158  if (p->getSpeed() > 0 || dist < MSPModel::SAFETY_GAP / 2) {
1159  distToPeds = MIN2(distToPeds, dist - MSPModel::SAFETY_GAP);
1160  if (collectBlockers != nullptr) {
1161  collectBlockers->push_back(p);
1162  }
1163  }
1164  }
1165  if (distToPeds != std::numeric_limits<double>::max()) {
1166  result.push_back(LinkLeader((MSVehicle*)nullptr, -1, distToPeds));
1167  }
1168  }
1169 }
1170 
1171 
1172 MSLane*
1174  if (myInternalLane != nullptr) {
1175  return myInternalLane;
1176  }
1177  return myLane;
1178 }
1179 
1180 
1181 const MSLane*
1183  if (myInternalLaneBefore != nullptr) {
1185  throw ProcessError("lane before mismatch!");
1186  }
1187  }
1188  return myLaneBefore;
1189 }
1190 
1191 
1192 MSLink*
1193 MSLink::getParallelLink(int direction) const {
1194  if (direction == -1) {
1195  return myParallelRight;
1196  } else if (direction == 1) {
1197  return myParallelLeft;
1198  } else {
1199  assert(false);
1200  return nullptr;
1201  }
1202 }
1203 
1204 
1205 MSLink*
1207  MSLane* before = getLaneBefore()->getParallelLane(direction);
1208  MSLane* after = getLane()->getParallelLane(direction);
1209  if (before != nullptr && after != nullptr) {
1210  return MSLinkContHelper::getConnectingLink(*before, *after);
1211  } else {
1212  return nullptr;
1213  }
1214 }
1215 
1216 
1217 const MSLane*
1219  return myInternalLaneBefore;
1220 }
1221 
1222 
1223 double
1224 MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
1225  SUMOTime arrivalTime,
1226  std::vector<const SUMOVehicle*>* collectFoes) const {
1227  if (myFoeLinks.size() == 0) {
1228  // link should have LINKSTATE_MAJOR in this case
1229  assert(false);
1230  return vSafe;
1231  } else if (myFoeLinks.size() > 1) {
1232  throw ProcessError("Zipper junctions with more than two conflicting lanes are not supported (at junction '"
1233  + myJunction->getID() + "')");
1234  }
1236  const double secondsToArrival = STEPS2TIME(arrivalTime - now);
1237  if (secondsToArrival > ZIPPER_ADAPT_TIME && dist > ZIPPER_ADAPT_DIST) {
1238 #ifdef DEBUG_ZIPPER
1239  if (DEBUG_COND_ZIPPER) std::cout << SIMTIME << " getZipperSpeed ego=" << ego->getID()
1240  << " dist=" << dist << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n";
1241 #endif
1242  return vSafe;
1243  }
1244 #ifdef DEBUG_ZIPPER
1245  if (DEBUG_COND_ZIPPER) std::cout << SIMTIME << " getZipperSpeed ego=" << ego->getID()
1246  << " egoAT=" << arrivalTime
1247  << " dist=" << dist
1248  << " vSafe=" << vSafe
1249  << " numFoes=" << collectFoes->size()
1250  << "\n";
1251 #endif
1252  MSLink* foeLink = myFoeLinks[0];
1253  for (std::vector<const SUMOVehicle*>::const_iterator i = collectFoes->begin(); i != collectFoes->end(); ++i) {
1254  const MSVehicle* foe = dynamic_cast<const MSVehicle*>(*i);
1255  assert(foe != 0);
1256  const ApproachingVehicleInformation& avi = foeLink->getApproaching(foe);
1257  const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
1258  STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * foe->getSpeed()));
1259 
1260  if ( // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
1261  ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
1262  // also ignore vehicles that are behind us and are able to brake for us
1263  couldBrakeForLeader(foeDist, dist, foe, ego) ||
1264  // resolve ties by lane index
1265  (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
1266 #ifdef DEBUG_ZIPPER
1267  if (DEBUG_COND_ZIPPER) std::cout
1268  << " ignoring foe=" << foe->getID()
1269  << " foeAT=" << avi.arrivalTime
1270  << " foeDist=" << avi.dist
1271  << " foeDist2=" << foeDist
1272  << " foeSpeed=" << foe->getSpeed()
1273  << " egoSpeed=" << ego->getSpeed()
1274  << " deltaDist=" << foeDist - dist
1275  << " delteSpeed=" << foe->getSpeed() - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
1276  << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
1277  << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
1278  << "\n";
1279 #endif
1280  continue;
1281  }
1282  // the idea behind speed adaption is three-fold:
1283  // 1) ego needs to be in a car-following relationship with foe eventually
1284  // thus, the ego speed should be equal to the follow speed once the foe enters
1285  // the zipper junction
1286  // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
1287  // achieving this distance can be spread over time but computing
1288  // safeGap is subject to estimation errors of future speeds
1289  // 3) deceleration can be spread out over the time until true
1290  // car-following happens, at the start of speed adaptions, smaller
1291  // decelerations should be sufficient
1292 
1293  // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
1294  // lets try to extrapolate
1295  const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
1296  const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, foe->getSpeed(), foe->getCarFollowModel().getMaxAccel());
1297  const double uEnd = MIN2(uMax, uAccel);
1298  const double uAvg = (foe->getSpeed() + uEnd) / 2;
1299  const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
1300  const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
1301 
1302  const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
1303  const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
1304  const double vEnd = MIN3(vMax, vAccel, uEnd);
1305  const double vAvg = (ego->getSpeed() + vEnd) / 2;
1306  const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
1307  const double te = MAX2(1.0, ceil((te0) / TS) * TS);
1308 
1309  const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
1310  const double safeGap = ego->getCarFollowModel().getSecureGap(vEnd, uEnd, foe->getCarFollowModel().getMaxDecel());
1311  // round t to next step size
1312  // increase gap to safeGap by the time foe reaches link
1313  // gap + u*t - (t * v + a * t^2 / 2) = safeGap
1314  const double deltaGap = gap + tf * uAvg - safeGap - vAvg * tf;
1315  const double a = 2 * deltaGap / (tf * tf);
1316  const double vSafeGap = ego->getSpeed() + ACCEL2SPEED(a);
1317  const double vFollow = ego->getCarFollowModel().followSpeed(
1318  ego, ego->getSpeed(), gap, foe->getSpeed(), foe->getCarFollowModel().getMaxDecel(), foe);
1319 
1320  // scale behavior based on ego time to link (te)
1321  const double w = MIN2(1.0, te / 10);
1322  const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
1323  const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), w * vSafeGap + (1 - w) * vFollow);
1324 
1325  vSafe = MIN2(vSafe, vZipper);
1326 #ifdef DEBUG_ZIPPER
1327  if (DEBUG_COND_ZIPPER) std::cout << " adapting to foe=" << foe->getID()
1328  << " foeDist=" << foeDist
1329  << " foeSpeed=" << foe->getSpeed()
1330  << " foeAS=" << avi.arrivalSpeed
1331  << " egoSpeed=" << ego->getSpeed()
1332  << " uMax=" << uMax
1333  << " uAccel=" << uAccel
1334  << " uEnd=" << uEnd
1335  << " uAvg=" << uAvg
1336  << " gap=" << gap
1337  << " safeGap=" << safeGap
1338  << "\n "
1339  << " tf=" << tf
1340  << " te=" << te
1341  << " dg=" << deltaGap
1342  << " aSafeGap=" << a
1343  << " vMax=" << vMax
1344  << " vAccel=" << vAccel
1345  << " vEnd=" << vEnd
1346  << " vSafeGap=" << vSafeGap
1347  << " vFollow=" << vFollow
1348  << " w=" << w
1349  << " maxDecel=" << maxDecel
1350  << " vZipper=" << vZipper
1351  << " vSafe=" << vSafe
1352  << "\n";
1353 #endif
1354  }
1355  return vSafe;
1356 }
1357 
1358 
1359 bool
1360 MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
1361  return (// leader is ahead of follower
1362  followDist > leaderDist &&
1363  // and follower could brake for 1 s to stay behind leader
1364  followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
1365 }
1366 
1367 
1368 void
1372 }
1373 
1374 bool
1376  // check whether this link gets to keep its cont status switching the tls off
1377  // @note: this could also be pre-computed in netconvert
1378  // we check whether there is any major link from this edge
1379  for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
1380  for (const MSLink* link : cand->getLinkCont()) {
1381  if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
1382  return true;
1383  }
1384  }
1385  }
1386  return false;
1387 }
1388 
1389 std::string
1391  return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
1392 }
1393 
1394 /****************************************************************************/
1395 
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:819
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:33
The link is a partial left direction.
static double gLateralResolution
Definition: MSGlobals.h:85
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:2532
double getLength() const
Returns the vehicle&#39;s length.
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:670
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:80
long long int SUMOTime
Definition: SUMOTime.h:35
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.
SUMOTime getWaitingTime() const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition: MSVehicle.h:625
virtual const MSVehicleType & getVehicleType() const =0
Returns the vehicle&#39;s type.
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:53
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:561
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:244
This is an uncontrolled, minor link, has to stop.
The base class for an intersection.
Definition: MSJunction.h:61
vehicle is a bicycle
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition: MSGlobals.h:121
static double rand(std::mt19937 *rng=0)
Returns a random real number in [0, 1)
Definition: RandHelper.h:60
AnyVehicleIterator is a structure, which manages the iteration through all vehicles on the lane...
Definition: MSLane.h:110
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:165
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
T MAX2(T a, T b)
Definition: StdDefs.h:80
SUMOTime getLastActionTime() const
Returns the time of the vehicle&#39;s last action point.
Definition: MSVehicle.h:521
double getLength() const
Returns the lane&#39;s length.
Definition: MSLane.h:541
const PositionVector & getShape() const
Returns this lane&#39;s shape.
Definition: MSLane.h:478
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
Definition: MSVehicle.cpp:1280
const std::string & getID() const
Returns the id.
Definition: Named.h:77
#define TIME2STEPS(x)
Definition: SUMOTime.h:59
virtual double getSpeed() const
the current speed of the transportable
#define TS
Definition: SUMOTime.h:44
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
The link is controlled by a tls which is off, not blinking, may pass.
This is an uncontrolled, all-way stop link.
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:2187
double getWidth() const
Returns the lane&#39;s width.
Definition: MSLane.h:557
T MAX3(T a, T b, T c)
Definition: StdDefs.h:94
This is an uncontrolled, zipper-merge link.
The link is a (hard) left direction.
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:4609
#define SIMTIME
Definition: SUMOTime.h:64
bool isFrontOnLane(const MSLane *lane) const
Returns the information whether the front of the vehicle is on the given lane.
Definition: MSVehicle.cpp:4082
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
The link is a straight direction.
double getMaxAccel() const
Get the vehicle type&#39;s maximum acceleration [m/s^2].
Definition: MSCFModel.h:210
bool willStop() const
Returns whether the vehicle will stop on the current edge.
Definition: MSVehicle.cpp:1757
bool isInternal() const
Definition: MSLane.cpp:1999
#define SUMOTime_MIN
Definition: SUMOTime.h:37
A road/street connecting two junctions.
Definition: MSEdge.h:76
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:5294
const MSCFModel & getCarFollowModel() const
Returns the vehicle&#39;s car following model definition.
Definition: MSVehicle.h:894
int getIndex() const
Returns the lane&#39;s index.
Definition: MSLane.h:564
virtual std::mt19937 * getRNG() const =0
Returns the associated RNG for this vehicle.
MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else 0.
Definition: MSLane.cpp:2127
const MSCFModel & getCarFollowModel() const
Returns the vehicle type&#39;s car following model definition (const version)
virtual bool blockedAtDist(const MSLane *lane, double vehSide, double vehWidth, double oncomingGap, std::vector< const MSPerson *> *collectBlockers)
whether a pedestrian is blocking the crossing of lane for the given vehicle bondaries ...
Definition: MSPModel.h:74
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
virtual double getSecureGap(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.h:328
Representation of a vehicle.
Definition: SUMOVehicle.h:61
static MSPModel * getModel()
Definition: MSPModel.cpp:59
double interpolateGeometryPosToLanePos(double geometryPos) const
Definition: MSLane.h:511
A list of positions.
double getEmergencyDecel() const
Get the vehicle type&#39;s maximal phisically possible deceleration [m/s^2].
Definition: MSCFModel.h:226
const std::set< MSTransportable * > & getPersons() const
Returns this edge&#39;s persons set.
Definition: MSEdge.h:174
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount
#define STEPS2TIME(x)
Definition: SUMOTime.h:57
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic, in MSLink and GNEInternalLane.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:284
T MIN2(T a, T b)
Definition: StdDefs.h:74
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction ...
Definition: MSLane.h:440
The link is a (hard) right direction.
#define POSITION_EPS
Definition: config.h:169
AnyVehicleIterator anyVehiclesBegin() const
begin iterator for iterating over all vehicles touching this lane in downstream direction ...
Definition: MSLane.h:434
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 ...
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:69
double getMinGap() const
Get the free space in front of vehicles of this class.
double getMaxDecel() const
Get the vehicle type&#39;s maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:218
#define DEBUG_COND
Definition: Vehicle.cpp:55
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:233
The link is a partial right direction.
const SUMOVTypeParameter & getParameter() const
bool lefthand() const
return whether the network was built for lefthand traffic
Definition: MSNet.h:662
double getLateralPositionOnLane() const
Get the vehicle&#39;s lateral position on the lane.
Definition: MSVehicle.h:434
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type definition.
bool isActive() const
Returns whether the current simulation step is an action point for the vehicle.
Definition: MSVehicle.h:591
The link is controlled by a tls which is off and blinks, has to brake.
const MSJunction * getFromJunction() const
Definition: MSEdge.h:357
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2022
virtual double getLateralPositionOnLane() const =0
Get the vehicle&#39;s lateral position on the lane.
double getLength() const
Get vehicle&#39;s length [m].
static SUMOTime gIgnoreJunctionBlocker
Definition: MSGlobals.h:73
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type.
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle&#39;s position relative to the given lane.
Definition: MSVehicle.cpp:3993
double estimateSpeedAfterDistance(const double dist, const double v, const double accel) const
Definition: MSCFModel.cpp:703
The parent class for traffic light logics.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
Position getPosition(const double) const
Return current position (x/y, cartesian)
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static const double SAFETY_GAP
Definition: MSPModel.h:108
T MIN3(T a, T b, T c)
Definition: StdDefs.h:87
#define NUMERICAL_EPS
Definition: config.h:145
bool isStopped() const
Returns whether the vehicle is at a stop.
Definition: MSVehicle.cpp:1751
const double INVALID_DOUBLE
Definition: StdDefs.h:63
const MSLinkCont & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.cpp:2099
double getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:477
virtual double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0) const =0
Computes the vehicle&#39;s follow speed (no dawdling)
const std::string & getID() const
Returns the name of the vehicle.
static bool gUseMesoSim
Definition: MSGlobals.h:91
Representation of a lane in the micro simulation.
Definition: MSLane.h:83
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane&#39;s maximum speed, given a vehicle&#39;s speed limit adaptation.
Definition: MSLane.h:519
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type&#39;s vehicle class.