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