Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSLink.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Laura Bieker
19 : /// @date Sept 2002
20 : ///
21 : // A connection between lanes
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <iostream>
26 : #include <algorithm>
27 : #include <limits>
28 : #include <utils/iodevices/OutputDevice.h>
29 : #include <utils/common/RandHelper.h>
30 : #include <utils/common/StringTokenizer.h>
31 : #include "MSNet.h"
32 : #include "MSJunction.h"
33 : #include "MSJunctionLogic.h"
34 : #include "MSLink.h"
35 : #include "MSLane.h"
36 : #include <microsim/transportables/MSPerson.h>
37 : #include <microsim/transportables/MSTransportableControl.h>
38 : #include "MSEdge.h"
39 : #include "MSGlobals.h"
40 : #include "MSVehicle.h"
41 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
42 : #include <microsim/transportables/MSPModel.h>
43 :
44 : //#define MSLink_DEBUG_CROSSING_POINTS
45 : //#define MSLink_DEBUG_CROSSING_POINTS_DETAILS
46 : //#define MSLink_DEBUG_OPENED
47 : //#define DEBUG_APPROACHING
48 : //#define DEBUG_ZIPPER
49 : //#define DEBUG_WALKINGAREA
50 : //#define DEBUG_COND (myLane->getID()=="43[0]_0" && myLaneBefore->getID()==":33_0_0")
51 : //#define DEBUG_COND (myLane->getID()=="end_0")
52 : //#define DEBUG_COND (true)
53 : #define DEBUG_COND2(obj) (obj->isSelected())
54 : //#define DEBUG_COND2(obj) (obj->getID() == "train2")
55 : //#define DEBUG_COND_ZIPPER (gDebugFlag1)
56 : //#define DEBUG_COND_ZIPPER (true)
57 : #define DEBUG_COND_ZIPPER (ego->isSelected())
58 :
59 : // ===========================================================================
60 : // static member variables
61 : // ===========================================================================
62 :
63 : #define INVALID_TIME -1000
64 :
65 : // the default safety gap when passing before oncoming pedestrians
66 : #define JM_CROSSING_GAP_DEFAULT 10
67 :
68 : // minimim width between sibling lanes to qualify as non-overlapping
69 : #define DIVERGENCE_MIN_WIDTH 2.5
70 :
71 : const SUMOTime MSLink::myLookaheadTime = TIME2STEPS(1);
72 : // additional caution is needed when approaching a zipper link
73 : const SUMOTime MSLink::myLookaheadTimeZipper = TIME2STEPS(4);
74 : std::set<std::pair<MSLink*, MSLink*> > MSLink::myRecheck;
75 : const double MSLink::NO_INTERSECTION(10000);
76 :
77 : // ===========================================================================
78 : // ConflictInfo member method definitions
79 : // ===========================================================================
80 :
81 : double
82 351592532 : MSLink::ConflictInfo::getFoeLengthBehindCrossing(const MSLink* foeExitLink) const {
83 351592532 : if (flag == CONFLICT_DUMMY_MERGE) {
84 : return 0;
85 344751593 : } else if (foeConflictIndex >= 0) {
86 328594470 : return foeExitLink->myConflicts[foeConflictIndex].lengthBehindCrossing;
87 : } else {
88 : return -NO_INTERSECTION;
89 : }
90 : }
91 :
92 : double
93 197596182 : MSLink::ConflictInfo::getFoeConflictSize(const MSLink* foeExitLink) const {
94 197596182 : if (foeConflictIndex >= 0) {
95 181439059 : return foeExitLink->myConflicts[foeConflictIndex].conflictSize;
96 : } else {
97 : return 0;
98 : }
99 : }
100 :
101 : double
102 351605510 : MSLink::ConflictInfo::getLengthBehindCrossing(const MSLink* exitLink) const {
103 351605510 : if (flag == CONFLICT_STOP_AT_INTERNAL_JUNCTION) {
104 14868855 : return exitLink->getInternalLaneBefore()->getLength();
105 : } else {
106 336736655 : return lengthBehindCrossing;
107 : }
108 : }
109 :
110 : // ===========================================================================
111 : // member method definitions
112 : // ===========================================================================
113 2751925 : MSLink::MSLink(MSLane* predLane, MSLane* succLane, MSLane* via, LinkDirection dir, LinkState state,
114 : double length, double foeVisibilityDistance, bool keepClear,
115 : MSTrafficLightLogic* logic, int tlIndex,
116 2751925 : bool indirect) :
117 2751925 : myLane(succLane),
118 2751925 : myLaneBefore(predLane),
119 2751925 : myApproachingPersons(nullptr),
120 2751925 : myIndex(-1),
121 2751925 : myTLIndex(tlIndex),
122 2751925 : myLogic(logic),
123 2751925 : myState(state),
124 2751925 : myLastGreenState(LINKSTATE_TL_GREEN_MINOR),
125 2751925 : myOffState(state),
126 2751925 : myLastStateChange(SUMOTime_MIN / 2), // a large negative value, but avoid overflows when subtracting
127 2751925 : myDirection(dir),
128 2751925 : myLength(length),
129 2751925 : myFoeVisibilityDistance(foeVisibilityDistance),
130 2751925 : myDistToFoePedCrossing(std::numeric_limits<double>::max()),
131 2751925 : myHasFoes(false),
132 2751925 : myAmCont(false),
133 2751925 : myAmContOff(false),
134 2751925 : myKeepClear(keepClear),
135 2751925 : myInternalLane(via),
136 2751925 : myInternalLaneBefore(nullptr),
137 2751925 : myMesoTLSPenalty(0),
138 2751925 : myGreenFraction(1),
139 2751925 : myLateralShift(0),
140 2751925 : myOffFoeLinks(nullptr),
141 2751925 : myWalkingAreaFoe(nullptr),
142 2751925 : myWalkingAreaFoeExit(nullptr),
143 2751925 : myHavePedestrianCrossingFoe(false),
144 2751925 : myParallelRight(nullptr),
145 2751925 : myParallelLeft(nullptr),
146 2751925 : myAmIndirect(indirect),
147 2751925 : myRadius(std::numeric_limits<double>::max()),
148 2751925 : myPermissions(myLaneBefore->getPermissions() & myLane->getPermissions() & (via == nullptr ? SVCAll : via->getPermissions())),
149 2751925 : myJunction(nullptr) {
150 :
151 2751925 : if (MSGlobals::gLateralResolution > 0) {
152 : // detect lateral shift from lane geometries
153 : //std::cout << "DEBUG link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " hasInternal=" << MSNet::getInstance()->hasInternalLinks() << " shapeBefore=" << myLaneBefore->getShape().back() << " shapeFront=" << getViaLaneOrLane()->getShape().front() << "\n";
154 184371 : if ((myInternalLane != nullptr || predLane->isInternal())
155 444905 : && myLaneBefore->getShape().back() != getViaLaneOrLane()->getShape().front()) {
156 : PositionVector from = myLaneBefore->getShape();
157 : const PositionVector& to = getViaLaneOrLane()->getShape();
158 : const double dist = from.back().distanceTo2D(to.front());
159 : // figure out direction of shift
160 : try {
161 634 : from.move2side(dist);
162 0 : } catch (InvalidArgument&) {
163 0 : }
164 634 : myLateralShift = (from.back().distanceTo2D(to.front()) < dist) ? dist : -dist;
165 634 : if (MSGlobals::gLefthand) {
166 90 : myLateralShift *= -1;
167 : }
168 : //std::cout << " lateral shift link=" << myLaneBefore->getID() << "->" << getViaLaneOrLane()->getID() << " dist=" << dist << " shift=" << myLateralShift << "\n";
169 634 : }
170 : }
171 2751925 : }
172 :
173 :
174 2558205 : MSLink::~MSLink() {
175 2558205 : delete myOffFoeLinks;
176 2559778 : delete myApproachingPersons;
177 2558205 : }
178 :
179 :
180 : void
181 4 : MSLink::addCustomConflict(const MSLane* from, const MSLane* to, double startPos, double endPos) {
182 4 : myCustomConflicts.push_back(CustomConflict(from, to, startPos, endPos));
183 4 : }
184 :
185 : const MSLink::CustomConflict*
186 3416817 : MSLink::getCustomConflict(const MSLane* foeLane) const {
187 3416817 : if (myCustomConflicts.size() > 0) {
188 16 : const MSLane* foeFrom = foeLane->getNormalPredecessorLane();
189 16 : const MSLane* foeTo = foeLane->getNormalSuccessorLane();
190 24 : for (const CustomConflict& cc : myCustomConflicts) {
191 16 : if (cc.from == foeFrom && cc.to == foeTo) {
192 : return &cc;
193 : }
194 : }
195 :
196 : }
197 : return nullptr;
198 : }
199 :
200 : void
201 2547026 : MSLink::setRequestInformation(int index, bool hasFoes, bool isCont,
202 : const std::vector<MSLink*>& foeLinks,
203 : const std::vector<MSLane*>& foeLanes,
204 : MSLane* internalLaneBefore) {
205 : //#ifdef MSLink_DEBUG_CROSSING_POINTS
206 : // std::cout << " setRequestInformation() for junction " << getViaLaneOrLane()->getEdge().getFromJunction()->getID()
207 : // << "\nInternalLanes = " << toString(getViaLaneOrLane()->getEdge().getFromJunction()->getInternalLanes())
208 : // << std::endl;
209 : //#endif
210 2547026 : myIndex = index;
211 2547026 : myHasFoes = hasFoes;
212 2547026 : myAmCont = isCont;
213 2547026 : myFoeLinks = foeLinks;
214 8791379 : for (MSLane* foeLane : foeLanes) {
215 : // cannot assign vector due to const-ness
216 6244353 : myFoeLanes.push_back(foeLane);
217 : }
218 2547026 : myJunction = const_cast<MSJunction*>(myLane->getEdge().getFromJunction()); // junctionGraph is initialized after the whole network is loaded
219 2547026 : myAmContOff = isCont && myLogic != nullptr && internalLaneBefore == nullptr && checkContOff();
220 2547026 : myInternalLaneBefore = internalLaneBefore;
221 : MSLane* lane = nullptr;
222 : if (internalLaneBefore != nullptr) {
223 : // this is an exit link. compute crossing points with all foeLanes
224 : lane = internalLaneBefore;
225 : //} else if (myLane->getEdge().isCrossing()) {
226 : // // this is the link to a pedestrian crossing. compute crossing points with all foeLanes
227 : // // @note not currently used by pedestrians
228 : // lane = myLane;
229 : }
230 2547026 : const MSLink* entryLink = getCorrespondingEntryLink();
231 2547026 : if (entryLink->getOffState() == LinkState::LINKSTATE_ALLWAY_STOP && entryLink->getTLLogic() != nullptr) {
232 : // TLS has "normal" right of way rules but all conflicting links are foes when switching TLS off
233 : // (unless it's an internal junction link which should ignore all foes and should be ignored by all foes
234 3149 : myOffFoeLinks = new std::vector<MSLink*>();
235 3149 : if (isEntryLink()) {
236 7172 : for (MSLane* foeLane : foeLanes) {
237 : assert(foeLane->isInternal() || foeLane->isCrossing());
238 5744 : MSLink* viaLink = foeLane->getIncomingLanes().front().viaLink;
239 5744 : if (viaLink->getLaneBefore()->isNormal()) {
240 3826 : myOffFoeLinks->push_back(viaLink);
241 : }
242 : }
243 : }
244 : }
245 : #ifdef MSLink_DEBUG_CROSSING_POINTS
246 : std::cout << "link " << myIndex << " to " << getViaLaneOrLane()->getID() << " internalLaneBefore=" << (lane == 0 ? "NULL" : lane->getID()) << " has foes: " << toString(foeLanes) << "\n";
247 : #endif
248 2547026 : if (lane != nullptr) {
249 928804 : const bool beforeInternalJunction = lane->getLinkCont()[0]->getViaLaneOrLane()->getEdge().isInternal();
250 928804 : if (lane->getIncomingLanes().size() != 1) {
251 0 : throw ProcessError("Internal lane '" + lane->getID() + "' has " + toString(lane->getIncomingLanes().size()) + " predecessors");
252 : }
253 928804 : const MSLink* junctionEntryLink = lane->getEntryLink();
254 928804 : const bool isSecondPart = isExitLinkAfterInternalJunction();
255 : // compute crossing points
256 4439990 : for (const MSLane* foeLane : myFoeLanes) {
257 3511186 : const CustomConflict* cc = junctionEntryLink != nullptr ? junctionEntryLink->getCustomConflict(foeLane) : nullptr;
258 3416809 : if (cc != nullptr) {
259 : // handle custom conflict definition
260 8 : double startPos = cc->startPos;
261 8 : const double conflictSize = cc->endPos - cc->startPos;
262 8 : if (isSecondPart) {
263 0 : startPos -= junctionEntryLink->getViaLane()->getLength();
264 : }
265 : // the foe connection may be split at an internal
266 : // junction, we need to figure out whether the current
267 : // foeLane is the intended target for the custom conflict
268 : // There are two possibilities:
269 : // a) We have no custom conflict for the reverse pair of connections
270 : // -> just check whether lane and foeLane intersect
271 : // b) We have a "reverse" custom conflict
272 : // -> check whether it covers the foeLane
273 8 : const CustomConflict* rcc = foeLane->getEntryLink()->getCustomConflict(lane);
274 : bool haveIntersection = false;
275 8 : if (rcc == nullptr) {
276 : // a)
277 8 : haveIntersection = lane->getShape().intersectsAtLengths2D(foeLane->getShape()).size() > 0;
278 : } else {
279 : // b)
280 0 : const bool foeIsSecondPart = foeLane->getLogicalPredecessorLane()->isInternal();
281 0 : double foeStartPos = rcc->startPos;
282 0 : const double foeConflictSize = rcc->endPos - rcc->startPos;
283 0 : if (foeIsSecondPart) {
284 0 : foeStartPos -= foeLane->getLogicalPredecessorLane()->getLength();
285 : }
286 0 : const double foeEndPos = foeStartPos + foeConflictSize;
287 0 : haveIntersection = ((foeStartPos > 0 && foeStartPos < foeLane->getLength())
288 0 : || (foeEndPos > 0 && foeEndPos < foeLane->getLength()));
289 : }
290 8 : if (haveIntersection) {
291 4 : myConflicts.push_back(ConflictInfo(lane->getLength() - startPos, conflictSize));
292 : } else {
293 4 : myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0));
294 : }
295 : #ifdef MSLink_DEBUG_CROSSING_POINTS
296 : std::cout << " " << lane->getID() << " custom conflict with " << foeLane->getID() << " customReverse=" << (rcc != nullptr)
297 : << " haveIntersection=" << haveIntersection
298 : << " startPos=" << startPos << " conflictSize=" << conflictSize
299 : << " lbc=" << myConflicts.back().lengthBehindCrossing
300 : << "\n";
301 : #endif
302 8 : continue;
303 8 : }
304 3511178 : myHavePedestrianCrossingFoe = myHavePedestrianCrossingFoe || foeLane->getEdge().isCrossing();
305 3511178 : const bool sameTarget = myLane == foeLane->getLinkCont()[0]->getLane();
306 3511178 : if (sameTarget && !beforeInternalJunction && !contIntersect(lane, foeLane)) {
307 : //if (myLane == foeLane->getLinkCont()[0]->getLane()) {
308 : // this foeLane has the same target and merges at the end (lane exits the junction)
309 1251665 : const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + foeLane->getWidth()));
310 1251665 : if (lane->getShape().back().distanceTo2D(foeLane->getShape().back()) >= minDist) {
311 : // account for lateral shift by the entry links
312 109296 : if (foeLane->getEntryLink()->isIndirect()) {
313 25 : myConflicts.push_back(ConflictInfo(-NO_INTERSECTION, 0)); // dummy value, never used
314 : #ifdef MSLink_DEBUG_CROSSING_POINTS
315 : std::cout << " " << lane->getID() << " dummy merge with indirect" << foeLane->getID() << "\n";
316 : #endif
317 : } else {
318 109271 : myConflicts.push_back(ConflictInfo(0, foeLane->getWidth(), CONFLICT_DUMMY_MERGE)); // dummy value, never used
319 : #ifdef MSLink_DEBUG_CROSSING_POINTS
320 : std::cout << " " << lane->getID() << " dummy merge with " << foeLane->getID() << "\n";
321 : #endif
322 : }
323 : } else {
324 1142369 : const double distAfterDivergence = computeDistToDivergence(lane, foeLane, minDist, false);
325 : const double lbcLane = lane->interpolateGeometryPosToLanePos(distAfterDivergence);
326 1142369 : myConflicts.push_back(ConflictInfo(lbcLane, foeLane->getWidth()));
327 : #ifdef MSLink_DEBUG_CROSSING_POINTS
328 : std::cout
329 : << " " << lane->getID()
330 : << " merges with " << foeLane->getID()
331 : << " nextLane " << lane->getLinkCont()[0]->getViaLaneOrLane()->getID()
332 : << " dist1=" << myConflicts.back().lengthBehindCrossing
333 : << "\n";
334 : #endif
335 : }
336 : } else {
337 2259513 : std::vector<double> intersections1 = lane->getShape().intersectsAtLengths2D(foeLane->getShape());
338 : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
339 : std::cout << " intersections1=" << toString(intersections1) << "\n";
340 : #endif
341 : bool haveIntersection = true;
342 2259513 : if (intersections1.size() == 0) {
343 1139738 : intersections1.push_back(-NO_INTERSECTION); // disregard this foe (using maxdouble leads to nasty problems down the line)
344 : haveIntersection = false;
345 1119775 : } else if (intersections1.size() > 1) {
346 1277 : std::sort(intersections1.begin(), intersections1.end());
347 : }
348 2259513 : std::vector<double> intersections2 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
349 : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
350 : std::cout << " intersections2=" << toString(intersections2) << "\n";
351 : #endif
352 2259513 : if (intersections2.size() == 0) {
353 1139738 : intersections2.push_back(0);
354 1119775 : } else if (intersections2.size() > 1) {
355 1277 : std::sort(intersections2.begin(), intersections2.end());
356 : }
357 : double conflictSize = foeLane->getWidth();
358 : ConflictFlag flag = CONFLICT_NO_INTERSECTION;
359 2259513 : if (haveIntersection) {
360 : flag = CONFLICT_DEFAULT;
361 1119775 : const double angle1 = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(intersections1.back()));
362 1119775 : const double angle2 = GeomHelper::naviDegree(foeLane->getShape().rotationAtOffset(intersections2.back()));
363 1119775 : const double angleDiff = GeomHelper::getMinAngleDiff(angle1, angle2);
364 : //const double angleDiff = MIN2(GeomHelper::getMinAngleDiff(angle1, angle2),
365 : // GeomHelper::getMinAngleDiff(angle1, angle2 + 180));
366 1119775 : const double widthFactor = 1 / MAX2(sin(DEG2RAD(angleDiff)), 0.2) * 2 - 1;
367 : //std::cout << " intersection of " << lane->getID() << " with " << foeLane->getID() << " angle1=" << angle1 << " angle2=" << angle2 << " angleDiff=" << angleDiff << " widthFactor=" << widthFactor << "\n";
368 1119775 : conflictSize *= widthFactor;
369 : conflictSize = MIN2(conflictSize, lane->getLength());
370 : // lane width affects the crossing point
371 1119775 : intersections1.back() -= conflictSize / 2;
372 : // ensure non-negative offset for weird geometries
373 1119775 : intersections1.back() = MAX2(0.0, intersections1.back());
374 :
375 : // also length/geometry factor. (XXX: Why subtract width/2 *before* converting geometric position to lane pos? refs #3031)
376 1119775 : intersections1.back() = lane->interpolateGeometryPosToLanePos(intersections1.back());
377 :
378 1119775 : if (internalLaneBefore->getLogicalPredecessorLane()->getEdge().isInternal() && !foeLane->getEdge().isCrossing()) {
379 : flag = CONFLICT_STOP_AT_INTERNAL_JUNCTION;
380 : }
381 :
382 1119775 : if (foeLane->getEdge().isCrossing()) {
383 88360 : const_cast<MSLink*>(getCorrespondingEntryLink())->updateDistToFoePedCrossing(intersections1.back());
384 : };
385 : }
386 :
387 2259513 : myConflicts.push_back(ConflictInfo(
388 2259513 : lane->getLength() - intersections1.back(),
389 : conflictSize, flag));
390 :
391 : #ifdef MSLink_DEBUG_CROSSING_POINTS
392 : std::cout
393 : << " intersection of " << lane->getID()
394 : << " totalLength=" << lane->getLength()
395 : << " with " << foeLane->getID()
396 : << " totalLength=" << foeLane->getLength()
397 : << " dist1=" << myConflicts.back().lengthBehindCrossing
398 : << " widthFactor=" << myConflicts.back().conflictSize / foeLane->getWidth()
399 : << "\n";
400 : #endif
401 2259513 : }
402 : }
403 : // check for overlap with internal lanes from the same source lane
404 928804 : const MSLane* pred = lane->getLogicalPredecessorLane();
405 : // to avoid overlap with vehicles that came from pred (especially when pred has endOffset > 0)
406 : // we add all other internal lanes from pred as foeLanes
407 2823609 : for (const MSLink* const link : pred->getLinkCont()) {
408 1894805 : const MSLane* const sibling = link->getViaLane();
409 1894805 : if (sibling != lane && sibling != nullptr) {
410 944094 : const double minDist = MIN2(DIVERGENCE_MIN_WIDTH, 0.5 * (lane->getWidth() + sibling->getWidth()));
411 944094 : if (lane->getShape().front().distanceTo2D(sibling->getShape().front()) >= minDist) {
412 : // account for lateral shift by the entry links
413 616 : continue;
414 : }
415 943478 : const double distToDivergence = computeDistToDivergence(lane, sibling, minDist, true);
416 : double lbcLane;
417 943478 : if (lane->getLength() == sibling->getLength() && &lane->getEdge() == &sibling->getEdge()) {
418 : // for parallel lanes, avoid inconsistency in distance estimation (#10988)
419 : // between forward distance (getLeaderInfo)
420 : // and backward distance used in lane-changing (getFollowersOnConsecutive)
421 60590 : lbcLane = lane->getLength() - distToDivergence;
422 : } else {
423 882888 : lbcLane = MAX2(0.0, lane->getLength() - lane->interpolateGeometryPosToLanePos(distToDivergence));
424 : }
425 : ConflictInfo ci = ConflictInfo(lbcLane, sibling->getWidth());
426 943478 : auto it = std::find(myFoeLanes.begin(), myFoeLanes.end(), sibling);
427 943478 : if (it != myFoeLanes.end()) {
428 : // avoid duplicate foeLane
429 50 : const int replacedIndex = (int)(it - myFoeLanes.begin());
430 50 : myConflicts[replacedIndex] = ci;
431 : } else {
432 943428 : myConflicts.push_back(ci);
433 943428 : myFoeLanes.push_back(sibling);
434 : }
435 : #ifdef MSLink_DEBUG_CROSSING_POINTS
436 : std::cout << " adding same-origin foe" << sibling->getID()
437 : << " dist1=" << myConflicts.back().lengthBehindCrossing
438 : << "\n";
439 : #endif
440 : }
441 : }
442 : // init points for the symmetrical conflict
443 : // for each pair of conflicting lanes, the link that gets second, sets the pointers
444 5383418 : for (int i = 0; i < (int)myFoeLanes.size(); i++) {
445 4454614 : const MSLane* foeLane = myFoeLanes[i];
446 4454614 : MSLink* foeExitLink = foeLane->getLinkCont()[0];
447 : int foundIndex = -1;
448 16593977 : for (int i2 = 0; i2 < (int)foeExitLink->myFoeLanes.size(); i2++) {
449 14145660 : if (foeExitLink->myFoeLanes[i2] == lane) {
450 2006297 : myConflicts[i].foeConflictIndex = i2;
451 2006297 : foeExitLink->myConflicts[i2].foeConflictIndex = i;
452 2006297 : myRecheck.erase({foeExitLink, this});
453 : foundIndex = i2;
454 2006297 : break;
455 : }
456 : }
457 : #ifdef MSLink_DEBUG_CROSSING_POINTS
458 : std::cout << lane->getID() << " foeLane=" << foeLane->getID() << " index=" << i << " foundIndex=" << foundIndex << "\n";
459 : #endif
460 4454614 : if (foundIndex < 0) {
461 2448317 : if (myConflicts[i].flag != CONFLICT_NO_INTERSECTION) {
462 1714333 : myRecheck.insert({this, foeExitLink});
463 : }
464 : }
465 : }
466 : }
467 2547026 : if (MSGlobals::gLateralResolution > 0) {
468 : // check for links with the same origin lane and the same destination edge
469 261040 : const MSEdge* myTarget = &myLane->getEdge();
470 : // save foes for entry links
471 835030 : for (MSLink* const it : myLaneBefore->getLinkCont()) {
472 : const MSEdge* target = &(it->getLane()->getEdge());
473 573990 : if (it == this) {
474 261040 : continue;
475 : }
476 312950 : if (target == myTarget) {
477 6390 : mySublaneFoeLinks.push_back(it);
478 : #ifdef MSLink_DEBUG_CROSSING_POINTS
479 : std::cout << " sublaneFoeLink (same target): " << it->getViaLaneOrLane()->getID() << "\n";
480 : #endif
481 306560 : } else if (myDirection != LinkDirection::STRAIGHT && it->getDirection() == LinkDirection::STRAIGHT) {
482 : // potential turn conflict
483 74641 : mySublaneFoeLinks2.push_back(it);
484 : #ifdef MSLink_DEBUG_CROSSING_POINTS
485 : std::cout << " sublaneFoeLink2 (other target: " << it->getViaLaneOrLane()->getID() << "\n";
486 : #endif
487 : }
488 : }
489 : // save foes for exit links
490 261040 : if (fromInternalLane()) {
491 : //std::cout << " setRequestInformation link=" << getViaLaneOrLane()->getID() << " before=" << myLaneBefore->getID() << " before2=" << myLaneBefore->getIncomingLanes().front().lane->getID() << "\n";
492 312648 : for (const MSLink* const link : myLaneBefore->getIncomingLanes().front().lane->getLinkCont()) {
493 219726 : if (link->getViaLane() != myInternalLaneBefore && &link->getLane()->getEdge() == myTarget) {
494 : //std::cout << " add sublaneFoe=" << (*it)->getViaLane()->getID() << "\n";
495 3966 : mySublaneFoeLanes.push_back(link->getViaLane());
496 : }
497 : }
498 : }
499 : }
500 2547026 : if (myInternalLaneBefore != nullptr
501 928804 : && myDirection != LinkDirection::STRAIGHT
502 : // for right turns, the curvature helps rather than restricts the linkLeader check
503 407703 : && (
504 407703 : (!MSGlobals::gLefthand && myDirection != LinkDirection::RIGHT)
505 123906 : || (MSGlobals::gLefthand && myDirection != LinkDirection::LEFT))) {
506 568424 : const double angle = fabs(GeomHelper::angleDiff(
507 284212 : myLaneBefore->getNormalPredecessorLane()->getShape().angleAt2D(-2),
508 284212 : myLane->getShape().angleAt2D(0)));
509 284212 : if (angle > 0) {
510 284212 : double length = myInternalLaneBefore->getShape().length2D();
511 568424 : if (myInternalLaneBefore->getIncomingLanes().size() == 1 &&
512 284212 : myInternalLaneBefore->getIncomingLanes()[0].lane->isInternal()) {
513 76574 : length += myInternalLaneBefore->getIncomingLanes()[0].lane->getShape().length2D();
514 207638 : } else if (myInternalLane != nullptr) {
515 76574 : length += myInternalLane->getShape().length2D();
516 : }
517 284212 : myRadius = length / angle;
518 : //std::cout << getDescription() << " a=" << RAD2DEG(angle) << " l=" << length << " r=" << myRadius << "\n";
519 : }
520 : }
521 2547026 : }
522 :
523 :
524 : void
525 42320 : MSLink::recheckSetRequestInformation() {
526 70681 : for (auto item : myRecheck) {
527 : #ifdef MSLink_DEBUG_CROSSING_POINTS
528 : std::cout << " recheck l1=" << item.first->getDescription() << " l2=" << item.second->getDescription() << "\n";
529 : #endif
530 : MSLink* link = item.first;
531 : MSLink* foeExitLink = item.second;
532 : const MSLane* lane = link->getInternalLaneBefore();
533 : const MSLane* foeLane = foeExitLink->getInternalLaneBefore();
534 : int conflictIndex = -1;
535 185221 : for (int i = 0; i < (int)link->myFoeLanes.size(); i++) {
536 185221 : if (link->myFoeLanes[i] == foeLane) {
537 : conflictIndex = i;
538 : break;
539 : }
540 : }
541 28361 : if (conflictIndex == -1) {
542 0 : WRITE_WARNING("Could not recheck ConflictInfo for " + link->getDescription() + " and " + foeExitLink->getDescription() + "\n");
543 72 : continue;
544 : }
545 28361 : ConflictInfo& ci = link->myConflicts[conflictIndex];
546 28361 : std::vector<double> intersections1 = foeLane->getShape().intersectsAtLengths2D(lane->getShape());
547 28361 : if (intersections1.size() == 0) {
548 : #ifdef MSLink_DEBUG_CROSSING_POINTS
549 : std::cout << " no intersection\n";
550 : #endif
551 : continue;
552 : }
553 28289 : const double widthFactor = ci.conflictSize / foeLane->getWidth();
554 28289 : const double conflictSize2 = lane->getWidth() * widthFactor;
555 28289 : std::sort(intersections1.begin(), intersections1.end());
556 28289 : intersections1.back() -= conflictSize2 / 2;
557 28289 : intersections1.back() = MAX2(0.0, intersections1.back());
558 28289 : ci.foeConflictIndex = (int)foeExitLink->myConflicts.size();
559 28289 : foeExitLink->myConflicts.push_back(ConflictInfo(foeLane->getLength() - intersections1.back(), conflictSize2));
560 : #ifdef MSLink_DEBUG_CROSSING_POINTS
561 : std::cout << " ci=" << conflictIndex << " wf=" << widthFactor << " flag=" << ci.flag << " flbc=" << foeExitLink->myConflicts.back().lengthBehindCrossing << "\n";
562 : #endif
563 28361 : }
564 : myRecheck.clear();
565 42320 : }
566 :
567 : double
568 2085847 : MSLink::computeDistToDivergence(const MSLane* lane, const MSLane* sibling, double minDist, bool sameSource) const {
569 : double lbcSibling = 0;
570 : double lbcLane = 0;
571 :
572 : PositionVector l = lane->getShape();
573 : PositionVector s = sibling->getShape();
574 2085847 : double length = l.length2D();
575 2085847 : double sibLength = s.length2D();
576 2085847 : if (!sameSource) {
577 2284738 : l = l.reverse();
578 2284738 : s = s.reverse();
579 943478 : } else if (sibling->getEntryLink()->myAmIndirect) {
580 : // ignore final waiting position since it may be quite close to the lane
581 : // shape but the waiting position is perpendicular (so the minDist
582 : // requirement is not necessary
583 54 : lbcSibling += s[-1].distanceTo2D(s[-2]);
584 : s.pop_back();
585 943424 : } else if (lane->getEntryLink()->myAmIndirect) {
586 : // ignore final waiting position since it may be quite close to the lane
587 : // shape but the waiting position is perpendicular (so the minDist
588 : // requirement is not necessary
589 54 : lbcLane += l[-1].distanceTo2D(l[-2]);
590 : l.pop_back();
591 : }
592 :
593 : #ifdef MSLink_DEBUG_CROSSING_POINTS_DETAILS
594 : std::cout << " sameSource=" << sameSource << " minDist=" << minDist << " backDist=" << l.back().distanceTo2D(s.back()) << "\n";
595 : #endif
596 2085847 : if (l.back().distanceTo2D(s.back()) > minDist) {
597 : // compute the final divergence point
598 : // this position serves two purposes:
599 : // 1) once the foe vehicle back (on sibling) has passed this point, we can safely ignore it
600 : // 2) both vehicles are put into a cf-relationship while before the point.
601 : // Since the actual crossing point is at the start of the junction,
602 : // we want to make sure that both vehicles have the same distance to the crossing point and thus follow each other naturally
603 2041449 : std::vector<double> distances = l.distances(s);
604 : #ifdef MSLink_DEBUG_CROSSING_POINTS
605 : std::cout << " distances=" << toString(distances) << "\n";
606 : #endif
607 : assert(distances.size() == l.size() + s.size());
608 2041449 : if (distances.back() > minDist && distances[l.size() - 1] > minDist) {
609 : // do a pairwise check between lane and sibling to make because we do not know which of them bends more
610 2156821 : for (int j = (int)s.size() - 2; j >= 0; j--) {
611 2156821 : const int i = j + (int)l.size();
612 2156821 : const double segLength = s[j].distanceTo2D(s[j + 1]);
613 2156821 : if (distances[i] > minDist) {
614 957452 : lbcSibling += segLength;
615 : } else {
616 : // assume no sharp bends and just interpolate the last segment
617 1199369 : lbcSibling += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
618 1199369 : break;
619 : }
620 : }
621 2157157 : for (int i = (int)l.size() - 2; i >= 0; i--) {
622 2157157 : const double segLength = l[i].distanceTo2D(l[i + 1]);
623 2157157 : if (distances[i] > minDist) {
624 957788 : lbcLane += segLength;
625 : } else {
626 : // assume no sharp bends and just interpolate the last segment
627 1199369 : lbcLane += segLength - (minDist - distances[i]) * segLength / (distances[i + 1] - distances[i]);
628 1199369 : break;
629 : }
630 : }
631 : }
632 : assert(lbcSibling >= -NUMERICAL_EPS);
633 : assert(lbcLane >= -NUMERICAL_EPS);
634 2041449 : }
635 2085847 : const double distToDivergence1 = sibling->getLength() - lbcSibling;
636 2085847 : const double distToDivergence2 = lane->getLength() - lbcLane;
637 : const double distToDivergence = MIN3(
638 : MAX2(distToDivergence1, distToDivergence2),
639 : sibLength, length);
640 : #ifdef MSLink_DEBUG_CROSSING_POINTS
641 : std::cout << " distToDivergence=" << distToDivergence
642 : << " distTD1=" << distToDivergence1
643 : << " distTD2=" << distToDivergence2
644 : << " length=" << length
645 : << " sibLength=" << sibLength
646 : << "\n";
647 : #endif
648 2085847 : return distToDivergence;
649 2085847 : }
650 :
651 :
652 : bool
653 1251825 : MSLink::contIntersect(const MSLane* lane, const MSLane* foe) {
654 1251825 : if (foe->getLinkCont()[0]->getViaLane() != nullptr) {
655 109721 : std::vector<double> intersections = lane->getShape().intersectsAtLengths2D(foe->getShape());
656 109721 : return intersections.size() > 0;
657 109721 : }
658 : return false;
659 : }
660 :
661 :
662 : void
663 771283125 : MSLink::setApproaching(const SUMOVehicle* approaching, const SUMOTime arrivalTime, const double arrivalSpeed, const double leaveSpeed,
664 : const bool setRequest, const double arrivalSpeedBraking, const SUMOTime waitingTime, double dist, double latOffset) {
665 771283125 : const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, approaching->getVehicleType().getLength());
666 : #ifdef DEBUG_APPROACHING
667 : if (DEBUG_COND2(approaching)) {
668 : std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
669 : for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
670 : std::cout << "'" << i->first->getID() << "'" << std::endl;
671 : }
672 : }
673 : #endif
674 : myApproachingVehicles.emplace(approaching,
675 1542566250 : ApproachingVehicleInformation(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, setRequest,
676 771283125 : arrivalSpeedBraking, waitingTime, dist, approaching->getSpeed(), latOffset));
677 771283125 : }
678 :
679 :
680 : void
681 1030657 : MSLink::setApproaching(const SUMOVehicle* approaching, ApproachingVehicleInformation ai) {
682 :
683 : #ifdef DEBUG_APPROACHING
684 : if (DEBUG_COND2(approaching)) {
685 : std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << "' Adding approaching vehicle '" << approaching->getID() << "'\nCurrently registered vehicles:" << std::endl;
686 : for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
687 : std::cout << "'" << i->first->getID() << "'" << std::endl;
688 : }
689 : }
690 : #endif
691 : myApproachingVehicles.emplace(approaching, ai);
692 1030657 : }
693 :
694 : void
695 535883 : MSLink::setApproachingPerson(const MSPerson* approaching, const SUMOTime arrivalTime, const SUMOTime leaveTime) {
696 535883 : if (myApproachingPersons == nullptr) {
697 1573 : myApproachingPersons = new PersonApproachInfos();
698 : }
699 535883 : myApproachingPersons->emplace(approaching, ApproachingPersonInformation(arrivalTime, leaveTime));
700 535883 : }
701 :
702 : void
703 770830892 : MSLink::removeApproaching(const SUMOVehicle* veh) {
704 :
705 : #ifdef DEBUG_APPROACHING
706 : if (DEBUG_COND2(veh)) {
707 : std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
708 : std::cout << "' Removing approaching vehicle '" << veh->getID() << "'\nCurrently registered vehicles:" << std::endl;
709 : for (auto i = myApproachingVehicles.begin(); i != myApproachingVehicles.end(); ++i) {
710 : std::cout << "'" << i->first->getID() << "'" << std::endl;
711 : }
712 : }
713 : #endif
714 : myApproachingVehicles.erase(veh);
715 770830892 : }
716 :
717 :
718 : void
719 30706 : MSLink::removeApproachingPerson(const MSPerson* person) {
720 30706 : if (myApproachingPersons == nullptr) {
721 16 : WRITE_WARNINGF("Person '%' entered crossing lane '%' without registering approach, time=%", person->getID(), myLane->getID(), time2string(SIMSTEP));
722 4 : return;
723 : }
724 : #ifdef DEBUG_APPROACHING
725 : if (DEBUG_COND2(person)) {
726 : std::cout << SIMTIME << " Link '" << (myLaneBefore == 0 ? "NULL" : myLaneBefore->getID()) << "'->'" << (myLane == 0 ? "NULL" : myLane->getID()) << std::endl;
727 : std::cout << "' Removing approaching person '" << person->getID() << "'\nCurrently registered persons:" << std::endl;
728 : for (auto i = myApproachingPersons->begin(); i != myApproachingPersons->end(); ++i) {
729 : std::cout << "'" << i->first->getID() << "'" << std::endl;
730 : }
731 : }
732 : #endif
733 : myApproachingPersons->erase(person);
734 : }
735 :
736 :
737 : MSLink::ApproachingVehicleInformation
738 25705363 : MSLink::getApproaching(const SUMOVehicle* veh) const {
739 : auto i = myApproachingVehicles.find(veh);
740 25705363 : if (i != myApproachingVehicles.end()) {
741 23039265 : return i->second;
742 : } else {
743 : return ApproachingVehicleInformation(INVALID_TIME, INVALID_TIME, 0, 0, false, 0, 0, 0, 0, 0);
744 : }
745 : }
746 :
747 :
748 : void
749 13088 : MSLink::clearState() {
750 : myApproachingVehicles.clear();
751 13088 : }
752 :
753 :
754 : SUMOTime
755 1372153258 : MSLink::getLeaveTime(const SUMOTime arrivalTime, const double arrivalSpeed,
756 : const double leaveSpeed, const double vehicleLength) const {
757 1403544745 : return arrivalTime == SUMOTime_MAX ? SUMOTime_MAX : arrivalTime + TIME2STEPS((getLength() + vehicleLength) / MAX2(0.5 * (arrivalSpeed + leaveSpeed), NUMERICAL_EPS));
758 : }
759 :
760 :
761 : bool
762 604037984 : MSLink::opened(SUMOTime arrivalTime, double arrivalSpeed, double leaveSpeed, double vehicleLength,
763 : double impatience, double decel, SUMOTime waitingTime, double posLat,
764 : BlockingFoes* collectFoes, bool ignoreRed, const SUMOTrafficObject* ego, double dist) const {
765 : #ifdef MSLink_DEBUG_OPENED
766 : if (gDebugFlag1) {
767 : std::cout << SIMTIME << " opened? link=" << getDescription() << " red=" << haveRed() << " cont=" << isCont() << " numFoeLinks=" << myFoeLinks.size() << " havePrio=" << havePriority() << " lastWasContMajorGreen=" << lastWasContState(LINKSTATE_TL_GREEN_MAJOR) << "\n";
768 : }
769 : #endif
770 604037984 : if (haveRed() && !ignoreRed) {
771 : return false;
772 : }
773 603151243 : if (isCont() && MSGlobals::gUsingInternalLanes) {
774 : return true;
775 : }
776 600131233 : const SUMOTime leaveTime = getLeaveTime(arrivalTime, arrivalSpeed, leaveSpeed, vehicleLength);
777 600131233 : if (MSGlobals::gLateralResolution > 0) {
778 : // check for foes on the same lane with the same target edge
779 127210605 : for (const MSLink* foeLink : mySublaneFoeLinks) {
780 : assert(myLane != foeLink->getLane());
781 9549726 : for (const auto& it : foeLink->myApproachingVehicles) {
782 6523589 : const SUMOVehicle* foe = it.first;
783 : if (
784 : // there only is a conflict if the paths cross
785 7020226 : ((posLat < foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() > foeLink->myLane->getIndex())
786 6314989 : || (posLat > foe->getLateralPositionOnLane() + it.second.latOffset && myLane->getIndex() < foeLink->myLane->getIndex()))
787 : // the vehicle that arrives later must yield
788 7031991 : && (arrivalTime > it.second.arrivalTime
789 : // if both vehicles arrive at the same time, the one
790 : // to the left must yield
791 325366 : || (arrivalTime == it.second.arrivalTime && posLat > foe->getLateralPositionOnLane()))) {
792 183679 : if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
793 : impatience, decel, waitingTime, ego)) {
794 : #ifdef MSLink_DEBUG_OPENED
795 : if (gDebugFlag1) {
796 : std::cout << SIMTIME << " blocked by " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
797 : }
798 : #endif
799 39373 : if (collectFoes == nullptr) {
800 : #ifdef MSLink_DEBUG_OPENED
801 : if (gDebugFlag1) {
802 : std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
803 : }
804 : #endif
805 : return false;
806 : } else {
807 0 : collectFoes->push_back(it.first);
808 : }
809 : }
810 : }
811 : }
812 : }
813 : // check for foes on the same lane with a different target edge
814 : // (straight movers take precedence if the paths cross)
815 124145095 : const int lhSign = MSGlobals::gLefthand ? -1 : 1;
816 125326973 : for (const MSLink* foeLink : mySublaneFoeLinks2) {
817 : assert(myDirection != LinkDirection::STRAIGHT);
818 5425932 : for (const auto& it : foeLink->myApproachingVehicles) {
819 4244054 : const SUMOVehicle* foe = it.first;
820 : // there only is a conflict if the paths cross
821 : // and if the vehicles are not currently in a car-following relationship
822 4244054 : const double egoWidth = ego == nullptr ? 1.8 : ego->getVehicleType().getWidth();
823 4244054 : if (!lateralOverlap(posLat, egoWidth, foe->getLateralPositionOnLane() + it.second.latOffset, foe->getVehicleType().getWidth())
824 4244054 : && (((myDirection == LinkDirection::RIGHT || myDirection == LinkDirection::PARTRIGHT)
825 461931 : && (posLat * lhSign > (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign))
826 434339 : || ((myDirection == LinkDirection::LEFT || myDirection == LinkDirection::PARTLEFT)
827 41903 : && (posLat * lhSign < (foe->getLateralPositionOnLane() + it.second.latOffset) * lhSign)))) {
828 71979 : if (blockedByFoe(foe, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, false,
829 : impatience, decel, waitingTime, ego)) {
830 : #ifdef MSLink_DEBUG_OPENED
831 : if (gDebugFlag1) {
832 : std::cout << SIMTIME << " blocked by sublane foe " << foe->getID() << " arrival=" << arrivalTime << " foeArrival=" << it.second.arrivalTime << "\n";
833 : }
834 : #endif
835 8621 : if (collectFoes == nullptr) {
836 : #ifdef MSLink_DEBUG_OPENED
837 : if (gDebugFlag1) {
838 : std::cout << " link=" << getViaLaneOrLane()->getID() << " blocked by sublaneFoe2=" << foe->getID() << " foeLink=" << foeLink->getViaLaneOrLane()->getID() << " posLat=" << posLat << "\n";
839 : }
840 : #endif
841 : return false;
842 : } else {
843 0 : collectFoes->push_back(it.first);
844 : }
845 : }
846 : }
847 : }
848 : }
849 : }
850 600083239 : if ((havePriority() || lastWasContState(LINKSTATE_TL_GREEN_MAJOR)) && myState != LINKSTATE_ZIPPER) {
851 : // priority usually means the link is open but there are exceptions:
852 : // zipper still needs to collect foes
853 : // sublane model could have detected a conflict
854 573425278 : return collectFoes == nullptr || collectFoes->size() == 0;
855 : }
856 26657961 : if (myState == LINKSTATE_ALLWAY_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_ALLWAYSTOP_WAIT, TS))) {
857 : return false;
858 25618640 : } else if (myState == LINKSTATE_STOP && waitingTime < TIME2STEPS(ego == nullptr ? TS : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPSIGN_WAIT, TS))) {
859 : return false;
860 : }
861 :
862 25588112 : const std::vector<MSLink*>& foeLinks = (myOffFoeLinks == nullptr || getCorrespondingEntryLink()->getState() != LINKSTATE_ALLWAY_STOP) ? myFoeLinks : *myOffFoeLinks;
863 : #ifdef MSLink_DEBUG_OPENED
864 : if (gDebugFlag1) {
865 : std::cout << SIMTIME << " opened link=" << getViaLaneOrLane()->getID() << " foeLinks=" << foeLinks.size() << "\n";
866 : }
867 : #endif
868 :
869 25588112 : if (MSGlobals::gUseMesoSim && impatience == 1) {
870 : return true;
871 : }
872 25587574 : const bool lastWasContRed = lastWasContState(LINKSTATE_TL_RED);
873 71236478 : for (const MSLink* const link : foeLinks) {
874 50033390 : if (MSGlobals::gUseMesoSim) {
875 1903360 : if (link->haveRed()) {
876 46444 : continue;
877 : }
878 : }
879 : #ifdef MSLink_DEBUG_OPENED
880 : if (gDebugFlag1) {
881 : std::cout << SIMTIME << " foeLink=" << link->getViaLaneOrLane()->getID() << " numApproaching=" << link->getApproaching().size() << "\n";
882 : if (link->getLane()->isCrossing()) {
883 : std::cout << SIMTIME << " approachingPersons=" << (link->myApproachingPersons == nullptr ? "NULL" : toString(link->myApproachingPersons->size())) << "\n";
884 : }
885 : }
886 : #endif
887 49986946 : if (link->blockedAtTime(arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, myLane == link->getLane(),
888 : impatience, decel, waitingTime, collectFoes, ego, lastWasContRed, dist)) {
889 : return false;
890 : }
891 : }
892 21203088 : if (collectFoes != nullptr && collectFoes->size() > 0) {
893 : return false;
894 : }
895 : return true;
896 : }
897 :
898 :
899 : bool
900 49999447 : MSLink::blockedAtTime(SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
901 : bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
902 : BlockingFoes* collectFoes, const SUMOTrafficObject* ego, bool lastWasContRed, double dist) const {
903 185754428 : for (const auto& it : myApproachingVehicles) {
904 : #ifdef MSLink_DEBUG_OPENED
905 : if (gDebugFlag1) {
906 : if (ego != nullptr
907 : && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) >= it.second.speed
908 : && ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) > 0) {
909 : std::stringstream stream; // to reduce output interleaving from different threads
910 : stream << SIMTIME << " " << myApproachingVehicles.size() << " foe link=" << getViaLaneOrLane()->getID()
911 : << " foeVeh=" << it.first->getID() << " (below ignore speed)"
912 : << " ignoreFoeProb=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0)
913 : << "\n";
914 : std::cout << stream.str();
915 : }
916 : }
917 : #endif
918 140022580 : if (it.first != ego
919 140017546 : && (ego == nullptr
920 140006023 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
921 17880 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.second.speed
922 1278 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
923 140016424 : && !ignoreFoe(ego, it.first)
924 140016182 : && (!lastWasContRed || it.first->getSpeed() > SUMO_const_haltingSpeed)
925 280019872 : && blockedByFoe(it.first, it.second, arrivalTime, leaveTime, arrivalSpeed, leaveSpeed, sameTargetLane,
926 : impatience, decel, waitingTime, ego)) {
927 6267042 : if (collectFoes == nullptr) {
928 : return true;
929 : } else {
930 1999443 : collectFoes->push_back(it.first);
931 : }
932 : }
933 : }
934 45731848 : if (myApproachingPersons != nullptr && !haveRed()) {
935 961694 : for (const auto& it : *myApproachingPersons) {
936 : if ((ego == nullptr
937 213907 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) == 0
938 600 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_SPEED, 0) < it.first->getSpeed()
939 600 : || ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_FOE_PROB, 0) < RandHelper::rand(ego->getRNG()))
940 213307 : && !ignoreFoe(ego, it.first)
941 427134 : && !((arrivalTime > it.second.leavingTime) || (leaveTime < it.second.arrivalTime))) {
942 : // check whether braking is feasible (ego might have started to accelerate already)
943 128667 : const auto& cfm = ego->getVehicleType().getCarFollowModel();
944 : #ifdef MSLink_DEBUG_OPENED
945 : if (gDebugFlag1) {
946 : std::cout << SIMTIME << ": " << ego->getID() << " conflict with person " << it.first->getID() << " aTime=" << arrivalTime << " foeATime=" << it.second.arrivalTime << " dist=" << dist << " bGap=" << cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0) << "\n";
947 : }
948 : #endif
949 128667 : if (dist > cfm.brakeGap(ego->getSpeed(), cfm.getMaxDecel(), 0)) {
950 : #ifdef MSLink_DEBUG_OPENED
951 : if (gDebugFlag1) {
952 : std::cout << SIMTIME << ": " << ego->getID() << " blocked by person " << it.first->getID() << "\n";
953 : }
954 : #endif
955 117967 : if (collectFoes == nullptr) {
956 : return true;
957 : } else {
958 0 : collectFoes->push_back(it.first);
959 : }
960 : }
961 : }
962 : }
963 : }
964 : return false;
965 : }
966 :
967 :
968 : bool
969 140252950 : MSLink::blockedByFoe(const SUMOVehicle* veh, const ApproachingVehicleInformation& avi,
970 : SUMOTime arrivalTime, SUMOTime leaveTime, double arrivalSpeed, double leaveSpeed,
971 : bool sameTargetLane, double impatience, double decel, SUMOTime waitingTime,
972 : const SUMOTrafficObject* ego) const {
973 : #ifdef MSLink_DEBUG_OPENED
974 : if (gDebugFlag1) {
975 : std::stringstream stream; // to reduce output interleaving from different threads
976 : stream << " link=" << getDescription()
977 : << " foeVeh=" << veh->getID()
978 : << " req=" << avi.willPass
979 : << " aT=" << avi.arrivalTime
980 : << " lT=" << avi.leavingTime
981 : << "\n";
982 : std::cout << stream.str();
983 : }
984 : #endif
985 140252950 : if (!avi.willPass) {
986 : return false;
987 : }
988 45318237 : if (myState == LINKSTATE_ALLWAY_STOP) {
989 : assert(waitingTime > 0);
990 : #ifdef MSLink_DEBUG_OPENED
991 : if (gDebugFlag1) {
992 : std::stringstream stream; // to reduce output interleaving from different threads
993 : stream << " foeDist=" << avi.dist
994 : << " foeBGap=" << veh->getBrakeGap(false)
995 : << " foeWait=" << avi.waitingTime
996 : << " wait=" << waitingTime
997 : << "\n";
998 : std::cout << stream.str();
999 : }
1000 : #endif
1001 : // when using actionSteps, the foe waiting time may be outdated
1002 1462377 : const SUMOTime actionDelta = SIMSTEP - veh->getLastActionTime();
1003 1462377 : if (waitingTime > avi.waitingTime + actionDelta) {
1004 : return false;
1005 : }
1006 232207 : if (waitingTime == (avi.waitingTime + actionDelta) && arrivalTime < avi.arrivalTime + actionDelta) {
1007 : return false;
1008 : }
1009 : }
1010 44055140 : SUMOTime foeArrivalTime = avi.arrivalTime;
1011 44055140 : double foeArrivalSpeedBraking = avi.arrivalSpeedBraking;
1012 44055140 : if (impatience > 0 && arrivalTime < avi.arrivalTime) {
1013 : #ifdef MSLink_DEBUG_OPENED
1014 : gDebugFlag6 = ((ego == nullptr || ego->isSelected()) && (veh == nullptr || veh->isSelected()));
1015 : #endif
1016 2393140 : const SUMOTime fatb = computeFoeArrivalTimeBraking(arrivalTime, veh, avi.arrivalTime, impatience, avi.dist, foeArrivalSpeedBraking);
1017 2393140 : foeArrivalTime = (SUMOTime)((1. - impatience) * (double)avi.arrivalTime + impatience * (double)fatb);
1018 : #ifdef MSLink_DEBUG_OPENED
1019 : if (gDebugFlag6) {
1020 : std::cout << SIMTIME << " link=" << getDescription() << " ego=" << ego->getID() << " foe=" << veh->getID()
1021 : << " at=" << STEPS2TIME(arrivalTime)
1022 : << " fat=" << STEPS2TIME(avi.arrivalTime)
1023 : << " fatb=" << STEPS2TIME(fatb)
1024 : << " fat2=" << STEPS2TIME(foeArrivalTime)
1025 : << "\n";
1026 : }
1027 : #endif
1028 : }
1029 :
1030 :
1031 44055140 : const SUMOTime lookAhead = (myState == LINKSTATE_ZIPPER
1032 44055140 : ? myLookaheadTimeZipper
1033 : : (ego == nullptr
1034 38375644 : ? myLookaheadTime
1035 38372935 : : TIME2STEPS(ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, STEPS2TIME(myLookaheadTime)))));
1036 : //if (ego != 0) std::cout << SIMTIME << " ego=" << ego->getID() << " jmTimegapMinor=" << ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_TIMEGAP_MINOR, -1) << " lookAhead=" << lookAhead << "\n";
1037 : #ifdef MSLink_DEBUG_OPENED
1038 : if (gDebugFlag1 || gDebugFlag6) {
1039 : std::stringstream stream; // to reduce output interleaving from different threads
1040 : stream << " imp=" << impatience << " fAT2=" << foeArrivalTime << " fASb=" << foeArrivalSpeedBraking << " lA=" << lookAhead << " egoAT=" << arrivalTime << " egoLT=" << leaveTime << " egoLS=" << leaveSpeed << "\n";
1041 : std::cout << stream.str();
1042 : }
1043 : #endif
1044 44055140 : if (avi.leavingTime < arrivalTime) {
1045 : // ego wants to be follower
1046 33064889 : if (sameTargetLane && (arrivalTime - avi.leavingTime < lookAhead
1047 15859326 : || unsafeMergeSpeeds(avi.leaveSpeed, arrivalSpeed,
1048 15859326 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), decel))) {
1049 : #ifdef MSLink_DEBUG_OPENED
1050 : if (gDebugFlag1 || gDebugFlag6) {
1051 : std::cout << " blocked (cannot follow)\n";
1052 : }
1053 : #endif
1054 2004651 : return true;
1055 : }
1056 10990251 : } else if (foeArrivalTime > leaveTime + lookAhead) {
1057 : // ego wants to be leader.
1058 11274127 : if (sameTargetLane && unsafeMergeSpeeds(leaveSpeed, foeArrivalSpeedBraking,
1059 4488854 : decel, veh->getVehicleType().getCarFollowModel().getMaxDecel())) {
1060 : #ifdef MSLink_DEBUG_OPENED
1061 : if (gDebugFlag1 || gDebugFlag6) {
1062 : std::cout << " blocked (cannot lead)\n";
1063 : }
1064 : #endif
1065 : return true;
1066 : }
1067 : } else {
1068 : // even without considering safeHeadwayTime there is already a conflict
1069 : #ifdef MSLink_DEBUG_OPENED
1070 : if (gDebugFlag1 || gDebugFlag6) {
1071 : std::cout << " blocked (hard conflict)\n";
1072 : }
1073 : #endif
1074 : return true;
1075 : }
1076 : return false;
1077 : }
1078 :
1079 :
1080 : SUMOTime
1081 2393140 : MSLink::computeFoeArrivalTimeBraking(SUMOTime arrivalTime, const SUMOVehicle* foe, SUMOTime foeArrivalTime, double impatience, double dist, double& fasb) {
1082 : // a: distance saved when foe brakes from arrivalTime to foeArrivalTime
1083 : // b: distance driven past foeArrivalTime
1084 : // m: permitted decceleration
1085 : // d: total deceleration until foeArrivalTime
1086 : // dist2: distance of foe at arrivalTime
1087 : // actual arrivalTime must fall on a simulation step
1088 2393140 : if (arrivalTime - arrivalTime % DELTA_T == foeArrivalTime - foeArrivalTime % DELTA_T) {
1089 : // foe enters the junction in the same step
1090 : return foeArrivalTime;
1091 : }
1092 2061468 : if (arrivalTime % DELTA_T > 0) {
1093 2034127 : arrivalTime = arrivalTime - (arrivalTime % DELTA_T) + DELTA_T;
1094 : }
1095 : //arrivalTime += DELTA_T - arrivalTime % DELTA_T;
1096 2061468 : const double m = foe->getVehicleType().getCarFollowModel().getMaxDecel() * impatience;
1097 2061468 : const double dt = STEPS2TIME(foeArrivalTime - arrivalTime);
1098 2061468 : const double d = dt * m;
1099 2061468 : const double a = dt * d / 2;
1100 2061468 : const double v = dist / STEPS2TIME(foeArrivalTime - SIMSTEP + DELTA_T);
1101 2061468 : const double dist2 = dist - v * STEPS2TIME(arrivalTime - SIMSTEP);
1102 2061468 : if (0.5 * v * v / m <= dist2) {
1103 1002108 : if (gDebugFlag6) {
1104 0 : std::cout << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " a=" << a << " canBrakeToStop\n";
1105 : }
1106 1002108 : fasb = 0;
1107 1002108 : return foeArrivalTime + TIME2STEPS(30);
1108 : }
1109 : // a = b (foe reaches the original distance to the stop line)
1110 : // x: time driven past foeArrivalTime
1111 : // v: foe speed without braking
1112 : // v2: average foe speed after foeArrivalTime (braking continues for time x)
1113 : // v2 = (v - d - x * m / 2)
1114 : // b = v2 * x
1115 : // solving for x gives:
1116 1059360 : const double x = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * -0.5 - d + v) / m;
1117 :
1118 : #ifdef MSLink_DEBUG_OPENED
1119 : const double x2 = (sqrt(4 * (v - d) * (v - d) - 8 * m * a) * 0.5 - d + v) / m;
1120 : if (gDebugFlag6 || std::isnan(x)) {
1121 : std::cout << SIMTIME << " dist=" << dist << " dist2=" << dist2 << " at=" << STEPS2TIME(arrivalTime) << " m=" << m << " d=" << d << " v=" << v << " a=" << a << " x=" << x << " x2=" << x2 << "\n";
1122 : }
1123 : #endif
1124 1059360 : fasb = v - (dt + x) * m;
1125 1059360 : return foeArrivalTime + TIME2STEPS(x);
1126 : }
1127 :
1128 :
1129 : bool
1130 738992 : MSLink::hasApproachingFoe(SUMOTime arrivalTime, SUMOTime leaveTime, double speed, double decel) const {
1131 750413 : for (const MSLink* const link : myFoeLinks) {
1132 12501 : if (link->blockedAtTime(arrivalTime, leaveTime, speed, speed, myLane == link->getLane(), 0, decel, 0)) {
1133 : return true;
1134 : }
1135 : }
1136 836056 : for (const MSLane* const lane : myFoeLanes) {
1137 107055 : if (lane->getVehicleNumberWithPartials() > 0) {
1138 : return true;
1139 : }
1140 : }
1141 : return false;
1142 : }
1143 :
1144 :
1145 : std::pair<const SUMOVehicle*, const MSLink*>
1146 5696 : MSLink::getFirstApproachingFoe(const MSLink* wrapAround) const {
1147 : double closetDist = std::numeric_limits<double>::max();
1148 : const SUMOVehicle* closest = nullptr;
1149 : const MSLink* foeLink = nullptr;
1150 18596 : for (MSLink* link : myFoeLinks) {
1151 19860 : for (const auto& it : link->myApproachingVehicles) {
1152 : //std::cout << " link=" << getDescription() << " foeLink_in=" << link->getLaneBefore()->getID() << " wrapAround=" << wrapAround->getDescription() << "\n";
1153 6960 : if (link->getLaneBefore() == wrapAround->getLaneBefore()) {
1154 488 : return std::make_pair(nullptr, wrapAround);
1155 6472 : } else if (it.second.dist < closetDist) {
1156 : closetDist = it.second.dist;
1157 3450 : if (it.second.willPass) {
1158 3184 : closest = it.first;
1159 : foeLink = link;
1160 : }
1161 : }
1162 : }
1163 : }
1164 : return std::make_pair(closest, foeLink);
1165 : }
1166 :
1167 :
1168 : void
1169 82399772 : MSLink::setTLState(LinkState state, SUMOTime t) {
1170 82399772 : if (myState != state) {
1171 14205051 : myLastStateChange = t;
1172 : }
1173 82399772 : myState = state;
1174 82399772 : if (haveGreen()) {
1175 63646069 : myLastGreenState = myState;
1176 : }
1177 82399772 : }
1178 :
1179 :
1180 : void
1181 195048 : MSLink::setTLLogic(const MSTrafficLightLogic* logic) {
1182 195048 : myLogic = logic;
1183 195048 : }
1184 :
1185 :
1186 : bool
1187 1134178052 : MSLink::isCont() const {
1188 : // when a traffic light is switched off minor roads have their cont status revoked
1189 1134178052 : return (myState == LINKSTATE_TL_OFF_BLINKING || myState == LINKSTATE_ALLWAY_STOP) ? myAmContOff : myAmCont;
1190 : }
1191 :
1192 :
1193 : bool
1194 55384643 : MSLink::lastWasContMajor() const {
1195 55384643 : if (myInternalLane == nullptr || myAmCont) {
1196 : return false;
1197 : } else {
1198 42075356 : MSLane* pred = myInternalLane->getLogicalPredecessorLane();
1199 42075356 : if (!pred->getEdge().isInternal()) {
1200 : return false;
1201 : } else {
1202 7886343 : const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1203 : assert(pred2 != nullptr);
1204 7886343 : const MSLink* const predLink = pred2->getLinkTo(pred);
1205 : assert(predLink != nullptr);
1206 7886343 : if (predLink->havePriority()) {
1207 : return true;
1208 : }
1209 7430988 : if (myHavePedestrianCrossingFoe) {
1210 562026 : return predLink->getLastGreenState() == LINKSTATE_TL_GREEN_MAJOR;
1211 : } else {
1212 6868962 : return predLink->haveYellow();
1213 : }
1214 : }
1215 : }
1216 : }
1217 :
1218 :
1219 : bool
1220 51302715 : MSLink::lastWasContState(LinkState linkState) const {
1221 51302715 : if (myInternalLane == nullptr || myAmCont || myHavePedestrianCrossingFoe) {
1222 : return false;
1223 : } else {
1224 44413170 : MSLane* pred = myInternalLane->getLogicalPredecessorLane();
1225 44413170 : if (!pred->getEdge().isInternal()) {
1226 : return false;
1227 : } else {
1228 10790368 : const MSLane* const pred2 = pred->getLogicalPredecessorLane();
1229 : assert(pred2 != nullptr);
1230 10790368 : const MSLink* const predLink = pred2->getLinkTo(pred);
1231 : assert(predLink != nullptr);
1232 10790368 : return predLink->getState() == linkState;
1233 : }
1234 : }
1235 : }
1236 :
1237 :
1238 : void
1239 81324 : MSLink::writeApproaching(OutputDevice& od, const std::string fromLaneID) const {
1240 81324 : if (myApproachingVehicles.size() > 0) {
1241 18080 : od.openTag("link");
1242 : od.writeAttr(SUMO_ATTR_FROM, fromLaneID);
1243 11408 : const std::string via = getViaLane() == nullptr ? "" : getViaLane()->getID();
1244 : od.writeAttr(SUMO_ATTR_VIA, via);
1245 18080 : od.writeAttr(SUMO_ATTR_TO, getLane() == nullptr ? "" : getLane()->getID());
1246 : std::vector<std::pair<SUMOTime, const SUMOVehicle*> > toSort; // stabilize output
1247 19578 : for (auto it : myApproachingVehicles) {
1248 10538 : toSort.push_back(std::make_pair(it.second.arrivalTime, it.first));
1249 : }
1250 9040 : std::sort(toSort.begin(), toSort.end());
1251 19578 : for (std::vector<std::pair<SUMOTime, const SUMOVehicle*> >::const_iterator it = toSort.begin(); it != toSort.end(); ++it) {
1252 10538 : od.openTag("approaching");
1253 10538 : const ApproachingVehicleInformation& avi = myApproachingVehicles.find(it->second)->second;
1254 10538 : od.writeAttr(SUMO_ATTR_ID, it->second->getID());
1255 10538 : od.writeAttr(SUMO_ATTR_IMPATIENCE, it->second->getImpatience());
1256 21076 : od.writeAttr("arrivalTime", time2string(avi.arrivalTime));
1257 21076 : od.writeAttr("leaveTime", time2string(avi.leavingTime));
1258 21076 : od.writeAttr("arrivalSpeed", toString(avi.arrivalSpeed));
1259 21076 : od.writeAttr("arrivalSpeedBraking", toString(avi.arrivalSpeedBraking));
1260 21076 : od.writeAttr("leaveSpeed", toString(avi.leaveSpeed));
1261 21076 : od.writeAttr("willPass", toString(avi.willPass));
1262 21076 : od.closeTag();
1263 : }
1264 9040 : od.closeTag();
1265 9040 : }
1266 81324 : }
1267 :
1268 :
1269 : double
1270 886303 : MSLink::getInternalLengthsAfter() const {
1271 : double len = 0.;
1272 886303 : MSLane* lane = myInternalLane;
1273 :
1274 1693913 : while (lane != nullptr && lane->isInternal()) {
1275 807610 : len += lane->getLength();
1276 807610 : lane = lane->getLinkCont()[0]->getViaLane();
1277 : }
1278 886303 : return len;
1279 : }
1280 :
1281 : double
1282 0 : MSLink::getInternalLengthsBefore() const {
1283 : double len = 0.;
1284 0 : const MSLane* lane = myInternalLane;
1285 :
1286 0 : while (lane != nullptr && lane->isInternal()) {
1287 0 : len += lane->getLength();
1288 0 : if (lane->getIncomingLanes().size() == 1) {
1289 0 : lane = lane->getIncomingLanes()[0].lane;
1290 : } else {
1291 : break;
1292 : }
1293 : }
1294 0 : return len;
1295 : }
1296 :
1297 :
1298 : double
1299 13038 : MSLink::getLengthsBeforeCrossing(const MSLane* foeLane) const {
1300 13038 : MSLane* via = myInternalLane;
1301 : double totalDist = 0.;
1302 : bool foundCrossing = false;
1303 15506 : while (via != nullptr) {
1304 14272 : MSLink* link = via->getLinkCont()[0];
1305 14272 : double dist = link->getLengthBeforeCrossing(foeLane);
1306 14272 : if (dist != INVALID_DOUBLE) {
1307 : // found conflicting lane
1308 11804 : totalDist += dist;
1309 : foundCrossing = true;
1310 : break;
1311 : } else {
1312 2468 : totalDist += via->getLength();
1313 : via = link->getViaLane();
1314 : }
1315 : }
1316 : if (foundCrossing) {
1317 11804 : return totalDist;
1318 : } else {
1319 : return INVALID_DOUBLE;
1320 : }
1321 : }
1322 :
1323 :
1324 : double
1325 14272 : MSLink::getLengthBeforeCrossing(const MSLane* foeLane) const {
1326 : int foe_ix;
1327 80108 : for (foe_ix = 0; foe_ix != (int)myFoeLanes.size(); ++foe_ix) {
1328 78874 : if (myFoeLanes[foe_ix] == foeLane) {
1329 : break;
1330 : }
1331 : }
1332 14272 : if (foe_ix == (int)myFoeLanes.size()) {
1333 : // no conflict with the given lane, indicate by returning -1
1334 : #ifdef MSLink_DEBUG_CROSSING_POINTS
1335 : std::cout << "No crossing of lanes '" << foeLane->getID() << "' and '" << myInternalLaneBefore->getID() << "'" << std::endl;
1336 : #endif
1337 : return INVALID_DOUBLE;
1338 : } else {
1339 : // found conflicting lane index
1340 13038 : double dist = myInternalLaneBefore->getLength() - myConflicts[foe_ix].getLengthBehindCrossing(this);
1341 13038 : if (dist == -10000.) {
1342 : // this is the value in myConflicts, if the relation allows intersection but none is present for the actual geometry.
1343 : return INVALID_DOUBLE;
1344 : }
1345 : #ifdef MSLink_DEBUG_CROSSING_POINTS
1346 : std::cout << "Crossing of lanes '" << myInternalLaneBefore->getID() << "' and '" << foeLane->getID()
1347 : << "' at distance " << dist << " (approach along '"
1348 : << myInternalLaneBefore->getEntryLink()->getLaneBefore()->getID() << "')" << std::endl;
1349 : #endif
1350 : return dist;
1351 : }
1352 : }
1353 :
1354 :
1355 : bool
1356 33723639 : MSLink::isEntryLink() const {
1357 33723639 : if (MSGlobals::gUsingInternalLanes) {
1358 54619067 : return myInternalLane != nullptr && myInternalLaneBefore == nullptr;
1359 : } else {
1360 : return false;
1361 : }
1362 : }
1363 :
1364 : bool
1365 16815416 : MSLink::isConflictEntryLink() const {
1366 : // either a non-cont entry link or the link after a cont-link
1367 16815416 : return !myAmCont && (isEntryLink() || (myInternalLaneBefore != nullptr && myInternalLane != nullptr));
1368 : }
1369 :
1370 : bool
1371 86167049 : MSLink::isExitLink() const {
1372 86167049 : if (MSGlobals::gUsingInternalLanes) {
1373 148431322 : return myInternalLaneBefore != nullptr && myInternalLane == nullptr;
1374 : } else {
1375 : return false;
1376 : }
1377 : }
1378 :
1379 : bool
1380 42626487 : MSLink::isExitLinkAfterInternalJunction() const {
1381 42626487 : if (MSGlobals::gUsingInternalLanes) {
1382 : return (getInternalLaneBefore() != nullptr
1383 42626487 : && myInternalLaneBefore->getIncomingLanes().size() == 1
1384 85252974 : && myInternalLaneBefore->getIncomingLanes().front().viaLink->isInternalJunctionLink());
1385 : } else {
1386 : return false;
1387 : }
1388 : }
1389 :
1390 :
1391 : const MSLink*
1392 20300 : MSLink::getCorrespondingExitLink() const {
1393 20300 : MSLane* lane = myInternalLane;
1394 : const MSLink* link = this;
1395 41654 : while (lane != nullptr) {
1396 21354 : link = lane->getLinkCont()[0];
1397 : lane = link->getViaLane();
1398 : }
1399 20300 : return link;
1400 : }
1401 :
1402 :
1403 : const MSLink*
1404 719626301 : MSLink::getCorrespondingEntryLink() const {
1405 : const MSLink* link = this;
1406 957020606 : while (link->myLaneBefore->isInternal()) {
1407 : assert(myLaneBefore->getIncomingLanes().size() == 1);
1408 237394305 : link = link->myLaneBefore->getIncomingLanes().front().viaLink;
1409 : }
1410 719626301 : return link;
1411 : }
1412 :
1413 :
1414 : bool
1415 316511166 : MSLink::isInternalJunctionLink() const {
1416 316511166 : return getInternalLaneBefore() != nullptr && myInternalLane != nullptr;
1417 : }
1418 :
1419 :
1420 : const MSLink::LinkLeaders
1421 779915572 : MSLink::getLeaderInfo(const MSVehicle* ego, double dist, std::vector<const MSPerson*>* collectBlockers, bool isShadowLink) const {
1422 : LinkLeaders result;
1423 : // this link needs to start at an internal lane (either an exit link or between two internal lanes)
1424 : // or it must be queried by the pedestrian model (ego == 0)
1425 779915572 : if (ego != nullptr && (!fromInternalLane() || ego->getLaneChangeModel().isOpposite())) {
1426 : // ignore link leaders
1427 : return result;
1428 : }
1429 : //gDebugFlag1 = true;
1430 253835495 : if (gDebugFlag1) {
1431 0 : std::cout << SIMTIME << " getLeaderInfo link=" << getDescription() << " dist=" << dist << " isShadowLink=" << isShadowLink << "\n";
1432 : }
1433 253835495 : if (MSGlobals::gComputeLC && ego != nullptr && ego->getLane()->isNormal()) {
1434 21394053 : const MSLink* junctionEntry = getLaneBefore()->getEntryLink();
1435 4331361 : if (junctionEntry->haveRed() && !ego->ignoreRed(junctionEntry, true)
1436 : // check oncoming on bidiLane during laneChanging
1437 25721380 : && (!MSGlobals::gComputeLC || junctionEntry->getLaneBefore()->getBidiLane() == nullptr)) {
1438 4290397 : if (gDebugFlag1) {
1439 0 : std::cout << " ignore linkLeaders beyond red light\n";
1440 : }
1441 : return result;
1442 : }
1443 : }
1444 : // this is an exit link
1445 598190756 : for (int i = 0; i < (int)myFoeLanes.size(); ++i) {
1446 348645661 : const MSLane* foeLane = myFoeLanes[i];
1447 348645661 : const MSLink* foeExitLink = foeLane->getLinkCont()[0];
1448 : // distance from the querying vehicle to the crossing point with foeLane
1449 348645661 : double distToCrossing = dist - myConflicts[i].getLengthBehindCrossing(this);
1450 348645661 : const double foeDistToCrossing = foeLane->getLength() - myConflicts[i].getFoeLengthBehindCrossing(foeExitLink);
1451 348645661 : const bool sameTarget = (myLane == foeExitLink->getLane()) && !isInternalJunctionLink() && !foeExitLink->isInternalJunctionLink();
1452 348645661 : const bool sameSource = (myInternalLaneBefore != nullptr && myInternalLaneBefore->getLogicalPredecessorLane() == foeLane->getLogicalPredecessorLane());
1453 348645661 : const double crossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].conflictSize;
1454 348645661 : const double foeCrossingWidth = (sameTarget || sameSource) ? 0 : myConflicts[i].getFoeConflictSize(foeExitLink);
1455 : // special treatment of contLane foe only applies if this lane is not a contLane or contLane follower itself
1456 439369659 : const bool contLane = (foeExitLink->getViaLaneOrLane()->getEdge().isInternal() && !(
1457 90723998 : isInternalJunctionLink() || isExitLinkAfterInternalJunction()));
1458 348645661 : if (gDebugFlag1) {
1459 : std::cout << " distToCrossing=" << distToCrossing << " foeLane=" << foeLane->getID() << " cWidth=" << crossingWidth
1460 0 : << " ijl=" << isInternalJunctionLink() << " sT=" << sameTarget << " sS=" << sameSource
1461 0 : << " lbc=" << myConflicts[i].getLengthBehindCrossing(this)
1462 0 : << " flbc=" << myConflicts[i].getFoeLengthBehindCrossing(foeExitLink)
1463 : << " cw=" << crossingWidth
1464 : << " fcw=" << foeCrossingWidth
1465 : << " contLane=" << contLane
1466 0 : << " state=" << toString(myState)
1467 0 : << " foeState=" << toString(foeExitLink->getState())
1468 0 : << "\n";
1469 : }
1470 84292844 : if (distToCrossing + crossingWidth < 0 && !sameTarget
1471 428123248 : && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing + crossingWidth + ego->getVehicleType().getLength() < 0)) {
1472 76373803 : continue; // vehicle is behind the crossing point, continue with next foe lane
1473 : }
1474 : bool ignoreGreenCont = false;
1475 : bool foeIndirect = false;
1476 272271858 : if (contLane) {
1477 26991546 : const MSLink* entry = getLaneBefore()->getEntryLink();
1478 26991546 : const MSLink* foeEntry = foeLane->getEntryLink();
1479 26991546 : foeIndirect = foeEntry->myAmIndirect;
1480 26977265 : if (entry != nullptr && entry->haveGreen()
1481 15093303 : && foeEntry != nullptr && foeEntry->haveGreen()
1482 34205338 : && entry->myLaneBefore != foeEntry->myLaneBefore) {
1483 : // ignore vehicles before an internaljunction as long as they are still in green minor mode
1484 : ignoreGreenCont = true;
1485 : }
1486 : }
1487 26991546 : if (foeIndirect && distToCrossing >= NO_INTERSECTION) {
1488 32543 : if (gDebugFlag1) {
1489 0 : std::cout << " ignore:noIntersection\n";
1490 : }
1491 32543 : continue;
1492 : }
1493 : // it is not sufficient to return the last vehicle on the foeLane because ego might be its leader
1494 : // therefore we return all vehicles on the lane
1495 : //
1496 : // special care must be taken for continuation lanes. (next lane is also internal)
1497 : // vehicles on cont. lanes or on internal lanes with the same target as this link can not be ignored
1498 : // and should block (gap = -1) unless they are part of an indirect turn
1499 : MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
1500 24183790 : for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1501 24183793 : MSVehicle* leader = (MSVehicle*)*it_veh;
1502 24183793 : const double leaderBack = leader->getBackPositionOnLane(foeLane);
1503 24183793 : const double leaderBackDist = foeDistToCrossing - leaderBack;
1504 24183793 : const double l2 = ego != nullptr ? ego->getLength() + 2 : 0; // add some slack to account for further meeting-angle effects
1505 24092965 : const double sagitta = ego != nullptr && myRadius != std::numeric_limits<double>::max() ? myRadius - sqrt(myRadius * myRadius - 0.25 * l2 * l2) : 0;
1506 24183793 : const bool pastTheCrossingPoint = leaderBackDist + foeCrossingWidth + sagitta < 0;
1507 24183793 : const bool enteredTheCrossingPoint = leaderBackDist < leader->getVehicleType().getLength();
1508 24183793 : const bool foeIsBicycleTurn = (leader->getVehicleType().getVehicleClass() == SVC_BICYCLE
1509 24183793 : && foeLane->getIncomingLanes().front().viaLink->getDirection() == LinkDirection::LEFT);
1510 24183793 : const bool ignoreIndirectBicycleTurn = pastTheCrossingPoint && foeIsBicycleTurn;
1511 24183793 : const bool cannotIgnore = ((contLane && !ignoreIndirectBicycleTurn) || sameTarget || sameSource) && ego != nullptr;
1512 24183793 : const bool inTheWay = ((((!pastTheCrossingPoint && distToCrossing > 0) || (sameTarget && distToCrossing > leaderBackDist - leader->getLength()))
1513 19661428 : && enteredTheCrossingPoint
1514 10726264 : && (!foeExitLink->isInternalJunctionLink() || foeIsBicycleTurn))
1515 38063447 : || foeExitLink->getLaneBefore()->getNormalPredecessorLane() == myLane->getBidiLane());
1516 24183793 : const bool isOpposite = leader->getLaneChangeModel().isOpposite();
1517 24183793 : const auto avi = foeExitLink->getApproaching(leader);
1518 : // if leader is not found, assume that it performed a lane change in the last step
1519 24183793 : const bool willPass = avi.willPass || (avi.arrivalTime == INVALID_TIME && sameTarget);
1520 24183793 : if (gDebugFlag1) {
1521 : std::cout << " candidate leader=" << leader->getID()
1522 : << " cannotIgnore=" << cannotIgnore
1523 : << " fdtc=" << foeDistToCrossing
1524 : << " lb=" << leaderBack
1525 : << " lbd=" << leaderBackDist
1526 : << " fcwidth=" << foeCrossingWidth
1527 0 : << " r=" << myRadius
1528 : << " sagitta=" << sagitta
1529 : << " foePastCP=" << pastTheCrossingPoint
1530 : << " foeEnteredCP=" << enteredTheCrossingPoint
1531 : << " inTheWay=" << inTheWay
1532 : << " willPass=" << willPass
1533 0 : << " isFrontOnLane=" << leader->isFrontOnLane(foeLane)
1534 : << " ignoreGreenCont=" << ignoreGreenCont
1535 : << " foeIndirect=" << foeIndirect
1536 : << " foeBikeTurn=" << foeIsBicycleTurn
1537 0 : << " isOpposite=" << isOpposite << "\n";
1538 : }
1539 24183793 : if (leader == ego) {
1540 6159220 : continue;
1541 : }
1542 : // ignore greenCont foe vehicles that are not in the way
1543 23601069 : if (!inTheWay && ignoreGreenCont) {
1544 8235 : if (gDebugFlag1) {
1545 0 : std::cout << " ignoreGreenCont\n";
1546 : }
1547 8235 : continue;
1548 : }
1549 : // after entering the conflict area, ignore foe vehicles that are not in the way
1550 2877184 : if ((!MSGlobals::gComputeLC || (ego != nullptr && ego->getLane() == foeLane) || MSGlobals::gSublane)
1551 22477596 : && distToCrossing < -POSITION_EPS && !inTheWay
1552 23878033 : && (ego == nullptr || !MSGlobals::gComputeLC || distToCrossing < -ego->getVehicleType().getLength())) {
1553 142386 : if (gDebugFlag1) {
1554 0 : std::cout << " ego entered conflict area\n";
1555 : }
1556 142386 : continue;
1557 : }
1558 23508025 : if (!MSGlobals::gComputeLC
1559 20619189 : && sameSource
1560 5192777 : && &ego->getLane()->getEdge() == &myInternalLaneBefore->getEdge()
1561 23742376 : && leaderBack + leader->getLength() < ego->getPositionOnLane() - ego->getLength()) {
1562 : // ego is already on the junction and clearly ahead of foe
1563 57577 : if (gDebugFlag1) {
1564 0 : std::cout << " ego ahead of same-source foe\n";
1565 : }
1566 57577 : continue;
1567 : }
1568 :
1569 : // ignore foe vehicles that will not pass
1570 15913635 : if ((!cannotIgnore || leader->isStopped() || sameTarget)
1571 16359687 : && !willPass
1572 1130730 : && leader->isFrontOnLane(foeLane)
1573 : && !isOpposite
1574 614642 : && !inTheWay
1575 : // willPass is false if the vehicle is already on the stopping edge
1576 23839142 : && !leader->willStop()) {
1577 445608 : if (gDebugFlag1) {
1578 0 : std::cout << " foe will not pass\n";
1579 : }
1580 445608 : continue;
1581 : }
1582 22947263 : if (leader->isBidiOn(foeLane)) {
1583 : // conflict resolved via forward lane of the foe
1584 45099 : continue;
1585 : }
1586 : // check whether foe is blocked and might need to change before leaving the junction
1587 22902164 : const bool foeStrategicBlocked = (leader->getLaneChangeModel().isStrategicBlocked() &&
1588 1143262 : leader->getCarFollowModel().brakeGap(leader->getSpeed()) <= foeLane->getLength() - leaderBack);
1589 22902164 : const bool sameInternalEdge = &myInternalLaneBefore->getEdge() == &foeExitLink->getInternalLaneBefore()->getEdge();
1590 :
1591 22902164 : const bool foeLaneIsBidi = myInternalLaneBefore->getBidiLane() == foeLane;
1592 22902164 : if (MSGlobals::gSublane && ego != nullptr && (sameSource || sameTarget || foeLaneIsBidi)
1593 6075162 : && (!foeStrategicBlocked || sameInternalEdge)) {
1594 5923747 : if (ego->getLane() == leader->getLane()) {
1595 125194 : continue;
1596 : }
1597 : // ignore vehicles if not in conflict sublane-wise
1598 5798553 : const double egoLatOffset = isShadowLink ? ego->getLatOffset(ego->getLaneChangeModel().getShadowLane()) : 0;
1599 5798553 : const double posLat = ego->getLateralPositionOnLane() + egoLatOffset;
1600 5798553 : double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1601 5798553 : if (foeLaneIsBidi) {
1602 : // leader is oncoming
1603 0 : posLatLeader = foeLane->getWidth() - posLatLeader;
1604 : }
1605 5798553 : const double latGap = (fabs(posLat - posLatLeader)
1606 5798553 : - 0.5 * (ego->getVehicleType().getWidth() + leader->getVehicleType().getWidth()));
1607 5798553 : const double maneuverDist = leader->getLaneChangeModel().getManeuverDist() * (posLat < posLatLeader ? -1 : 1);
1608 5798553 : if (gDebugFlag1) {
1609 0 : std::cout << " checkIgnore sublaneFoe lane=" << myInternalLaneBefore->getID()
1610 : << " sameSource=" << sameSource
1611 : << " sameTarget=" << sameTarget
1612 : << " foeLaneIsBidi=" << foeLaneIsBidi
1613 : << " foeLane=" << foeLane->getID()
1614 : << " leader=" << leader->getID()
1615 0 : << " egoLane=" << ego->getLane()->getID()
1616 0 : << " leaderLane=" << leader->getLane()->getID()
1617 : << " egoLat=" << posLat
1618 : << " egoLatOffset=" << egoLatOffset
1619 : << " leaderLat=" << posLatLeader
1620 0 : << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1621 : << " latGap=" << latGap
1622 : << " maneuverDist=" << maneuverDist
1623 0 : << " computeLC=" << MSGlobals::gComputeLC
1624 0 : << " egoMaxSpeedLat=" << ego->getVehicleType().getMaxSpeedLat()
1625 0 : << "\n";
1626 : }
1627 1059079 : if (latGap > 0 && (latGap > maneuverDist || !sameTarget || !MSGlobals::gComputeLC)
1628 : // do not perform sublane changes that interfere with the leader vehicle
1629 6849399 : && (!MSGlobals::gComputeLC || latGap > ego->getVehicleType().getMaxSpeedLat())) {
1630 919065 : const MSLink* foeEntryLink = foeLane->getIncomingLanes().front().viaLink;
1631 919065 : if (sameSource) {
1632 : // for lanes from the same edge, higer index implies a
1633 : // connection further to the left
1634 608283 : const bool leaderFromRight = (myIndex > foeEntryLink->getIndex());
1635 608283 : if ((posLat > posLatLeader) == leaderFromRight) {
1636 : // ignore speed since lanes diverge
1637 334589 : if (gDebugFlag1) {
1638 0 : std::cout << " ignored (same source) leaderFromRight=" << leaderFromRight << "\n";
1639 : }
1640 334589 : continue;
1641 : }
1642 310782 : } else if (sameTarget) {
1643 : // for lanes from different edges we cannot rely on the
1644 : // index due to wrap-around issues
1645 310782 : if (myDirection != foeEntryLink->getDirection()) {
1646 298110 : bool leaderFromRight = foeEntryLink->getDirection() < myDirection;
1647 : // leader vehicle should not move towards ego
1648 298110 : if (MSGlobals::gLefthand) {
1649 0 : leaderFromRight = !leaderFromRight;
1650 : }
1651 409913 : if ((posLat > posLatLeader) == leaderFromRight
1652 : // leader should keep lateral position or move away from ego
1653 165280 : && (leader->getLaneChangeModel().getSpeedLat() == 0
1654 54119 : || leaderFromRight == (leader->getLaneChangeModel().getSpeedLat() < latGap))
1655 417522 : && (ego->getLaneChangeModel().getSpeedLat() == 0
1656 16025 : || leaderFromRight == (ego->getLaneChangeModel().getSpeedLat() > latGap))) {
1657 111803 : if (gDebugFlag1) {
1658 0 : std::cout << " ignored (different source) leaderFromRight=" << leaderFromRight << "\n";
1659 : }
1660 111803 : continue;
1661 : }
1662 : } else {
1663 : // XXX figure out relative direction somehow
1664 : }
1665 : } else {
1666 0 : if (gDebugFlag1) {
1667 0 : std::cout << " ignored oncoming bidi leader\n";
1668 : }
1669 0 : continue;
1670 : }
1671 : }
1672 : }
1673 22330578 : if (leader->getWaitingTime() < MSGlobals::gIgnoreJunctionBlocker) {
1674 : // compute distance between vehicles on the superimposition of both lanes
1675 : // where the crossing point is the common point
1676 : double gap;
1677 : bool fromLeft = true;
1678 21896730 : if (ego == nullptr) {
1679 : // request from pedestrian model. return distance between leaderBack and crossing point
1680 : //std::cout << " foeLane=" << foeLane->getID() << " leaderBack=" << leaderBack << " foeDistToCrossing=" << foeDistToCrossing << " foeLength=" << foeLane->getLength() << " foebehind=" << myConflicts[i].second << " dist=" << dist << " behind=" << myConflicts[i].first << "\n";
1681 90419 : gap = leaderBackDist;
1682 : // distToCrossing should not take into account the with of the foe lane
1683 : // (which was subtracted in setRequestInformation)
1684 : // Instead, the width of the foe vehicle is used directly by the caller.
1685 90419 : distToCrossing += myConflicts[i].conflictSize / 2;
1686 90419 : if (gap + foeCrossingWidth < 0) {
1687 : // leader is completely past the crossing point
1688 : // or there is no crossing point
1689 3723281 : continue; // next vehicle
1690 : }
1691 : // we need to determine whether the vehicle passes the
1692 : // crossing from the left or the right (heuristic)
1693 89196 : fromLeft = foeDistToCrossing > 0.5 * foeLane->getLength();
1694 21806311 : } else if ((contLane && !sameSource && !ignoreIndirectBicycleTurn) || isOpposite) {
1695 969952 : gap = -std::numeric_limits<double>::max(); // always break for vehicles which are on a continuation lane or for opposite-direction vehicles
1696 : } else {
1697 20836359 : if (pastTheCrossingPoint && !sameTarget) {
1698 : // leader is completely past the crossing point
1699 : // or there is no crossing point
1700 3721979 : if (gDebugFlag1) {
1701 0 : std::cout << " foePastCP ignored\n";
1702 : }
1703 3721979 : continue;
1704 : }
1705 : double leaderBackDist2 = leaderBackDist;
1706 17114380 : if (sameTarget && leaderBackDist2 < 0) {
1707 2946811 : const double mismatch = myConflicts[i].getFoeLengthBehindCrossing(foeExitLink) - myConflicts[i].getLengthBehindCrossing(this);
1708 2946811 : if (mismatch > 0) {
1709 1465912 : leaderBackDist2 += mismatch;
1710 : }
1711 : }
1712 17114380 : if (gDebugFlag1) {
1713 : std::cout << " distToCrossing=" << distToCrossing << " leaderBack=" << leaderBack
1714 : << " backDist=" << leaderBackDist
1715 : << " backDist2=" << leaderBackDist2
1716 0 : << " blockedStrategic=" << leader->getLaneChangeModel().isStrategicBlocked()
1717 0 : << "\n";
1718 : }
1719 17114380 : gap = distToCrossing - ego->getVehicleType().getMinGap() - leaderBackDist2 - foeCrossingWidth;
1720 : }
1721 : // if the foe is already moving off the intersection, we may
1722 : // advance up to the crossing point unless we have the same target or same source
1723 : // (for sameSource, the crossing point indicates the point of divergence)
1724 18173528 : const bool stopAsap = leader->isFrontOnLane(foeLane) ? cannotIgnore : (sameTarget || sameSource);
1725 18173528 : if (gDebugFlag1) {
1726 0 : std::cout << " leader=" << leader->getID() << " contLane=" << contLane << " cannotIgnore=" << cannotIgnore << " stopAsap=" << stopAsap << " gap=" << gap << "\n";
1727 : }
1728 18173528 : if (ignoreFoe(ego, leader)) {
1729 79 : continue;
1730 : }
1731 18173449 : const int llFlags = ((fromLeft ? LL_FROM_LEFT : 0) |
1732 18173449 : (inTheWay ? LL_IN_THE_WAY : 0) |
1733 18173449 : (sameSource ? LL_SAME_SOURCE : 0) |
1734 18173449 : (sameTarget ? LL_SAME_TARGET : 0));
1735 23696925 : result.emplace_back(leader, gap, stopAsap ? -1 : distToCrossing, llFlags, leader->getLatOffset(foeLane));
1736 : }
1737 :
1738 : }
1739 272239312 : if (ego != nullptr && MSNet::getInstance()->hasPersons()) {
1740 : // check for crossing pedestrians (keep driving if already on top of the crossing
1741 4458573 : const double distToPeds = distToCrossing - ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP);
1742 4458573 : const double vehWidth = ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP; // + configurable safety gap
1743 : /// @todo consider lateral position (depending on whether the crossing is encountered on the way in or out)
1744 : // @check lefthand?!
1745 4458573 : const bool wayIn = myConflicts[i].lengthBehindCrossing < myLaneBefore->getLength() * 0.5;
1746 4458573 : const double vehSideOffset = (foeDistToCrossing + myLaneBefore->getWidth() * 0.5 - vehWidth * 0.5
1747 4458573 : + ego->getLateralPositionOnLane() * (wayIn ? -1 : 1));
1748 : // can access the movement model here since we already checked for existing persons above
1749 8558824 : if (distToPeds >= -MSPModel::SAFETY_GAP && MSNet::getInstance()->getPersonControl().getMovementModel()->blockedAtDist(ego, foeLane, vehSideOffset, vehWidth,
1750 4100251 : ego->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_CROSSING_GAP, JM_CROSSING_GAP_DEFAULT),
1751 : collectBlockers)) {
1752 593179 : result.emplace_back(nullptr, -1, distToPeds);
1753 3865394 : } else if (foeLane->isCrossing() && ego->getLane()->isInternal() && ego->getLane()->getEdge().getToJunction() == myJunction) {
1754 131469 : const MSLink* crossingLink = foeLane->getIncomingLanes()[0].viaLink;
1755 131469 : if (distToCrossing > 0 && crossingLink->havePriority() && crossingLink->myApproachingPersons != nullptr) {
1756 : // a person might step on the crossing at any moment, since ego
1757 : // is already on the junction, the opened() check is not done anymore
1758 24386 : const double timeToEnterCrossing = distToCrossing / MAX2(ego->getSpeed(), 1.0);
1759 29856 : for (const auto& item : (*crossingLink->myApproachingPersons)) {
1760 6289 : if (!ignoreFoe(ego, item.first) && timeToEnterCrossing > STEPS2TIME(item.second.arrivalTime - SIMSTEP)) {
1761 819 : if (gDebugFlag1) {
1762 0 : std::cout << SIMTIME << ": " << ego->getID() << " breaking for approaching person " << item.first->getID()
1763 : //<< " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1764 0 : << "\n";
1765 : }
1766 819 : result.emplace_back(nullptr, -1, distToPeds);
1767 819 : break;
1768 : //} else {
1769 : // if (gDebugFlag1) {
1770 : // std::cout << SIMTIME << ": " << ego->getID() << " notBreaking for approaching person " << item.first->getID()
1771 : // << " dtc=" << distToCrossing << " ttc=" << distToCrossing / MAX2(ego->getSpeed(), 1.0) << " foeAT=" << item.second.arrivalTime << " foeTTC=" << STEPS2TIME(item.second.arrivalTime - SIMSTEP)
1772 : // << "\n";
1773 : // }
1774 : }
1775 : }
1776 : }
1777 : }
1778 : }
1779 : }
1780 :
1781 : //std::cout << SIMTIME << " ego=" << Named::getIDSecure(ego) << " link=" << getViaLaneOrLane()->getID() << " myWalkingAreaFoe=" << Named::getIDSecure(myWalkingAreaFoe) << "\n";
1782 249545095 : if (ego != nullptr) {
1783 248668755 : checkWalkingAreaFoe(ego, myWalkingAreaFoe, collectBlockers, result);
1784 248668755 : checkWalkingAreaFoe(ego, myWalkingAreaFoeExit, collectBlockers, result);
1785 : }
1786 :
1787 249545095 : if (MSGlobals::gLateralResolution > 0 && ego != nullptr && !isShadowLink) {
1788 : // check for foes on the same edge
1789 62876783 : for (std::vector<MSLane*>::const_iterator it = mySublaneFoeLanes.begin(); it != mySublaneFoeLanes.end(); ++it) {
1790 5261287 : const MSLane* foeLane = *it;
1791 : MSLane::AnyVehicleIterator end = foeLane->anyVehiclesEnd();
1792 3569675 : for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != end; ++it_veh) {
1793 3569675 : MSVehicle* leader = (MSVehicle*)*it_veh;
1794 3569675 : if (leader == ego) {
1795 2081897 : continue;
1796 : }
1797 3011779 : if (leader->getLane()->isNormal()) {
1798 : // leader is past the conflict point
1799 1170845 : continue;
1800 : }
1801 1840934 : const double maxLength = MAX2(myInternalLaneBefore->getLength(), foeLane->getLength());
1802 1840934 : const double gap = dist - maxLength - ego->getVehicleType().getMinGap() + leader->getBackPositionOnLane(foeLane);
1803 1840934 : if (gap < -(ego->getVehicleType().getMinGap() + leader->getLength())) {
1804 : // ego is ahead of leader
1805 353156 : continue;
1806 : }
1807 1487778 : const double posLat = ego->getLateralPositionOnLane();
1808 1487778 : const double posLatLeader = leader->getLateralPositionOnLane() + leader->getLatOffset(foeLane);
1809 1487778 : if (gDebugFlag1) {
1810 0 : std::cout << " sublaneFoe lane=" << myInternalLaneBefore->getID()
1811 : << " foeLane=" << foeLane->getID()
1812 : << " leader=" << leader->getID()
1813 0 : << " egoLane=" << ego->getLane()->getID()
1814 0 : << " leaderLane=" << leader->getLane()->getID()
1815 : << " gap=" << gap
1816 : << " egoLat=" << posLat
1817 : << " leaderLat=" << posLatLeader
1818 0 : << " leaderLatOffset=" << leader->getLatOffset(foeLane)
1819 0 : << " egoIndex=" << myInternalLaneBefore->getIndex()
1820 0 : << " foeIndex=" << foeLane->getIndex()
1821 0 : << " dist=" << dist
1822 0 : << " leaderBack=" << leader->getBackPositionOnLane(foeLane)
1823 0 : << "\n";
1824 : }
1825 : // there only is a conflict if the paths cross
1826 609607 : if ((posLat < posLatLeader && myInternalLaneBefore->getIndex() > foeLane->getIndex())
1827 1810509 : || (posLat > posLatLeader && myInternalLaneBefore->getIndex() < foeLane->getIndex())) {
1828 678097 : if (gDebugFlag1) {
1829 0 : std::cout << SIMTIME << " blocked by " << leader->getID() << " (sublane split) foeLane=" << foeLane->getID() << "\n";
1830 : }
1831 678097 : if (ignoreFoe(ego, leader)) {
1832 0 : continue;
1833 : }
1834 678097 : result.emplace_back(leader, gap, -1);
1835 : }
1836 : }
1837 : }
1838 : }
1839 : return result;
1840 3 : }
1841 :
1842 :
1843 : void
1844 497337510 : MSLink::checkWalkingAreaFoe(const MSVehicle* ego, const MSLane* foeLane, std::vector<const MSPerson*>* collectBlockers, LinkLeaders& result) const {
1845 497337510 : if (foeLane != nullptr && foeLane->getEdge().getPersons().size() > 0) {
1846 : // pedestrians may be on an arbitrary path across this
1847 : // walkingarea. make sure to keep enough distance.
1848 : // This is a simple but conservative solution that could be improved
1849 : // by ignoring pedestrians that are "obviously" not on a collision course
1850 85165 : double distToPeds = std::numeric_limits<double>::max();
1851 : assert(myInternalLaneBefore != nullptr);
1852 85165 : PositionVector egoPath = myInternalLaneBefore->getShape();
1853 85165 : if (ego->getLateralPositionOnLane() != 0) {
1854 33736 : egoPath.move2side((MSGlobals::gLefthand ? 1 : -1) * ego->getLateralPositionOnLane());
1855 : }
1856 861066 : for (MSTransportable* t : foeLane->getEdge().getPersons()) {
1857 775901 : MSPerson* p = static_cast<MSPerson*>(t);
1858 775901 : double dist = ego->getPosition().distanceTo2D(p->getPosition()) - p->getVehicleType().getLength();
1859 1458930 : const bool inFront = isInFront(ego, egoPath, p->getPosition()) || isInFront(ego, egoPath, getFuturePosition(p));
1860 775901 : if (inFront) {
1861 109249 : dist -= ego->getVehicleType().getMinGap();
1862 : }
1863 : #ifdef DEBUG_WALKINGAREA
1864 : if (ego->isSelected()) {
1865 : std::cout << SIMTIME << " veh=" << ego->getID() << " ped=" << p->getID()
1866 : << " pos=" << ego->getPosition() << " pedPos=" << p->getPosition()
1867 : << " futurePedPos=" << getFuturePosition(p)
1868 : << " rawDist=" << ego->getPosition().distanceTo2D(p->getPosition())
1869 : << " inFront=" << inFront
1870 : << " dist=" << dist << "\n";
1871 : }
1872 : #endif
1873 775901 : if (dist < ego->getVehicleType().getWidth() / 2 || inFront) {
1874 109540 : if (inFront) {
1875 109249 : const double oncomingFactor = isOnComingPed(ego, p);
1876 109249 : if (oncomingFactor > 0) {
1877 : // account for pedestrian movement while closing in
1878 53857 : const double timeToStop = sqrt(dist) / 2;
1879 53857 : const double pedDist = p->getMaxSpeed() * MAX2(timeToStop, TS) * oncomingFactor;
1880 53857 : dist = MAX2(0.0, dist - pedDist);
1881 : #ifdef DEBUG_WALKINGAREA
1882 : if (ego->isSelected()) {
1883 : std::cout << " timeToStop=" << timeToStop << " pedDist=" << pedDist << " factor=" << oncomingFactor << " dist2=" << dist << "\n";
1884 : }
1885 : #endif
1886 : }
1887 : }
1888 109540 : if (ignoreFoe(ego, p)) {
1889 25237 : continue;
1890 : }
1891 84303 : distToPeds = MIN2(distToPeds, dist);
1892 84303 : if (collectBlockers != nullptr) {
1893 0 : collectBlockers->push_back(p);
1894 : }
1895 : }
1896 : }
1897 85165 : if (distToPeds != std::numeric_limits<double>::max()) {
1898 : // leave extra space in front
1899 47565 : result.emplace_back(nullptr, -1, distToPeds);
1900 : }
1901 85165 : }
1902 497337510 : }
1903 :
1904 : bool
1905 1458930 : MSLink::isInFront(const MSVehicle* ego, const PositionVector& egoPath, const Position& pPos) const {
1906 1458930 : const double pedAngle = ego->getPosition().angleTo2D(pPos);
1907 1458930 : const double angleDiff = fabs(GeomHelper::angleDiff(ego->getAngle(), pedAngle));
1908 : #ifdef DEBUG_WALKINGAREA
1909 : if (ego->isSelected()) {
1910 : std::cout << " angleDiff=" << RAD2DEG(angleDiff) << "\n";
1911 : }
1912 : #endif
1913 1458930 : if (angleDiff < DEG2RAD(75)) {
1914 1019971 : return egoPath.distance2D(pPos) < ego->getVehicleType().getWidth() + MSPModel::SAFETY_GAP;
1915 : }
1916 : return false;
1917 : }
1918 :
1919 :
1920 : double
1921 109249 : MSLink::isOnComingPed(const MSVehicle* ego, const MSPerson* p) const {
1922 109249 : const double pedToEgoAngle = p->getPosition().angleTo2D(ego->getPosition());
1923 109249 : const double angleDiff = fabs(GeomHelper::angleDiff(p->getAngle(), pedToEgoAngle));
1924 : #ifdef DEBUG_WALKINGAREA
1925 : if (ego->isSelected()) {
1926 : std::cout << " ped-angleDiff=" << RAD2DEG(angleDiff) << " res=" << cos(angleDiff) << "\n";
1927 : }
1928 : #endif
1929 109249 : if (angleDiff <= DEG2RAD(90)) {
1930 : ;
1931 53857 : return cos(angleDiff);
1932 : } else {
1933 : return 0;
1934 : }
1935 : }
1936 :
1937 :
1938 : Position
1939 683029 : MSLink::getFuturePosition(const MSPerson* p, double timeHorizon) const {
1940 683029 : const double a = p->getAngle();
1941 683029 : const double dist = timeHorizon * p->getMaxSpeed();
1942 :
1943 683029 : const Position offset(cos(a) * dist, sin(a) * dist);
1944 683029 : return p->getPosition() + offset;
1945 : }
1946 :
1947 :
1948 : MSLink*
1949 8653681 : MSLink::getParallelLink(int direction) const {
1950 8653681 : if (direction == -1) {
1951 3430577 : return myParallelRight;
1952 5223104 : } else if (direction == 1) {
1953 5223104 : return myParallelLeft;
1954 : } else {
1955 : assert(false || myLane->getOpposite() != nullptr);
1956 : return nullptr;
1957 : }
1958 : }
1959 :
1960 : MSLink*
1961 172201 : MSLink::getOppositeDirectionLink() const {
1962 172201 : if (myLane->getOpposite() != nullptr && myLaneBefore->getOpposite() != nullptr) {
1963 42540 : for (MSLink* cand : myLane->getOpposite()->getLinkCont()) {
1964 40943 : if (cand->getLane() == myLaneBefore->getOpposite()) {
1965 : return cand;
1966 : }
1967 : }
1968 : }
1969 : return nullptr;
1970 : }
1971 :
1972 :
1973 : MSLink*
1974 5491162 : MSLink::computeParallelLink(int direction) {
1975 5491162 : const MSLane* const before = getLaneBefore()->getParallelLane(direction, false);
1976 5491162 : const MSLane* const after = getLane()->getParallelLane(direction, false);
1977 5491162 : if (before != nullptr && after != nullptr) {
1978 1003081 : for (MSLink* const link : before->getLinkCont()) {
1979 705516 : if (link->getLane() == after) {
1980 : return link;
1981 : }
1982 : }
1983 : }
1984 : return nullptr;
1985 : }
1986 :
1987 :
1988 : double
1989 817941 : MSLink::getZipperSpeed(const MSVehicle* ego, const double dist, double vSafe,
1990 : SUMOTime arrivalTime,
1991 : const BlockingFoes* foes) const {
1992 817941 : if (myFoeLinks.size() == 0) {
1993 : // link should have LINKSTATE_MAJOR in this case
1994 : assert(false);
1995 : return vSafe;
1996 817941 : } else if (myFoeLinks.size() > 1) {
1997 : throw ProcessError("Zipper junctions with more than two conflicting lanes are not supported (at junction '"
1998 10 : + myJunction->getID() + "')");
1999 : }
2000 817936 : const double brakeGap = ego->getCarFollowModel().brakeGap(ego->getSpeed(), ego->getCarFollowModel().getMaxDecel(), TS);
2001 914632 : if (dist > MAX2(myFoeVisibilityDistance, brakeGap)) {
2002 : #ifdef DEBUG_ZIPPER
2003 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
2004 : DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2005 : << " dist=" << dist << " bGap=" << brakeGap << " ignoring foes (arrival in " << STEPS2TIME(arrivalTime - now) << ")\n")
2006 : #endif
2007 : return vSafe;
2008 : }
2009 : #ifdef DEBUG_ZIPPER
2010 : DEBUGOUT(DEBUG_COND_ZIPPER, SIMTIME << " getZipperSpeed ego=" << ego->getID()
2011 : << " egoAT=" << arrivalTime
2012 : << " dist=" << dist
2013 : << " brakeGap=" << brakeGap
2014 : << " vSafe=" << vSafe
2015 : << " numFoes=" << foes->size()
2016 : << "\n")
2017 : #endif
2018 275105 : MSLink* foeLink = myFoeLinks[0];
2019 739188 : for (const auto& item : *foes) {
2020 464083 : if (!item->isVehicle()) {
2021 254025 : continue;
2022 : }
2023 464083 : const MSVehicle* foe = dynamic_cast<const MSVehicle*>(item);
2024 : assert(foe != 0);
2025 464083 : const ApproachingVehicleInformation& avi = foeLink->getApproaching(foe);
2026 464083 : const double foeDist = (foe->isActive() ? avi.dist : MAX2(0.0, avi.dist -
2027 32 : STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - foe->getLastActionTime()) * avi.speed));
2028 :
2029 254025 : if ( // ignore vehicles that arrive after us (unless they are ahead and we could easily brake for them)
2030 475005 : ((avi.arrivalTime > arrivalTime) && !couldBrakeForLeader(dist, foeDist, ego, foe)) ||
2031 : // also ignore vehicles that are behind us and are able to brake for us
2032 685067 : couldBrakeForLeader(foeDist, dist, foe, ego) ||
2033 : // resolve ties by lane index
2034 3045 : (avi.arrivalTime == arrivalTime && foeDist == dist && ego->getLane()->getIndex() < foe->getLane()->getIndex())) {
2035 : #ifdef DEBUG_ZIPPER
2036 : if (DEBUG_COND_ZIPPER) std::cout
2037 : << " ignoring foe=" << foe->getID()
2038 : << " foeAT=" << avi.arrivalTime
2039 : << " foeDist=" << avi.dist
2040 : << " foeDist2=" << foeDist
2041 : << " foeSpeed=" << avi.speed
2042 : << " egoSpeed=" << ego->getSpeed()
2043 : << " deltaDist=" << foeDist - dist
2044 : << " delteSpeed=" << avi.speed - foe->getCarFollowModel().getMaxDecel() - ego->getSpeed()
2045 : << " egoCouldBrake=" << couldBrakeForLeader(dist, foeDist, ego, foe)
2046 : << " foeCouldBrake=" << couldBrakeForLeader(foeDist, dist, foe, ego)
2047 : << "\n";
2048 : #endif
2049 254025 : continue;
2050 : }
2051 : // the idea behind speed adaption is three-fold:
2052 : // 1) ego needs to be in a car-following relationship with foe eventually
2053 : // thus, the ego speed should be equal to the follow speed once the foe enters
2054 : // the zipper junction
2055 : // 2) ego vehicle needs to put a certain distance beteen himself and foe (safeGap)
2056 : // achieving this distance can be spread over time but computing
2057 : // safeGap is subject to estimation errors of future speeds
2058 : // 3) deceleration can be spread out over the time until true
2059 : // car-following happens, at the start of speed adaptions, smaller
2060 : // decelerations should be sufficient
2061 :
2062 : // we cannot trust avi.arrivalSpeed if the foe has leader vehicles that are accelerating
2063 : // lets try to extrapolate
2064 210058 : const double uMax = foe->getLane()->getVehicleMaxSpeed(foe);
2065 210058 : const double uAccel = foe->getCarFollowModel().estimateSpeedAfterDistance(foeDist, avi.speed, foe->getCarFollowModel().getMaxAccel());
2066 : const double uEnd = MIN2(uMax, uAccel);
2067 210058 : const double uAvg = (avi.speed + uEnd) / 2;
2068 210058 : const double tf0 = foeDist / MAX2(NUMERICAL_EPS, uAvg);
2069 210058 : const double tf = MAX2(1.0, ceil((tf0) / TS) * TS);
2070 :
2071 210058 : const double vMax = ego->getLane()->getVehicleMaxSpeed(ego);
2072 210058 : const double vAccel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxAccel());
2073 210058 : const double vDecel = ego->getCarFollowModel().estimateSpeedAfterDistance(dist, ego->getSpeed(), ego->getCarFollowModel().getMaxDecel());
2074 : const double vEnd = MIN3(vMax, vAccel, MAX2(uEnd, vDecel));
2075 210058 : const double vAvg = (ego->getSpeed() + vEnd) / 2;
2076 210058 : const double te0 = dist / MAX2(NUMERICAL_EPS, vAvg);
2077 210058 : const double te = MAX2(1.0, ceil((te0) / TS) * TS);
2078 :
2079 210058 : const double gap = dist - foe->getVehicleType().getLength() - ego->getVehicleType().getMinGap() - foeDist;
2080 210058 : const double safeGap = ego->getCarFollowModel().getSecureGap(ego, foe, vEnd, uEnd, foe->getCarFollowModel().getMaxDecel());
2081 : // round t to next step size
2082 : // increase gap to safeGap by the time foe reaches link
2083 : // gap + u*t - (t * v + a * t^2 / 2) = safeGap
2084 210058 : const double deltaGap = gap + tf * uAvg - safeGap - vAvg * tf;
2085 210058 : const double a = 2 * deltaGap / (tf * tf);
2086 210058 : const double vSafeGap = ego->getSpeed() + ACCEL2SPEED(a);
2087 210058 : const double vFollow = ego->getCarFollowModel().followSpeed(
2088 210058 : ego, ego->getSpeed(), gap, avi.speed, foe->getCarFollowModel().getMaxDecel(), foe);
2089 :
2090 : // scale behavior based on ego time to link (te)
2091 210058 : const double w = MIN2(1.0, te / 10);
2092 210058 : const double maxDecel = w * ego->getCarFollowModel().getMaxDecel() + (1 - w) * ego->getCarFollowModel().getEmergencyDecel();
2093 210058 : const double vZipper = MAX3(vFollow, ego->getSpeed() - ACCEL2SPEED(maxDecel), w * vSafeGap + (1 - w) * vFollow);
2094 :
2095 : vSafe = MIN2(vSafe, vZipper);
2096 : #ifdef DEBUG_ZIPPER
2097 : if (DEBUG_COND_ZIPPER) std::cout << " adapting to foe=" << foe->getID()
2098 : << " foeDist=" << foeDist
2099 : << " foeSpeed=" << avi.speed
2100 : << " foeAS=" << avi.arrivalSpeed
2101 : << " egoSpeed=" << ego->getSpeed()
2102 : << " uMax=" << uMax
2103 : << " uAccel=" << uAccel
2104 : << " uEnd=" << uEnd
2105 : << " uAvg=" << uAvg
2106 : << " gap=" << gap
2107 : << " safeGap=" << safeGap
2108 : << "\n "
2109 : << " tf=" << tf
2110 : << " te=" << te
2111 : << " dg=" << deltaGap
2112 : << " aSafeGap=" << a
2113 : << " vMax=" << vMax
2114 : << " vAccel=" << vAccel
2115 : << " vDecel=" << vDecel
2116 : << " vEnd=" << vEnd
2117 : << " vSafeGap=" << vSafeGap
2118 : << " vFollow=" << vFollow
2119 : << " w=" << w
2120 : << " maxDecel=" << maxDecel
2121 : << " vZipper=" << vZipper
2122 : << " vSafe=" << vSafe
2123 : << "\n";
2124 : #endif
2125 : }
2126 : return vSafe;
2127 : }
2128 :
2129 :
2130 : bool
2131 475005 : MSLink::couldBrakeForLeader(double followDist, double leaderDist, const MSVehicle* follow, const MSVehicle* leader) {
2132 : return (// leader is ahead of follower
2133 475005 : followDist > leaderDist &&
2134 : // and follower could brake for 1 s to stay behind leader
2135 32755 : followDist - leaderDist > follow->getSpeed() - follow->getCarFollowModel().getMaxDecel() - leader->getSpeed());
2136 : }
2137 :
2138 :
2139 : void
2140 2745581 : MSLink::initParallelLinks() {
2141 2745581 : myParallelRight = computeParallelLink(-1);
2142 2745581 : myParallelLeft = computeParallelLink(1);
2143 2745581 : }
2144 :
2145 : bool
2146 60275 : MSLink::checkContOff() const {
2147 : // check whether this link gets to keep its cont status switching the tls off
2148 : // @note: this could also be pre-computed in netconvert
2149 : // we check whether there is any major link from this edge
2150 185310 : for (const MSLane* cand : myLaneBefore->getEdge().getLanes()) {
2151 368494 : for (const MSLink* link : cand->getLinkCont()) {
2152 243459 : if (link->getOffState() == LINKSTATE_TL_OFF_NOSIGNAL) {
2153 : return true;
2154 : }
2155 : }
2156 : }
2157 : return false;
2158 : }
2159 :
2160 : bool
2161 4244054 : MSLink::lateralOverlap(double posLat, double width, double posLat2, double width2) {
2162 4244054 : return fabs(posLat2 - posLat) < (width + width2) / 2;
2163 : }
2164 :
2165 : std::string
2166 0 : MSLink::getDescription() const {
2167 0 : return myLaneBefore->getID() + "->" + getViaLaneOrLane()->getID();
2168 : }
2169 :
2170 :
2171 : bool
2172 159790394 : MSLink::ignoreFoe(const SUMOTrafficObject* ego, const SUMOTrafficObject* foe) {
2173 159790394 : if (ego == nullptr || !ego->getParameter().wasSet(VEHPARS_JUNCTIONMODEL_PARAMS_SET)) {
2174 159757955 : return false;
2175 : }
2176 32439 : const SUMOVehicleParameter& param = ego->getParameter();
2177 71050 : for (const std::string& typeID : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_TYPES), "")).getVector()) {
2178 31537 : if (typeID == foe->getVehicleType().getID()) {
2179 : return true;
2180 : }
2181 32439 : }
2182 16136 : for (const std::string& id : StringTokenizer(param.getParameter(toString(SUMO_ATTR_JM_IGNORE_IDS), "")).getVector()) {
2183 2291 : if (id == foe->getID()) {
2184 : return true;
2185 : }
2186 7074 : }
2187 6771 : return false;
2188 : }
2189 :
2190 :
2191 : void
2192 88360 : MSLink::updateDistToFoePedCrossing(double dist) {
2193 88360 : myDistToFoePedCrossing = MIN2(myDistToFoePedCrossing, dist);
2194 88360 : }
2195 :
2196 :
2197 : std::pair<const SUMOVehicle* const, const MSLink::ApproachingVehicleInformation>
2198 465039 : MSLink::getClosest() const {
2199 : assert(getApproaching().size() > 0);
2200 : double minDist = std::numeric_limits<double>::max();
2201 : auto closestIt = getApproaching().begin();
2202 930579 : for (auto apprIt = getApproaching().begin(); apprIt != getApproaching().end(); apprIt++) {
2203 465540 : if (apprIt->second.dist < minDist) {
2204 : minDist = apprIt->second.dist;
2205 : closestIt = apprIt;
2206 : }
2207 : }
2208 : // maybe a parallel link has a closer vehicle
2209 : /*
2210 : for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
2211 : if (link2 != link) {
2212 : for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
2213 : if (apprIt2->second.dist < minDist) {
2214 : minDist = apprIt2->second.dist;
2215 : closestIt = apprIt2;
2216 : }
2217 : }
2218 : }
2219 : }
2220 : */
2221 465039 : return *closestIt;
2222 : }
2223 :
2224 :
2225 : /****************************************************************************/
|