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