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