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