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()) {
384 const_cast<MSLink*>(before)->updateDistToFoePedCrossing(intersections1.back());
385 };
386 }
387
388 myConflicts.push_back(ConflictInfo(
389 lane->getLength() - intersections1.back(),
390 conflictSize, flag));
391
392#ifdef MSLink_DEBUG_CROSSING_POINTS
393 std::cout
394 << " intersection of " << lane->getID()
395 << " totalLength=" << lane->getLength()
396 << " with " << foeLane->getID()
397 << " totalLength=" << foeLane->getLength()
398 << " dist1=" << myConflicts.back().lengthBehindCrossing
399 << " widthFactor=" << myConflicts.back().conflictSize / foeLane->getWidth()
400 << "\n";
401#endif
402 }
403 }
404 // check for overlap with internal lanes from the same source lane
405 const MSLane* pred = lane->getLogicalPredecessorLane();
406 // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
407 // we add all other internal lanes from pred as foeLanes
408 for (const MSLink* const link : pred->getLinkCont()) {
409 const MSLane* const sibling = link->getViaLane();
410 if (sibling != lane && sibling != nullptr) {
411 const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
412 if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
413 // account for lateral shift by the entry links
414 continue;
415 }
416 const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
417 double lbcLane;
418 if (lane->getLength() == sibling->getLength() && &lane->getEdge() == &sibling->getEdge()) {
419 // for parallel lanes, avoid inconsistency in distance estimation (#10988)
420 // between forward distance (getLeaderInfo)
421 // and backward distance used in lane-changing (getFollowersOnConsecutive)
422 lbcLane = lane->getLength() - distToDivergence;
423 } else {
424 lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
425 }
426 ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
427 auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
428 if (it != myFoeLanes.end()) {
429 // avoid duplicate foeLane
430 const int replacedIndex = (int)(it - myFoeLanes.begin());
431 myConflicts[replacedIndex] = ci;
432 } else {
433 myConflicts.push_back(ci);
434 myFoeLanes.push_back(sibling);
435 }
436#ifdef MSLink_DEBUG_CROSSING_POINTS
437 std::cout << " adding same-origin foe" << sibling->getID()
438 << " dist1=" << myConflicts.back().lengthBehindCrossing
439 << "\n";
440#endif
441 }
442 }
443 // init points for the symmetrical conflict
444 // for each pair of conflicting lanes, the link that gets second, sets the pointers
445 for (int i = 0; i < (int)myFoeLanes.size(); i++) {
446 const MSLane* foeLane = myFoeLanes[i];
447 MSLink* foeExitLink = foeLane->getLinkCont()[0];
448 int foundIndex = -1;
449 for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
450 if (foeExitLink->myFoeLanes[i2] == lane) {
451 myConflicts[i].foeConflictIndex = i2;
452 foeExitLink->myConflicts[i2].foeConflictIndex = i;
453 myRecheck.erase({foeExitLink, this});
454 foundIndex = i2;
455 break;
456 }
457 }
458#ifdef MSLink_DEBUG_CROSSING_POINTS
459 std::cout << lane->getID() << " foeLane=" << foeLane->getID() << " index=" << i << " foundIndex=" << foundIndex << "\n";
460#endif
461 if (foundIndex < 0) {
462 if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
463 myRecheck.insert({this, foeExitLink});
464 }
465 }
466 }
467 }
469 // check for links with the same origin lane and the same destination edge
470 const MSEdge* myTarget = &myLane->getEdge();
471 // save foes for entry links
472 for (MSLink* const it : myLaneBefore->getLinkCont()) {
473 const MSEdge* target = &(it->getLane()->getEdge());
474 if (it == this) {
475 continue;
476 }
477 if (target == myTarget) {
478 mySublaneFoeLinks.push_back(it);
479#ifdef MSLink_DEBUG_CROSSING_POINTS
480 std::cout << " sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
481#endif
482 } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
483 // potential turn conflict
484 mySublaneFoeLinks2.push_back(it);
485#ifdef MSLink_DEBUG_CROSSING_POINTS
486 std::cout << " sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
487#endif
488 }
489 }
490 // save foes for exit links
491 if (fromInternalLane()) {
492 //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
493 for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
494 if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
495 //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
496 mySublaneFoeLanes.push_back(link->getViaLane());
497 }
498 }
499 }
500 }
501 if (myInternalLaneBefore != nullptr
503 // for right turns, the curvature helps rather than restricts the linkLeader check
504 && (
507 const double angle = fabs(GeomHelper::angleDiff(
509 myLane->getShape().angleAt2D(0)));
510 if (angle > 0) {
511 double length = myInternalLaneBefore->getShape().length2D();
512 if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
513 myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
514 length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
515 } else if (myInternalLane != nullptr) {
516 length += myInternalLane->getShape().length2D();
517 }
518 myRadius = length / angle;
519 //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
520 }
521 }
522}
523
524
525void
527 for (auto item : myRecheck) {
528#ifdef MSLink_DEBUG_CROSSING_POINTS
529 std::cout << " recheck l1=" << item.first->getDescription() << " l2=" << item.second->getDescription() << "\n";
530#endif
531 MSLink* link = item.first;
532 MSLink* foeExitLink = item.second;
533 const MSLane* lane = link->getInternalLaneBefore();
534 const MSLane* foeLane = foeExitLink->getInternalLaneBefore();
535 int conflictIndex = -1;
536 for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
537 if (link->myFoeLanes[i] == foeLane) {
538 conflictIndex = i;
539 break;
540 }
541 }
542 if (conflictIndex == -1) {
543 WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
544 continue;
545 }
546 ConflictInfo& ci = link->myConflicts[conflictIndex];
547 std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
548 if (intersections1.size() == 0) {
549#ifdef MSLink_DEBUG_CROSSING_POINTS
550 std::cout << " no intersection\n";
551#endif
552 continue;
553 }
554 const double widthFactor = ci.conflictSize / foeLane->getWidth();
555 const double conflictSize2 = lane->getWidth() * widthFactor;
556 std::sort(intersections1.begin(), intersections1.end());
557 intersections1.back() -= conflictSize2 / 2;
558 intersections1.back() = MAX2(0.0, intersections1.back());
559 ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
560 foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
561#ifdef MSLink_DEBUG_CROSSING_POINTS
562 std::cout << " ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
563#endif
564 }
565 myRecheck.clear();
566}
567
568double
569MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource) const {
570 double lbcSibling = 0;
571 double lbcLane = 0;
572
573 PositionVector l = lane->getShape();
574 PositionVector s = sibling->getShape();
575 double length = l.length2D();
576 double sibLength = s.length2D();
577 if (!sameSource) {
578 l = l.reverse();
579 s = s.reverse();
580 } else if (sibling->getEntryLink()->myAmIndirect) {
581 // ignore final waiting position since it may be quite close to the lane
582 // shape but the waiting position is perpendicular (so the minDist
583 // requirement is not necessary
584 lbcSibling += s[-1].distanceTo2D(s[-2]);
585 s.pop_back();
586 } else if (lane->getEntryLink()->myAmIndirect) {
587 // ignore final waiting position since it may be quite close to the lane
588 // shape but the waiting position is perpendicular (so the minDist
589 // requirement is not necessary
590 lbcLane += l[-1].distanceTo2D(l[-2]);
591 l.pop_back();
592 }
593
594#ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
595 std::cout << " sameSource=" << sameSource << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
596#endif
597 if (l.back().distanceTo2D(s.back()) > minDist) {
598 // compute the final divergence point
599 // this position serves two purposes:
600 // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
601 // 2) both vehicles are put into a cf-relationship while before the point.
602 // Since the actual crossing point is at the start of the junction,
603 // we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
604 std::vector<double> distances = l.distances(s);
605#ifdef MSLink_DEBUG_CROSSING_POINTS
606 std::cout << " distances=" << toString(distances) << "\n";
607#endif
608 assert(distances.size() == l.size() + s.size());
609 if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
610 // do a pairwise check between lane and sibling to make because we do not know which of them bends more
611 for (int j = (int)s.size() - 2; j >= 0; j--) {
612 const int i = j + (int)l.size();
613 const double segLength = s[j].distanceTo2D(s[j + 1]);
614 if (distances[i] > minDist) {
615 lbcSibling += segLength;
616 } else {
617 // assume no sharp bends and just interpolate the last segment
618 lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
619 break;
620 }
621 }
622 for (int i = (int)l.size() - 2; i >= 0; i--) {
623 const double segLength = l[i].distanceTo2D(l[i + 1]);
624 if (distances[i] > minDist) {
625 lbcLane += segLength;
626 } else {
627 // assume no sharp bends and just interpolate the last segment
628 lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
629 break;
630 }
631 }
632 }
633 assert(lbcSibling >= -NUMERICAL_EPS);
634 assert(lbcLane >= -NUMERICAL_EPS);
635 }
636 const double distToDivergence1 = sibling->getLength() - lbcSibling;
637 const double distToDivergence2 = lane->getLength() - lbcLane;
638 const double distToDivergence = MIN3(
639 MAX2(distToDivergence1, distToDivergence2),
640 sibLength, length);
641#ifdef MSLink_DEBUG_CROSSING_POINTS
642 std::cout << " distToDivergence=" << distToDivergence
643 << " distTD1=" << distToDivergence1
644 << " distTD2=" << distToDivergence2
645 << " length=" << length
646 << " sibLength=" << sibLength
647 << "\n";
648#endif
649 return distToDivergence;
650}
651
652
653bool
654MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
655 if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
656 std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
657 return intersections.size() > 0;
658 }
659 return false;
660}
661
662
663void
664MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
665 const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
666 const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
667#ifdef DEBUG_APPROACHING
668 if (DEBUG_COND2(approaching)) {
669 std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
670 for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
671 std::cout << "'" << i->first->getID() << "'" << std::endl;
672 }
673 }
674#endif
675 myApproachingVehicles.emplace(approaching,
676 ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
677 arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
678}
679
680
681void
683
684#ifdef DEBUG_APPROACHING
685 if (DEBUG_COND2(approaching)) {
686 std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
687 for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
688 std::cout << "'" << i->first->getID() << "'" << std::endl;
689 }
690 }
691#endif
692 myApproachingVehicles.emplace(approaching, ai);
693}
694
695void
696MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
697 if (myApproachingPersons == nullptr) {
699 }
700 myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
701}
702
703void
705
706#ifdef DEBUG_APPROACHING
707 if (DEBUG_COND2(veh)) {
708 std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
709 std::cout << "' Removing approaching vehicle '" << veh->getID() << "'\nCurrently registered vehicles:" << std::endl;
710 for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
711 std::cout << "'" << i->first->getID() << "'" << std::endl;
712 }
713 }
714#endif
715 myApproachingVehicles.erase(veh);
716}
717
718
719void
721 if (myApproachingPersons == nullptr) {
722 WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
723 return;
724 }
725#ifdef DEBUG_APPROACHING
726 if (DEBUG_COND2(person)) {
727 std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
728 std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
729 for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
730 std::cout << "'" << i->first->getID() << "'" << std::endl;
731 }
732 }
733#endif
734 myApproachingPersons->erase(person);
735}
736
737
740 auto i = myApproachingVehicles.find(veh);
741 if (i != myApproachingVehicles.end()) {
742 return i->second;
743 } else {
744 return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
745 }
746}
747
748
749void
753
754
756MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
757 const double leaveSpeed, const double vehicleLength) const {
758 return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
759}
760
761
762bool
763MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
764 double impatience, double decel, SUMOTime waitingTime, double posLat,
765 BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
766#ifdef MSLink_DEBUG_OPENED
767 if (gDebugFlag1) {
768 std::cout << SIMTIME << " opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
769 }
770#endif
771 if (haveRed() && !ignoreRed) {
772 return false;
773 }
775 return true;
776 }
777 const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
779 // check for foes on the same lane with the same target edge
780 for (const MSLink* foeLink : mySublaneFoeLinks) {
781 assert(myLane != foeLink->getLane());
782 for (const auto& it : foeLink->myApproachingVehicles) {
783 const SUMOVehicle* foe = it.first;
784 if (
785 // there only is a conflict if the paths cross
786 ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
787 || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
788 // the vehicle that arrives later must yield
789 && (arrivalTime > it.second.arrivalTime
790 // if both vehicles arrive at the same time, the one
791 // to the left must yield
792 || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
793 if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
794 impatience, decel, waitingTime, ego)) {
795#ifdef MSLink_DEBUG_OPENED
796 if (gDebugFlag1) {
797 std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
798 }
799#endif
800 if (collectFoes == nullptr) {
801#ifdef MSLink_DEBUG_OPENED
802 if (gDebugFlag1) {
803 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
804 }
805#endif
806 return false;
807 } else {
808 collectFoes->push_back(it.first);
809 }
810 }
811 }
812 }
813 }
814 // check for foes on the same lane with a different target edge
815 // (straight movers take precedence if the paths cross)
816 const int lhSign = MSGlobals::gLefthand ? -1 : 1;
817 for (const MSLink* foeLink : mySublaneFoeLinks2) {
819 for (const auto& it : foeLink->myApproachingVehicles) {
820 const SUMOVehicle* foe = it.first;
821 // there only is a conflict if the paths cross
822 // and if the vehicles are not currently in a car-following relationship
823 const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
824 if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
826 && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
828 && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
829 if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
830 impatience, decel, waitingTime, ego)) {
831#ifdef MSLink_DEBUG_OPENED
832 if (gDebugFlag1) {
833 std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
834 }
835#endif
836 if (collectFoes == nullptr) {
837#ifdef MSLink_DEBUG_OPENED
838 if (gDebugFlag1) {
839 std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
840 }
841#endif
842 return false;
843 } else {
844 collectFoes->push_back(it.first);
845 }
846 }
847 }
848 }
849 }
850 }
852 // priority usually means the link is open but there are exceptions:
853 // zipper still needs to collect foes
854 // sublane model could have detected a conflict
855 return collectFoes == nullptr || collectFoes->size() == 0;
856 }
857 if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
858 return false;
859 } else if (myState == LINKSTATE_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPSIGN_WAIT, TS))) {
860 return false;
861 }
862
863 const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
864#ifdef MSLink_DEBUG_OPENED
865 if (gDebugFlag1) {
866 std::cout << SIMTIME << " opened link=" << getViaLaneOrLane()->getID() << " foeLinks=" << foeLinks.size() << "\n";
867 }
868#endif
869
870 if (MSGlobals::gUseMesoSim && impatience == 1) {
871 return true;
872 }
873 const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
874 for (const MSLink* const link : foeLinks) {
876 if (link->haveRed()) {
877 continue;
878 }
879 }
880#ifdef MSLink_DEBUG_OPENED
881 if (gDebugFlag1) {
882 std::cout << SIMTIME << " foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
883 if (link->getLane()->isCrossing()) {
884 std::cout << SIMTIME << " approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
885 }
886 }
887#endif
888 if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
889 impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
890 return false;
891 }
892 }
893 if (collectFoes != nullptr && collectFoes->size() > 0) {
894 return false;
895 }
896 return true;
897}
898
899
900bool
901MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
902 bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
903 BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
904 for (const auto& it : myApproachingVehicles) {
905#ifdef MSLink_DEBUG_OPENED
906 if (gDebugFlag1) {
907 if (ego != nullptr
910 std::stringstream stream; // to reduce output interleaving from different threads
911 stream << SIMTIME << " " << myApproachingVehicles.size() << " foe link=" << getViaLaneOrLane()->getID()
912 << " foeVeh=" << it.first->getID() << " (below ignore speed)"
913 << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
914 << "\n";
915 std::cout << stream.str();
916 }
917 }
918#endif
919 if (it.first != ego
920 && (ego == nullptr
924 && !ignoreFoe(ego, it.first)
925 && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
926 && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
927 impatience, decel, waitingTime, ego)) {
928 if (collectFoes == nullptr) {
929 return true;
930 } else {
931 collectFoes->push_back(it.first);
932 }
933 }
934 }
935 if (myApproachingPersons != nullptr && !haveRed()) {
936 for (const auto& it : *myApproachingPersons) {
937//#ifdef MSLink_DEBUG_OPENED
938// if (gDebugFlag1) {
939// std::cout << SIMTIME << ": " << ego->getID() << " check person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime
940// << " lTime=" << leaveTime << " foeLTime=" << it.second.leavingTime
941// << " dist=" << dist << "\n";
942// }
943//#endif
944 if ((ego == nullptr
946 || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
948 && !ignoreFoe(ego, it.first)
949 && !((arrivalTime > it.second.leavingTime) || (leaveTime < it.second.arrivalTime))) {
950 if (ego == nullptr) {
951 // during insertion
953 continue;
954 } else {
955 return true;
956 }
957 }
958 // check whether braking is feasible (ego might have started to accelerate already)
959 const auto& cfm = ego->getVehicleType().getCarFollowModel();
960#ifdef MSLink_DEBUG_OPENED
961 if (gDebugFlag1) {
962 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";
963 }
964#endif
965 if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
966#ifdef MSLink_DEBUG_OPENED
967 if (gDebugFlag1) {
968 std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
969 }
970#endif
971 if (collectFoes == nullptr) {
972 return true;
973 } else {
974 collectFoes->push_back(it.first);
975 }
976 }
977 }
978 }
979 }
980 return false;
981}
982
983
984bool
986 SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
987 bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
988 const SUMOTrafficObject* ego) const {
989#ifdef MSLink_DEBUG_OPENED
990 if (gDebugFlag1) {
991 std::stringstream stream; // to reduce output interleaving from different threads
992 stream << " link=" << getDescription()
993 << " foeVeh=" << veh->getID()
994 << " req=" << avi.willPass
995 << " aT=" << avi.arrivalTime
996 << " lT=" << avi.leavingTime
997 << "\n";
998 std::cout << stream.str();
999 }
1000#endif
1001 if (!avi.willPass) {
1002 return false;
1003 }
1005 assert(waitingTime > 0);
1006#ifdef MSLink_DEBUG_OPENED
1007 if (gDebugFlag1) {
1008 std::stringstream stream; // to reduce output interleaving from different threads
1009 stream << " foeDist=" << avi.dist
1010 << " foeBGap=" << veh->getBrakeGap(false)
1011 << " foeWait=" << avi.waitingTime
1012 << " wait=" << waitingTime
1013 << "\n";
1014 std::cout << stream.str();
1015 }
1016#endif
1017 // when using actionSteps, the foe waiting time may be outdated
1018 const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
1019 if (waitingTime > avi.waitingTime + actionDelta) {
1020 return false;
1021 }
1022 if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
1023 return false;
1024 }
1025 }
1026 SUMOTime foeArrivalTime = avi.arrivalTime;
1027 double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
1028 if (impatience > 0 && arrivalTime < avi.arrivalTime) {
1029#ifdef MSLink_DEBUG_OPENED
1030 gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
1031#endif
1032 const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
1033 foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
1034#ifdef MSLink_DEBUG_OPENED
1035 if (gDebugFlag6) {
1036 std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
1037 << " at=" << STEPS2TIME(arrivalTime)
1038 << " fat=" << STEPS2TIME(avi.arrivalTime)
1039 << " fatb=" << STEPS2TIME(fatb)
1040 << " fat2=" << STEPS2TIME(foeArrivalTime)
1041 << "\n";
1042 }
1043#endif
1044 }
1045
1046
1047 const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
1049 : (ego == nullptr
1052 //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
1053#ifdef MSLink_DEBUG_OPENED
1054 if (gDebugFlag1 || gDebugFlag6) {
1055 std::stringstream stream; // to reduce output interleaving from different threads
1056 stream << " imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
1057 std::cout << stream.str();
1058 }
1059#endif
1060 if (avi.leavingTime < arrivalTime) {
1061 // ego wants to be follower
1062 if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
1063 || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
1064 veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
1065#ifdef MSLink_DEBUG_OPENED
1066 if (gDebugFlag1 || gDebugFlag6) {
1067 std::cout << " blocked (cannot follow)\n";
1068 }
1069#endif
1070 return true;
1071 }
1072 } else if (foeArrivalTime > leaveTime + lookAhead) {
1073 // ego wants to be leader.
1074 if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
1075 decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
1076#ifdef MSLink_DEBUG_OPENED
1077 if (gDebugFlag1 || gDebugFlag6) {
1078 std::cout << " blocked (cannot lead)\n";
1079 }
1080#endif
1081 return true;
1082 }
1083 } else {
1084 // even without considering safeHeadwayTime there is already a conflict
1085#ifdef MSLink_DEBUG_OPENED
1086 if (gDebugFlag1 || gDebugFlag6) {
1087 std::cout << " blocked (hard conflict)\n";
1088 }
1089#endif
1090 return true;
1091 }
1092 return false;
1093}
1094
1095
1097MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
1098 // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
1099 // b: distance driven past foeArrivalTime
1100 // m: permitted decceleration
1101 // d: total deceleration until foeArrivalTime
1102 // dist2: distance of foe at arrivalTime
1103 // actual arrivalTime must fall on a simulation step
1104 if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
1105 // foe enters the junction in the same step
1106 return foeArrivalTime;
1107 }
1108 if (arrivalTime % DELTA_T > 0) {
1109 arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
1110 }
1111 //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
1112 const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
1113 const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
1114 const double d = dt * m;
1115 const double a = dt * d / 2;
1116 const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
1117 const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
1118 if (0.5 * v * v / m <= dist2) {
1119 if (gDebugFlag6) {
1120 std::cout << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " a=" << a << " canBrakeToStop\n";
1121 }
1122 fasb = 0;
1123 return foeArrivalTime + TIME2STEPS(30);
1124 }
1125 // a = b (foe reaches the original distance to the stop line)
1126 // x: time driven past foeArrivalTime
1127 // v: foe speed without braking
1128 // v2: average foe speed after foeArrivalTime (braking continues for time x)
1129 // v2 = (v - d - x * m / 2)
1130 // b = v2 * x
1131 // solving for x gives:
1132 const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
1133
1134#ifdef MSLink_DEBUG_OPENED
1135 const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
1136 if (gDebugFlag6 || std::isnan(x)) {
1137 std::cout << SIMTIME << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
1138 }
1139#endif
1140 fasb = v - (dt + x) * m;
1141 return foeArrivalTime + TIME2STEPS(x);
1142}
1143
1144
1145bool
1146MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
1147 for (const MSLink* const link : myFoeLinks) {
1148 if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
1149 return true;
1150 }
1151 }
1152 for (const MSLane* const lane : myFoeLanes) {
1153 if (lane->getVehicleNumberWithPartials() > 0) {
1154 return true;
1155 }
1156 }
1157 return false;
1158}
1159
1160
1161std::pair<const SUMOVehicle*, const MSLink*>
1162MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
1163 double closetDist = std::numeric_limits<double>::max();
1164 const SUMOVehicle* closest = nullptr;
1165 const MSLink* foeLink = nullptr;
1166 for (MSLink* link : myFoeLinks) {
1167 for (const auto& it : link->myApproachingVehicles) {
1168 //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
1169 if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
1170 return std::make_pair(nullptr, wrapAround);
1171 } else if (it.second.dist < closetDist) {
1172 closetDist = it.second.dist;
1173 if (it.second.willPass) {
1174 closest = it.first;
1175 foeLink = link;
1176 }
1177 }
1178 }
1179 }
1180 return std::make_pair(closest, foeLink);
1181}
1182
1183
1184void
1186 if (myState != state) {
1188 }
1189 myState = state;
1190 if (haveGreen()) {
1192 }
1193}
1194
1195
1196void
1198 myLogic = logic;
1199}
1200
1201
1202bool
1204 // when a traffic light is switched off minor roads have their cont status revoked
1206}
1207
1208
1209bool
1211 if (myInternalLane == nullptr || myAmCont) {
1212 return false;
1213 } else {
1215 if (!pred->getEdge().isInternal()) {
1216 return false;
1217 } else {
1218 const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1219 assert(pred2 != nullptr);
1220 const MSLink* const predLink = pred2->getLinkTo(pred);
1221 assert(predLink != nullptr);
1222 if (predLink->havePriority()) {
1223 return true;
1224 }
1226 return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
1227 } else {
1228 return predLink->haveYellow();
1229 }
1230 }
1231 }
1232}
1233
1234
1235bool
1238 return false;
1239 } else {
1241 if (!pred->getEdge().isInternal()) {
1242 return false;
1243 } else {
1244 const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1245 assert(pred2 != nullptr);
1246 const MSLink* const predLink = pred2->getLinkTo(pred);
1247 assert(predLink != nullptr);
1248 return predLink->getState() == linkState;
1249 }
1250 }
1251}
1252
1253
1254void
1255MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
1256 if (myApproachingVehicles.size() > 0) {
1257 od.openTag("link");
1258 od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
1259 const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
1260 od.writeAttr(SUMO_ATTR_VIA, via);
1261 od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
1262 std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
1263 for (auto it : myApproachingVehicles) {
1264 toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
1265 }
1266 std::sort(toSort.begin(), toSort.end());
1267 for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
1268 od.openTag("approaching");
1269 const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
1270 od.writeAttr(SUMO_ATTR_ID, it->second->getID());
1271 od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
1272 od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
1273 od.writeAttr("leaveTime", time2string(avi.leavingTime));
1274 od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
1275 od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
1276 od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
1277 od.writeAttr("willPass", toString(avi.willPass));
1278 od.closeTag();
1279 }
1280 od.closeTag();
1281 }
1282}
1283
1284
1285double
1287 double len = 0.;
1288 MSLane* lane = myInternalLane;
1289
1290 while (lane != nullptr && lane->isInternal()) {
1291 len += lane->getLength();
1292 lane = lane->getLinkCont()[0]->getViaLane();
1293 }
1294 return len;
1295}
1296
1297double
1299 double len = 0.;
1300 const MSLane* lane = myInternalLane;
1301
1302 while (lane != nullptr && lane->isInternal()) {
1303 len += lane->getLength();
1304 if (lane->getIncomingLanes().size() == 1) {
1305 lane = lane->getIncomingLanes()[0].lane;
1306 } else {
1307 break;
1308 }
1309 }
1310 return len;
1311}
1312
1313
1314double
1316 MSLane* via = myInternalLane;
1317 double totalDist = 0.;
1318 bool foundCrossing = false;
1319 while (via != nullptr) {
1320 MSLink* link = via->getLinkCont()[0];
1321 double dist = link->getLengthBeforeCrossing(foeLane);
1322 if (dist != INVALID_DOUBLE) {
1323 // found conflicting lane
1324 totalDist += dist;
1325 foundCrossing = true;
1326 break;
1327 } else {
1328 totalDist += via->getLength();
1329 via = link->getViaLane();
1330 }
1331 }
1332 if (foundCrossing) {
1333 return totalDist;
1334 } else {
1335 return INVALID_DOUBLE;
1336 }
1337}
1338
1339
1340double
1342 int foe_ix;
1343 for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
1344 if (myFoeLanes[foe_ix] == foeLane) {
1345 break;
1346 }
1347 }
1348 if (foe_ix == (int)myFoeLanes.size()) {
1349 // no conflict with the given lane, indicate by returning -1
1350#ifdef MSLink_DEBUG_CROSSING_POINTS
1351 std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
1352#endif
1353 return INVALID_DOUBLE;
1354 } else {
1355 // found conflicting lane index
1356 double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
1357 if (dist == -10000.) {
1358 // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
1359 return INVALID_DOUBLE;
1360 }
1361#ifdef MSLink_DEBUG_CROSSING_POINTS
1362 std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
1363 << "' at distance " << dist << " (approach along '"
1364 << myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
1365#endif
1366 return dist;
1367 }
1368}
1369
1370
1371bool
1374 return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
1375 } else {
1376 return false;
1377 }
1378}
1379
1380bool
1382 // either a non-cont entry link or the link after a cont-link
1383 return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
1384}
1385
1386bool
1389 return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
1390 } else {
1391 return false;
1392 }
1393}
1394
1395bool
1398 return (getInternalLaneBefore() != nullptr
1399 && myInternalLaneBefore->getIncomingLanes().size() == 1
1400 && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
1401 } else {
1402 return false;
1403 }
1404}
1405
1406
1407const MSLink*
1409 MSLane* lane = myInternalLane;
1410 const MSLink* link = this;
1411 while (lane != nullptr) {
1412 link = lane->getLinkCont()[0];
1413 lane = link->getViaLane();
1414 }
1415 return link;
1416}
1417
1418
1419const MSLink*
1421 const MSLink* link = this;
1422 while (link->myLaneBefore->isInternal()) {
1423 assert(myLaneBefore->getIncomingLanes().size() == 1);
1424 link = link->myLaneBefore->getIncomingLanes().front().viaLink;
1425 }
1426 return link;
1427}
1428
1429
1430bool
1432 return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
1433}
1434
1435
1437MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
1438 LinkLeaders result;
1439 // this link needs to start at an internal lane (either an exit link or between two internal lanes)
1440 // or it must be queried by the pedestrian model (ego == 0)
1441 if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
1442 // ignore link leaders
1443 return result;
1444 }
1445 //gDebugFlag1 = true;
1446 if (gDebugFlag1) {
1447 std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
1448 }
1449 if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
1450 const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
1451 if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
1452 // check oncoming on bidiLane during laneChanging
1453 && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
1454 if (gDebugFlag1) {
1455 std::cout << " ignore linkLeaders beyond red light\n";
1456 }
1457 return result;
1458 }
1459 }
1460 // this is an exit link
1461 const double extraGap = ego != nullptr ? ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_EXTRA_GAP, 0) : 0;
1462 for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
1463 const MSLane* foeLane = myFoeLanes[i];
1464 const MSLink* foeExitLink = foeLane->getLinkCont()[0];
1465 // distance from the querying vehicle to the crossing point with foeLane
1466 double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
1467 const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
1468 const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
1469 const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getLogicalPredecessorLane() == foeLane->getLogicalPredecessorLane());
1470 const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
1471 const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
1472 // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
1473 const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
1475 if (gDebugFlag1) {
1476 std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
1477 << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
1478 << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
1479 << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
1480 << " cw=" << crossingWidth
1481 << " fcw=" << foeCrossingWidth
1482 << " contLane=" << contLane
1483 << " state=" << toString(myState)
1484 << " foeState=" << toString(foeExitLink->getState())
1485 << "\n";
1486 }
1487 if (distToCrossing + crossingWidth < 0 && !sameTarget
1488 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
1489 continue; // vehicle is behind the crossing point, continue with next foe lane
1490 }
1491 bool ignoreGreenCont = false;
1492 bool foeIndirect = false;
1493 if (contLane) {
1494 const MSLink* entry = getLaneBefore()->getEntryLink();
1495 const MSLink* foeEntry = foeLane->getEntryLink();
1496 foeIndirect = foeEntry->myAmIndirect;
1497 if (entry != nullptr && entry->haveGreen()
1498 && foeEntry != nullptr && foeEntry->haveGreen()
1499 && entry->myLaneBefore != foeEntry->myLaneBefore) {
1500 // ignore vehicles before an internaljunction as long as they are still in green minor mode
1501 ignoreGreenCont = true;
1502 }
1503 }
1504 if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
1505 if (gDebugFlag1) {
1506 std::cout << " ignore:noIntersection\n";
1507 }
1508 continue;
1509 }
1510 // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
1511 // therefore we return all vehicles on the lane
1512 //
1513 // special care must be taken for continuation lanes. (next lane is also internal)
1514 // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
1515 // and should block (gap = -1) unless they are part of an indirect turn
1517 for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1518 MSVehicle* leader = (MSVehicle*)*it_veh;
1519 const double leaderBack = leader->getBackPositionOnLane(foeLane) - extraGap;
1520 const double leaderBackDist = foeDistToCrossing - leaderBack;
1521 const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
1522 const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
1523 const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
1524 const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
1525 const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
1526 && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
1527 const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
1528 const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || (sameSource && !MSGlobals::gComputeLC)) && ego != nullptr;
1529 const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
1530 && enteredTheCrossingPoint
1531 && (!foeExitLink->isInternalJunctionLink() || foeIsBicycleTurn))
1532 || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
1533 const bool isOpposite = leader->getLaneChangeModel().isOpposite();
1534 const auto avi = foeExitLink->getApproaching(leader);
1535 // if leader is not found, assume that it performed a lane change in the last step
1536 const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
1537 if (gDebugFlag1) {
1538 std::cout << " candidate leader=" << leader->getID()
1539 << " cannotIgnore=" << cannotIgnore
1540 << " fdtc=" << foeDistToCrossing
1541 << " lb=" << leaderBack
1542 << " lbd=" << leaderBackDist
1543 << " fcwidth=" << foeCrossingWidth
1544 << " r=" << myRadius
1545 << " sagitta=" << sagitta
1546 << " foePastCP=" << pastTheCrossingPoint
1547 << " foeEnteredCP=" << enteredTheCrossingPoint
1548 << " inTheWay=" << inTheWay
1549 << " willPass=" << willPass
1550 << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
1551 << " ignoreGreenCont=" << ignoreGreenCont
1552 << " foeIndirect=" << foeIndirect
1553 << " foeBikeTurn=" << foeIsBicycleTurn
1554 << " isOpposite=" << isOpposite << "\n";
1555 }
1556 if (leader == ego) {
1557 continue;
1558 }
1559 // ignore greenCont foe vehicles that are not in the way
1560 if (!inTheWay && ignoreGreenCont) {
1561 if (gDebugFlag1) {
1562 std::cout << " ignoreGreenCont\n";
1563 }
1564 continue;
1565 }
1566 // after entering the conflict area, ignore foe vehicles that are not in the way
1567 if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
1568 && distToCrossing < -POSITION_EPS && !inTheWay
1569 && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
1570 if (gDebugFlag1) {
1571 std::cout << " ego entered conflict area\n";
1572 }
1573 continue;
1574 }
1576 && sameSource
1577 && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
1578 && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
1579 // ego is already on the junction and clearly ahead of foe
1580 if (gDebugFlag1) {
1581 std::cout << " ego ahead of same-source foe\n";
1582 }
1583 continue;
1584 }
1585
1586 // ignore foe vehicles that will not pass
1587 if ((!cannotIgnore || leader->isStopped() || sameTarget)
1588 && !willPass
1589 && leader->isFrontOnLane(foeLane)
1590 && !isOpposite
1591 && !inTheWay
1592 // willPass is false if the vehicle is already on the stopping edge
1593 && !leader->willStop()) {
1594 if (gDebugFlag1) {
1595 std::cout << " foe will not pass\n";
1596 }
1597 continue;
1598 }
1599 if (leader->isBidiOn(foeLane)) {
1600 // conflict resolved via forward lane of the foe
1601 continue;
1602 }
1603 // check whether foe is blocked and might need to change before leaving the junction
1604 const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
1605 leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
1606 const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
1607
1608 const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
1609 if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
1610 && (!foeStrategicBlocked || sameInternalEdge)) {
1611 if (ego->getLane() == leader->getLane()) {
1612 continue;
1613 }
1614 // ignore vehicles if not in conflict sublane-wise
1615 const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
1616 const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
1617 double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1618 if (foeLaneIsBidi) {
1619 // leader is oncoming
1620 posLatLeader = foeLane->getWidth() - posLatLeader;
1621 }
1622 const double latGap = (fabs(posLat - posLatLeader)
1623 - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
1624 const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
1625 if (gDebugFlag1) {
1626 std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
1627 << " sameSource=" << sameSource
1628 << " sameTarget=" << sameTarget
1629 << " foeLaneIsBidi=" << foeLaneIsBidi
1630 << " foeLane=" << foeLane->getID()
1631 << " leader=" << leader->getID()
1632 << " egoLane=" << ego->getLane()->getID()
1633 << " leaderLane=" << leader->getLane()->getID()
1634 << " egoLat=" << posLat
1635 << " egoLatOffset=" << egoLatOffset
1636 << " leaderLat=" << posLatLeader
1637 << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1638 << " latGap=" << latGap
1639 << " maneuverDist=" << maneuverDist
1640 << " computeLC=" << MSGlobals::gComputeLC
1641 << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
1642 << "\n";
1643 }
1644 if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
1645 // do not perform sublane changes that interfere with the leader vehicle
1646 && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
1647 const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
1648 if (sameSource) {
1649 // for lanes from the same edge, higer index implies a
1650 // connection further to the left
1651 const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
1652 if ((posLat > posLatLeader) == leaderFromRight) {
1653 // ignore speed since lanes diverge
1654 if (gDebugFlag1) {
1655 std::cout << " ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
1656 }
1657 continue;
1658 }
1659 } else if (sameTarget) {
1660 // for lanes from different edges we cannot rely on the
1661 // index due to wrap-around issues
1662 if (myDirection != foeEntryLink->getDirection()) {
1663 bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
1664 // leader vehicle should not move towards ego
1666 leaderFromRight = !leaderFromRight;
1667 }
1668 if ((posLat > posLatLeader) == leaderFromRight
1669 // leader should keep lateral position or move away from ego
1670 && (leader->getLaneChangeModel().getSpeedLat() == 0
1671 || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
1672 && (ego->getLaneChangeModel().getSpeedLat() == 0
1673 || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > latGap))) {
1674 if (gDebugFlag1) {
1675 std::cout << " ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
1676 }
1677 continue;
1678 }
1679 } else {
1680 // XXX figure out relative direction somehow
1681 }
1682 } else {
1683 if (gDebugFlag1) {
1684 std::cout << " ignored oncoming bidi leader\n";
1685 }
1686 continue;
1687 }
1688 }
1689 }
1691 // compute distance between vehicles on the superimposition of both lanes
1692 // where the crossing point is the common point
1693 double gap;
1694 bool fromLeft = true;
1695 if (ego == nullptr) {
1696 // request from pedestrian model. return distance between leaderBack and crossing point
1697 //std::cout << " foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
1698 gap = leaderBackDist;
1699 // distToCrossing should not take into account the with of the foe lane
1700 // (which was subtracted in setRequestInformation)
1701 // Instead, the width of the foe vehicle is used directly by the caller.
1702 distToCrossing += myConflicts[i].conflictSize / 2;
1703 if (gap + foeCrossingWidth < 0) {
1704 // leader is completely past the crossing point
1705 // or there is no crossing point
1706 continue; // next vehicle
1707 }
1708 // we need to determine whether the vehicle passes the
1709 // crossing from the left or the right (heuristic)
1710 fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
1711 } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
1712 gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
1713 } else {
1714 if (pastTheCrossingPoint && !sameTarget) {
1715 // leader is completely past the crossing point
1716 // or there is no crossing point
1717 if (gDebugFlag1) {
1718 std::cout << " foePastCP ignored\n";
1719 }
1720 continue;
1721 }
1722 double leaderBackDist2 = leaderBackDist;
1723 if (sameTarget && leaderBackDist2 < 0) {
1724 const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
1725 if (mismatch > 0) {
1726 leaderBackDist2 += mismatch;
1727 }
1728 }
1729 if (gDebugFlag1) {
1730 std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
1731 << " backDist=" << leaderBackDist
1732 << " backDist2=" << leaderBackDist2
1733 << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
1734 << "\n";
1735 }
1736 gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
1737 }
1738 // if the foe is already moving off the intersection, we may
1739 // advance up to the crossing point unless we have the same target or same source
1740 // (for sameSource, the crossing point indicates the point of divergence)
1741 const bool stopAsap = ((leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource))
1742 || (ego != nullptr && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ADVANCE, 1.0) == 0.0));
1743 if (gDebugFlag1) {
1744 std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
1745 }
1746 if (ignoreFoe(ego, leader)) {
1747 continue;
1748 }
1749 const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
1750 (inTheWay ? LL_IN_THE_WAY : 0) |
1751 (sameSource ? LL_SAME_SOURCE : 0) |
1752 (sameTarget ? LL_SAME_TARGET : 0));
1753 result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
1754 }
1755
1756 }
1757 if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
1758 // check for crossing pedestrians (keep driving if already on top of the crossing
1759 const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
1760 const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
1762 // @check lefthand?!
1763 const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
1764 const double vehCenter = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5
1765 + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
1766 // can access the movement model here since we already checked for existing persons above
1767 if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehCenter, vehWidth,
1769 collectBlockers)) {
1770 result.emplace_back(nullptr, -1, distToPeds);
1771 } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
1772 const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
1773 if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
1774 // a person might step on the crossing at any moment, since ego
1775 // is already on the junction, the opened() check is not done anymore
1776 const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
1777 for (const auto& item : (*crossingLink->myApproachingPersons)) {
1778 if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
1779 if (gDebugFlag1) {
1780 std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
1781 //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1782 << "\n";
1783 }
1784 result.emplace_back(nullptr, -1, distToPeds);
1785 break;
1786 //} else {
1787 // if (gDebugFlag1) {
1788 // std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
1789 // << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1790 // << "\n";
1791 // }
1792 }
1793 }
1794 }
1795 }
1796 }
1797 }
1798
1799 //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
1800 if (ego != nullptr) {
1801 checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
1802 checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
1803 }
1804
1805 if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
1806 // check for foes on the same edge
1807 for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
1808 const MSLane* foeLane = *it;
1810 for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1811 MSVehicle* leader = (MSVehicle*)*it_veh;
1812 if (leader == ego) {
1813 continue;
1814 }
1815 if (leader->getLane()->isNormal()) {
1816 // leader is past the conflict point
1817 continue;
1818 }
1819 const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
1820 const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane) - extraGap;
1821 if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
1822 // ego is ahead of leader
1823 continue;
1824 }
1825 const double posLat = ego->getLateralPositionOnLane();
1826 const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1827 if (gDebugFlag1) {
1828 std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
1829 << " foeLane=" << foeLane->getID()
1830 << " leader=" << leader->getID()
1831 << " egoLane=" << ego->getLane()->getID()
1832 << " leaderLane=" << leader->getLane()->getID()
1833 << " gap=" << gap
1834 << " egoLat=" << posLat
1835 << " leaderLat=" << posLatLeader
1836 << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1837 << " egoIndex=" << myInternalLaneBefore->getIndex()
1838 << " foeIndex=" << foeLane->getIndex()
1839 << " dist=" << dist
1840 << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
1841 << "\n";
1842 }
1843 // there only is a conflict if the paths cross
1844 if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
1845 || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
1846 if (gDebugFlag1) {
1847 std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
1848 }
1849 if (ignoreFoe(ego, leader)) {
1850 continue;
1851 }
1852 result.emplace_back(leader, gap, -1);
1853 }
1854 }
1855 }
1856 }
1857 return result;
1858}
1859
1860
1861void
1862MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
1863 if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
1864 // pedestrians may be on an arbitrary path across this
1865 // walkingarea. make sure to keep enough distance.
1866 // This is a simple but conservative solution that could be improved
1867 // by ignoring pedestrians that are "obviously" not on a collision course
1868 double distToPeds = std::numeric_limits<double>::max();
1869 assert(myInternalLaneBefore != nullptr);
1871 if (ego->getLateralPositionOnLane() != 0) {
1872 egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
1873 }
1874 for (MSTransportable* t : foeLane->getEdge().getPersons()) {
1875 MSPerson* p = static_cast<MSPerson*>(t);
1876 double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
1877 const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
1878 if (inFront) {
1879 dist -= ego->getVehicleType().getMinGap();
1880 }
1881#ifdef DEBUG_WALKINGAREA
1882 if (ego->isSelected()) {
1883 std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
1884 << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
1885 << " futurePedPos=" << getFuturePosition(p)
1886 << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
1887 << " inFront=" << inFront
1888 << " dist=" << dist << "\n";
1889 }
1890#endif
1891 if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
1892 if (inFront) {
1893 const double oncomingFactor = isOnComingPed(ego, p);
1894 if (oncomingFactor > 0) {
1895 // account for pedestrian movement while closing in
1896 const double timeToStop = sqrt(dist) / 2;
1897 const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
1898 dist = MAX2(0.0, dist - pedDist);
1899#ifdef DEBUG_WALKINGAREA
1900 if (ego->isSelected()) {
1901 std::cout << " timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
1902 }
1903#endif
1904 }
1905 }
1906 if (ignoreFoe(ego, p)) {
1907 continue;
1908 }
1909 distToPeds = MIN2(distToPeds, dist);
1910 if (collectBlockers != nullptr) {
1911 collectBlockers->push_back(p);
1912 }
1913 }
1914 }
1915 if (distToPeds != std::numeric_limits<double>::max()) {
1916 // leave extra space in front
1917 result.emplace_back(nullptr, -1, distToPeds);
1918 }
1919 }
1920}
1921
1922bool
1923MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
1924 const double pedAngle = ego->getPosition().angleTo2D(pPos);
1925 const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
1926#ifdef DEBUG_WALKINGAREA
1927 if (ego->isSelected()) {
1928 std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
1929 }
1930#endif
1931 if (angleDiff < DEG2RAD(75)) {
1932 return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
1933 }
1934 return false;
1935}
1936
1937
1938double
1939MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
1940 const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
1941 const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
1942#ifdef DEBUG_WALKINGAREA
1943 if (ego->isSelected()) {
1944 std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
1945 }
1946#endif
1947 if (angleDiff <= DEG2RAD(90)) {
1948 ;
1949 return cos(angleDiff);
1950 } else {
1951 return 0;
1952 }
1953}
1954
1955
1957MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
1958 const double a = p->getAngle();
1959 const double dist = timeHorizon * p->getMaxSpeed();
1960
1961 const Position offset(cos(a) * dist, sin(a) * dist);
1962 return p->getPosition() + offset;
1963}
1964
1965
1966MSLink*
1967MSLink::getParallelLink(int direction) const {
1968 if (direction == -1) {
1969 return myParallelRight;
1970 } else if (direction == 1) {
1971 return myParallelLeft;
1972 } else {
1973 assert(false || myLane->getOpposite() != nullptr);
1974 return nullptr;
1975 }
1976}
1977
1978MSLink*
1980 if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
1981 for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
1982 if (cand->getLane() == myLaneBefore->getOpposite()) {
1983 return cand;
1984 }
1985 }
1986 }
1987 return nullptr;
1988}
1989
1990
1991MSLink*
1993 const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
1994 const MSLane* const after = getLane()->getParallelLane(direction, false);
1995 if (before != nullptr && after != nullptr) {
1996 for (MSLink* const link : before->getLinkCont()) {
1997 if (link->getLane() == after) {
1998 return link;
1999 }
2000 }
2001 }
2002 return nullptr;
2003}
2004
2005
2006double
2007MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
2008 SUMOTime arrivalTime,
2009 const BlockingFoes* foes) const {
2010 if (myFoeLinks.size() == 0) {
2011 // link should have LINKSTATE_MAJOR in this case
2012 assert(false);
2013 return vSafe;
2014 } else if (myFoeLinks.size() > 1) {
2015 throw ProcessError("Zipper junctions with more than two conflicting lanes are not supported (at junction '"
2016 + myJunction->getID() + "')");
2017 }
2018 const double brakeGap = ego->getCarFollowModel().brakeGap(ego->getSpeed(), ego->getCarFollowModel().getMaxDecel(), TS);
2019 if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
2020#ifdef DEBUG_ZIPPER
2022 DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2023 << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
2024#endif
2025 return vSafe;
2026 }
2027#ifdef DEBUG_ZIPPER
2028 DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2029 << " egoAT=" << arrivalTime
2030 << " dist=" << dist
2031 << " brakeGap=" << brakeGap
2032 << " vSafe=" << vSafe
2033 << " numFoes=" << foes->size()
2034 << "\n")
2035#endif
2036 MSLink* foeLink = myFoeLinks[0];
2037 for (const auto& item : *foes) {
2038 if (!item->isVehicle()) {
2039 continue;
2040 }
2041 const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
2042 assert(foe != 0);
2043 const ApproachingVehicleInformation& avi = foeLink->getApproaching(foe);
2044 const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
2045 STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
2046
2047 if ( // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
2048 ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
2049 // also ignore vehicles that are behind us and are able to brake for us
2050 couldBrakeForLeader(foeDist, dist, foe, ego) ||
2051 // resolve ties by lane index
2052 (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
2053#ifdef DEBUG_ZIPPER
2054 if (DEBUG_COND_ZIPPER) std::cout
2055 << " ignoring foe=" << foe->getID()
2056 << " foeAT=" << avi.arrivalTime
2057 << " foeDist=" << avi.dist
2058 << " foeDist2=" << foeDist
2059 << " foeSpeed=" << avi.speed
2060 << " egoSpeed=" << ego->getSpeed()
2061 << " deltaDist=" << foeDist - dist
2062 << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
2063 << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
2064 << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
2065 << "\n";
2066#endif
2067 continue;
2068 }
2069 // the idea behind speed adaption is three-fold:
2070 // 1) ego needs to be in a car-following relationship with foe eventually
2071 // thus, the ego speed should be equal to the follow speed once the foe enters
2072 // the zipper junction
2073 // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
2074 // achieving this distance can be spread over time but computing
2075 // safeGap is subject to estimation errors of future speeds
2076 // 3) deceleration can be spread out over the time until true
2077 // car-following happens, at the start of speed adaptions, smaller
2078 // decelerations should be sufficient
2079
2080 // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
2081 // lets try to extrapolate
2082 const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
2083 const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
2084 const double uEnd = MIN2(uMax, uAccel);
2085 const double uAvg = (avi.speed + uEnd) / 2;
2086 const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
2087 const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
2088
2089 const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
2090 const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
2091 const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxDecel());
2092 const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
2093 const double vAvg = (ego->getSpeed() + vEnd) / 2;
2094 const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
2095 const double te = MAX2(1.0, ceil((te0) / TS) * TS);
2096
2097 const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
2098 const double safeGap = ego->getCarFollowModel().getSecureGap(ego, foe, vEnd, uEnd, foe->getCarFollowModel().getMaxDecel());
2099 // round t to next step size
2100 // increase gap to safeGap by the time foe reaches link
2101 // gap + u*t - (t * v + a * t^2 / 2) = safeGap
2102 const double deltaGap = gap + tf * uAvg - safeGap - vAvg * tf;
2103 const double a = 2 * deltaGap / (tf * tf);
2104 const double vSafeGap = ego->getSpeed() + ACCEL2SPEED(a);
2105 const double vFollow = ego->getCarFollowModel().followSpeed(
2106 ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
2107
2108 // scale behavior based on ego time to link (te)
2109 const double w = MIN2(1.0, te / 10);
2110 const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
2111 const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), w * vSafeGap + (1 - w) * vFollow);
2112
2113 vSafe = MIN2(vSafe, vZipper);
2114#ifdef DEBUG_ZIPPER
2115 if (DEBUG_COND_ZIPPER) std::cout << " adapting to foe=" << foe->getID()
2116 << " foeDist=" << foeDist
2117 << " foeSpeed=" << avi.speed
2118 << " foeAS=" << avi.arrivalSpeed
2119 << " egoSpeed=" << ego->getSpeed()
2120 << " uMax=" << uMax
2121 << " uAccel=" << uAccel
2122 << " uEnd=" << uEnd
2123 << " uAvg=" << uAvg
2124 << " gap=" << gap
2125 << " safeGap=" << safeGap
2126 << "\n "
2127 << " tf=" << tf
2128 << " te=" << te
2129 << " dg=" << deltaGap
2130 << " aSafeGap=" << a
2131 << " vMax=" << vMax
2132 << " vAccel=" << vAccel
2133 << " vDecel=" << vDecel
2134 << " vEnd=" << vEnd
2135 << " vSafeGap=" << vSafeGap
2136 << " vFollow=" << vFollow
2137 << " w=" << w
2138 << " maxDecel=" << maxDecel
2139 << " vZipper=" << vZipper
2140 << " vSafe=" << vSafe
2141 << "\n";
2142#endif
2143 }
2144 return vSafe;
2145}
2146
2147
2148bool
2149MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
2150 return (// leader is ahead of follower
2151 followDist > leaderDist &&
2152 // and follower could brake for 1 s to stay behind leader
2153 followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
2154}
2155
2156
2157void
2162
2163bool
2165 // check whether this link gets to keep its cont status switching the tls off
2166 // @note: this could also be pre-computed in netconvert
2167 // we check whether there is any major link from this edge
2168 for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
2169 for (const MSLink* link : cand->getLinkCont()) {
2170 if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
2171 return true;
2172 }
2173 }
2174 }
2175 return false;
2176}
2177
2178bool
2179MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
2180 return fabs(posLat2 - posLat) < (width + width2) / 2;
2181}
2182
2183std::string
2185 return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
2186}
2187
2188
2189bool
2191 if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
2192 return false;
2193 }
2194 const SUMOVehicleParameter& param = ego->getParameter();
2195 for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
2196 if (typeID == foe->getVehicleType().getID()) {
2197 return true;
2198 }
2199 }
2200 for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
2201 if (id == foe->getID()) {
2202 return true;
2203 }
2204 }
2205 return false;
2206}
2207
2208
2209void
2213
2214
2215std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
2217 assert(getApproaching().size() > 0);
2218 double minDist = std::numeric_limits<double>::max();
2219 auto closestIt = getApproaching().begin();
2220 for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
2221 if (apprIt->second.dist < minDist) {
2222 minDist = apprIt->second.dist;
2223 closestIt = apprIt;
2224 }
2225 }
2226 // maybe a parallel link has a closer vehicle
2227 /*
2228 for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
2229 if (link2 != link) {
2230 for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
2231 if (apprIt2->second.dist < minDist) {
2232 minDist = apprIt2->second.dist;
2233 closestIt = apprIt2;
2234 }
2235 }
2236 }
2237 }
2238 */
2239 return *closestIt;
2240}
2241
2242
2243/****************************************************************************/
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
SumoXMLNodeType getType() const
return the type of this Junction
Definition MSJunction.h:133
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:2774
const MSLane * getNormalSuccessorLane() const
get normal lane following this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3171
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:2692
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2669
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:950
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3192
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:3136
bool isNormal() const
Definition MSLane.cpp:2552
bool isCrossing() const
Definition MSLane.cpp:2558
bool isInternal() const
Definition MSLane.cpp:2546
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:4300
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4565
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:3161
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:186
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:1190
virtual bool blockedAtDist(const SUMOTrafficObject *ego, const MSLane *lane, double vehCenter, 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:969
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:735
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