Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSDriveWay.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
18// A sequende of rail tracks (lanes) that may be used as a "set route" (Fahrstraße)
19/****************************************************************************/
20#include <config.h>
21#include <cassert>
22#include <utility>
23
26#include <microsim/MSStop.h>
27#include <microsim/MSLane.h>
28#include <microsim/MSEdge.h>
29#include <microsim/MSLink.h>
30#include <microsim/MSNet.h>
33#include <mesosim/MELoop.h>
34#include "MSRailSignal.h"
35#include "MSDriveWay.h"
36#include "MSRailSignalControl.h"
37
38#define DRIVEWAY_SANITY_CHECK
39//#define SUBDRIVEWAY_WARN_NOCONFLICT
40
41//#define DEBUG_BUILD_DRIVEWAY
42//#define DEBUG_BUILD_SUBDRIVEWAY
43//#define DEBUG_ADD_FOES
44//#define DEBUG_BUILD_SIDINGS
45//#define DEBUG_DRIVEWAY_BUILDROUTE
46//#define DEBUG_CHECK_FLANKS
47//#define DEBUG_SIGNALSTATE_PRIORITY
48//#define DEBUG_SIGNALSTATE
49//#define DEBUG_MOVEREMINDER
50//#define DEBUG_MATCH
51
52#define DEBUG_HELPER(obj) ((obj) != nullptr && (obj)->isSelected())
53//#define DEBUG_HELPER(obj) ((obj)->getID() == "")
54//#define DEBUG_HELPER(obj) (true)
55
56#define DEBUG_DW_ID ""
57#define DEBUG_COND_DW(obj) (obj->getID() == DEBUG_DW_ID || DEBUG_DW_ID == std::string("ALL"))
58#define DEBUG_COND_DW2 (getID() == DEBUG_DW_ID || DEBUG_DW_ID == std::string("ALL"))
59
60// ===========================================================================
61// static value definitions
62// ===========================================================================
64std::set<const MSEdge*> MSDriveWay::myBlockLengthWarnings;
67std::map<const MSLink*, std::vector<MSDriveWay*> > MSDriveWay::mySwitchDriveWays;
68std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myReversalDriveWays;
69std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myDepartureDriveways;
70std::map<const MSJunction*, int> MSDriveWay::myDepartDrivewayIndex;
71std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myDepartureDrivewaysEnds;
72std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myEndingDriveways;
73std::map<const MSEdge*, std::vector<std::pair<MSDriveWay*, MSDriveWay*> >, ComparatorNumericalIdLess> MSDriveWay::mySidingDriveways;
74std::vector<const MSEdge*> MSDriveWay::myCurrentSidingCheck;
75std::map<ConstMSEdgeVector, MSDriveWay*> MSDriveWay::myDriveWayRouteLookup;
76std::map<std::string, MSDriveWay*> MSDriveWay::myDriveWayLookup;
77const std::vector<MSDriveWay*> MSDriveWay::EMPTY_DRIVEWAY_VECTOR;
78
79// ---------------------------------------------------------------------------
80// static initialisation methods
81// ---------------------------------------------------------------------------
82void
84 myWriteVehicles = OptionsCont::getOptions().isSet("railsignal-vehicle-output");
85 myMovingBlockMaxDist = OptionsCont::getOptions().getFloat("railsignal.moving-block.max-dist");
86}
87
88// ===========================================================================
89// MSDriveWay method definitions
90// ===========================================================================
91
92
93MSDriveWay::MSDriveWay(const MSLink* origin, const std::string& id, bool temporary) :
94 MSMoveReminder("DriveWay_" + (temporary ? "tmp" : id)),
95 Named(id),
96 myNumericalID(temporary ? -1 : myGlobalDriveWayIndex++),
97 myOrigin(origin),
98 myActive(nullptr),
99 myCoreSize(0),
100 myForwardEdgeCount(0),
101 myFoundSignal(false),
102 myFoundJump(false),
103 myTerminateRoute(false),
104 myAbortedBuild(false),
105 myBidiEnded(false),
106 myParent(nullptr)
107{}
108
109
111 for (const MSDriveWay* sub : mySubDriveWays) {
112 delete sub;
113 }
114 mySubDriveWays.clear();
115}
116
117void
120 myBlockLengthWarnings.clear();
121 myWriteVehicles = false;
122
123 for (auto item : myDepartureDriveways) {
124 for (MSDriveWay* dw : item.second) {
125 delete dw;
126 }
127 }
135}
136
137void
139 for (auto item : myEndingDriveways) {
140 for (MSDriveWay* dw : item.second) {
141 dw->myTrains.clear();
142 }
143 }
144}
145
146
147bool
149#ifdef DEBUG_MOVEREMINDER
150 std::cout << SIMTIME << " notifyEnter " << getDescription() << " veh=" << veh.getID() << " lane=" << (MSGlobals::gUseMesoSim ? veh.getCurrentEdge()->getID() : Named::getIDSecure(enteredLane)) << " reason=" << reason << "\n";
151#endif
152
154 if ((enteredLane == myLane || (MSGlobals::gUseMesoSim && veh.getCurrentEdge() == &myLane->getEdge()))
155 && (reason == NOTIFICATION_DEPARTED || reason == NOTIFICATION_JUNCTION || reason == NOTIFICATION_PARKING)) {
156 SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
157 MSRouteIterator firstIt = std::find(sveh.getCurrentRouteEdge(), sveh.getRoute().end(), myLane->getNextNormal());
158 if (match(firstIt, sveh.getRoute().end())) {
159 if (myTrains.count(&sveh) == 0) {
160 enterDriveWay(sveh, reason);
161 }
162 return true;
163 }
164 } else if (reason == NOTIFICATION_REROUTE) {
165 SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
166 assert(myTrains.count(&sveh) == 0);
167 int movedPast = matchesPastRoute(sveh);
168 // vehicle must still be one the drivway
169 if (movedPast >= 0 && movedPast < myForwardEdgeCount) {
170 enterDriveWay(sveh, reason);
171 return true;
172 }
173 }
174 }
175 return false;
176}
177
178
179bool
180MSDriveWay::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, Notification reason, const MSLane* enteredLane) {
181 UNUSED_PARAMETER(enteredLane);
182#ifdef DEBUG_MOVEREMINDER
183 std::cout << SIMTIME << " notifyLeave " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(enteredLane) << " reason=" << toString(reason) << "\n";
184#endif
186 // leaving network with departure, teleport etc
188 myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
189 if (myWriteVehicles) {
190 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
191 }
192 return false;
194 // notifyLeave is called before moving the route iterator
195 const MSLane* leftLane = (*(dynamic_cast<SUMOVehicle&>(veh).getCurrentRouteEdge()))->getLanes().front();
196 return notifyLeaveBack(veh, reason, leftLane);
197 } else {
198 return true;
199 }
200 } else {
201 return false;
202 }
203}
204
205
206bool
208#ifdef DEBUG_MOVEREMINDER
209 std::cout << SIMTIME << " notifyLeaveBack " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(leftLane) << " reason=" << toString(reason) << "\n";
210#endif
212 if (leftLane == myForward.back() && (veh.getBackLane() != leftLane->getBidiLane() || MSGlobals::gUseMesoSim)) {
213 myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
214 if (myWriteVehicles) {
215 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
216 }
217 return false;
218 } else {
219 return true;
220 }
221 } else {
222 return false;
223 }
224}
225
226
227bool
229#ifdef DEBUG_MOVEREMINDER
230 std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << "\n";
231#endif
232 assert(veh.isVehicle());
234 SUMOVehicle* sveh = dynamic_cast<SUMOVehicle*>(&veh);
235 assert(myTrains.count(sveh) != 0);
236 if (matchesPastRoute(*sveh) >= 0) {
237 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
238 return true;
239 }
240 // no match found, remove
241 myTrains.erase(sveh);
242 if (myWriteVehicles) {
244 }
245 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " invalid\n";
246 }
247 return false;
248}
249
250
251int
253 // look backwards along the route to find the driveway lane
254 const ConstMSEdgeVector& routeEdges = sveh.getRoute().getEdges();
255 for (int i = sveh.getRoutePosition(); i >= 0; i--) {
256 if (routeEdges[i] == myLane->getNextNormal()) {
257 MSRouteIterator firstIt = routeEdges.begin() + i;
258 if (match(firstIt, sveh.getRoute().end())) {
259 // driveway is still valid after rerouting
260 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
261 return sveh.getRoutePosition() - i;
262 }
263 break;
264 }
265 }
266 return -1;
267}
268
269
270void
272 myTrains.insert(&sveh);
273 if (myOrigin != nullptr) {
275 }
276 for (const MSDriveWay* foe : myFoes) {
277 if (foe->myOrigin != nullptr) {
279 }
280 }
281 if (myWriteVehicles) {
282 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, true, sveh.getID(), reason));
283 }
284}
285
286bool
287MSDriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
288 if (foeDriveWayOccupied(true, closest.first, occupied)) {
289 return false;
290 }
291 for (MSLink* foeLink : myConflictLinks) {
292 if (hasLinkConflict(closest, foeLink)) {
293#ifdef DEBUG_SIGNALSTATE
294 if (gDebugFlag4 || DEBUG_HELPER(closest.first)) {
295 std::cout << getID() << " linkConflict with " << getTLLinkID(foeLink) << "\n";
296 }
297#endif
298 return false;
299 }
300 }
301 myActive = closest.first;
302 return true;
303}
304
305
306bool
307MSDriveWay::hasLinkConflict(const Approaching& veh, const MSLink* foeLink) const {
308#ifdef DEBUG_SIGNALSTATE_PRIORITY
309 if (gDebugFlag4) {
310 std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << " ego=" << Named::getIDSecure(veh.first) << "\n";
311 }
312#endif
313 if (foeLink->getApproaching().size() > 0) {
314 Approaching foe = foeLink->getClosest();
315#ifdef DEBUG_SIGNALSTATE_PRIORITY
316 if (gDebugFlag4) {
317 std::cout << " approaching foe=" << foe.first->getID() << "\n";
318 }
319#endif
320 if (foe.first == veh.first) {
321 return false;
322 }
323 const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
324 assert(foeTLL != nullptr);
325 const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
326 MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
327 if (foeRS != nullptr) {
328 const MSDriveWay& foeDriveWay = foeRS->retrieveDriveWayForVeh(foeLink->getTLIndex(), foe.first);
329 MSEdgeVector occupied;
330 if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied) ||
331 !foeRS->constraintsAllow(foe.first) ||
332 !overlap(foeDriveWay) ||
333 getFoeOrSubFoe(&foeDriveWay) == nullptr ||
334 canUseSiding(veh.first, getFoeOrSubFoe(&foeDriveWay)).first) {
335#ifdef DEBUG_SIGNALSTATE_PRIORITY
336 if (gDebugFlag4 || veh.first->isSelected()) {
337 if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied)) {
338 std::cout << " foe blocked\n";
339 } else if (!foeRS->constraintsAllow(foe.first)) {
340 std::cout << " foe constrained\n";
341 } else if (!overlap(foeDriveWay)) {
342 std::cout << " no overlap with foeDW=" << foeDriveWay.getID() << "\n";
343 } else if (getFoeOrSubFoe(&foeDriveWay) == nullptr) {
344 std::cout << " foeDW=" << foeDriveWay.getID() << " is not a foe to " << getID() << "\n";
345 } else if (canUseSiding(veh.first, &foeDriveWay).first) {
346 std::cout << " use siding\n";
347 }
348 }
349#endif
350 return false;
351 }
352#ifdef DEBUG_SIGNALSTATE_PRIORITY
353 if (gDebugFlag4) {
354 std::cout
355 << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
356 << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
357 << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
358 << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
359 << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
360 << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
361 << "\n";
362 }
363#endif
364 const bool yield = mustYield(veh, foe);
366 MSRailSignal::rivalVehicles().push_back(foe.first);
367 if (yield) {
368 MSRailSignal::priorityVehicles().push_back(foe.first);
369 }
370 }
371 return yield;
372 }
373 }
374 return false;
375}
376
377
378const MSDriveWay*
380 if (std::find(myFoes.begin(), myFoes.end(), dw) != myFoes.end()) {
381 return dw;
382 }
383 for (const MSDriveWay* sub : dw->mySubDriveWays) {
384 const MSDriveWay* foe = getFoeOrSubFoe(sub);
385 if (foe != nullptr) {
386 return foe;
387 }
388 }
389 return nullptr;
390}
391
392
393bool
395 if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
396 if (foe.second.arrivalTime == veh.second.arrivalTime) {
397 if (foe.first->getSpeed() == veh.first->getSpeed()) {
398 if (foe.second.dist == veh.second.dist) {
399 if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
400 return foe.first->getNumericalID() < veh.first->getNumericalID();
401 } else {
402 return foe.first->getWaitingTime() > veh.first->getWaitingTime();
403 }
404 } else {
405 return foe.second.dist < veh.second.dist;
406 }
407 } else {
408 return foe.first->getSpeed() > veh.first->getSpeed();
409 }
410 } else {
411 return foe.second.arrivalTime < veh.second.arrivalTime;
412 }
413 } else {
414 return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
415 }
416}
417
418
419bool
420MSDriveWay::conflictLaneOccupied(bool store, const SUMOVehicle* ego) const {
421 for (const MSLane* lane : myConflictLanes) {
422 if (!lane->isEmpty()) {
423 std::string joinVehicle = "";
424 if (ego != nullptr && !MSGlobals::gUseMesoSim) {
426 if (stop != nullptr) {
427 joinVehicle = stop->join;
428 }
429 }
430#ifdef DEBUG_SIGNALSTATE
431 if (gDebugFlag4) {
432 std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
433 if (joinVehicle != "") {
434 std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
435 lane->releaseVehicles();
436 }
437 }
438#endif
439 if (lane->getVehicleNumberWithPartials() == 1) {
440 MSVehicle* foe = lane->getLastAnyVehicle();
441 if (joinVehicle != "") {
442 if (foe->getID() == joinVehicle && foe->isStopped()) {
443#ifdef DEBUG_SIGNALSTATE
444 if (gDebugFlag4) {
445 std::cout << " ignore join-target '" << joinVehicle << "\n";
446 }
447#endif
448 continue;
449 }
450 }
451 if (ego != nullptr) {
452 if (foe == ego && std::find(myForward.begin(), myForward.end(), lane) == myForward.end()) {
453#ifdef DEBUG_SIGNALSTATE
454 if (gDebugFlag4) {
455 std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
456 }
457#endif
458 continue;
459 }
460 if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
461#ifdef DEBUG_SIGNALSTATE
462 if (gDebugFlag4) {
463 std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
464 }
465#endif
466 continue;
467 }
468 }
469 }
470 if (MSRailSignal::storeVehicles() && store) {
471 MSRailSignal::blockingVehicles().push_back(lane->getLastAnyVehicle());
472 }
473 return true;
474 }
475 }
476 return false;
477}
478
479
480bool
482 for (const MSDriveWay* foeDW : myFoes) {
483 if (foeDW->myOrigin != nullptr && foeDW->myOrigin->getApproaching().size() > 0) {
484#ifdef DEBUG_SIGNALSTATE
485 if (gDebugFlag4) {
486 std::cout << SIMTIME << " foeLink=" << foeDW->myOrigin->getDescription() << " approachedBy=" << foeDW->myOrigin->getApproaching().begin()->first->getID() << "\n";
487 }
488#endif
489 return true;
490 }
491 }
492 return false;
493}
494
495
496bool
497MSDriveWay::foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const {
498 for (const MSDriveWay* foeDW : myFoes) {
499 if (!foeDW->myTrains.empty()) {
500#ifdef DEBUG_SIGNALSTATE
501 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
502 std::cout << SIMTIME << " " << getID() << " foeDriveWay " << foeDW->getID() << " occupied ego=" << Named::getIDSecure(ego) << " foeVeh=" << toString(foeDW->myTrains) << "\n";
503 }
504#endif
505 if (foeDW->myTrains.size() == 1) {
506 SUMOVehicle* foe = *foeDW->myTrains.begin();
507 if (foe == ego) {
508#ifdef DEBUG_SIGNALSTATE
509 if (gDebugFlag4 || DEBUG_HELPER(ego)) {
510 std::cout << " ignore ego as foe '" << Named::getIDSecure(ego) << "\n";
511 }
512#endif
513 continue;
514 }
515 if (hasJoin(ego, foe)) {
516 continue;
517 }
518 }
519 std::pair<bool, const MSDriveWay*> useSiding = canUseSiding(ego, foeDW);
520#ifdef DEBUG_SIGNALSTATE
521 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
522 auto it = mySidings.find(foeDW);
523 int numSidings = 0;
524 if (it != mySidings.end()) {
525 numSidings = it->second.size();
526 }
527 std::cout << " ego=" << Named::getIDSecure(ego) << " useSiding=" << useSiding.first << " sidingFoe=" << Named::getIDSecure(useSiding.second) << " numSidings=" << numSidings << "\n";
528 }
529#endif
530 if (useSiding.first) {
531 continue;
532 } else {
533 if (MSRailSignal::storeVehicles() && store) {
534 for (SUMOVehicle* foe : foeDW->myTrains) {
535 MSRailSignal::blockingVehicles().push_back(foe);
536 }
537 MSRailSignal::blockingDriveWays().push_back(foeDW);
538 }
539 for (const SUMOVehicle* foe : foeDW->myTrains) {
540 occupied.push_back(const_cast<MSEdge*>(foe->getEdge()));
541 MSEdge* bidi = const_cast<MSEdge*>(foe->getEdge()->getBidiEdge());
542 if (bidi != nullptr) {
543 occupied.push_back(bidi);
544 }
546 }
547 if (ego != nullptr && MSGlobals::gTimeToTeleportRSDeadlock > 0
548 && (ego->getWaitingTime() > ego->getVehicleType().getCarFollowModel().getStartupDelay() || !ego->isOnRoad())) {
549 // if there is an occupied siding, it becomes part of the waitRelation
550 SUMOVehicle* foe = *(useSiding.second == nullptr ? foeDW : useSiding.second)->myTrains.begin();
551 const MSRailSignal* rs = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
553 }
554 return true;
555 }
556 } else if (foeDW != this && isDepartDriveway() && !foeDW->isDepartDriveway()) {
557 if (foeDW->myOrigin->getApproaching().size() > 0) {
558 Approaching foeA = foeDW->myOrigin->getClosest();
559 const SUMOVehicle* foe = foeA.first;
560 if (foeA.second.dist < foe->getBrakeGap(true)) {
561 MSRouteIterator firstIt = std::find(foe->getCurrentRouteEdge(), foe->getRoute().end(), foeDW->myRoute.front());
562 if (firstIt != foe->getRoute().end()) {
563 if (foeDW->match(firstIt, foe->getRoute().end())) {
564 bool useSiding = canUseSiding(ego, foeDW).first;
565#ifdef DEBUG_SIGNALSTATE
566 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
567 std::cout << SIMTIME << " " << getID() << " blocked by " << foeDW->getID() << " (approached by " << foe->getID() << ") useSiding=" << useSiding << "\n";
568 }
569#endif
570 if (useSiding) {
571 //std::cout << SIMTIME << " " << getID() << " ego=" << ego->getID() << " foeDW=" << foeDW->getID() << " myFoes=" << toString(myFoes) << "\n";
572 continue;
573 } else {
574 return true;
575 }
576 }
577 }
578 }
579 }
580 }
581 }
582 for (const std::set<const MSDriveWay*>& dlFoes : myDeadlocks) {
583 bool allOccupied = true;
584 for (const MSDriveWay* dlFoe : dlFoes) {
585 if (dlFoe->myTrains.empty()) {
586 allOccupied = false;
587 //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck clear " << dlFoe->getID() << "\n";
588 break;
589 }
590 }
591 if (allOccupied) {
592#ifdef DEBUG_SIGNALSTATE
593 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
594 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck " << joinNamedToString(dlFoes, " ") << " myFoes=" << toString(myFoes) << "\n";
595 }
596#endif
597 for (const MSDriveWay* dlFoe : dlFoes) {
598 MSRailSignal::blockingDriveWays().push_back(dlFoe);
599 }
600 // for addWaitRelation we need to find the foe that results in the
601 // longest chain (otherwise the deadlock relation is smaller than the original)
602 int start = myForwardEdgeCount;
603 bool foundFoe = false;
604 while (start < (int)myRoute.size() && !foundFoe) {
605 const MSEdge* e = myRoute[start];
607 const MSEdge* p = myRoute[start - 1];
608 const MSLink* link = p->getLanes().front()->getLinkTo(e->getLanes().front());
609 if (link != nullptr && link->isTLSControlled()) {
610 MSRailSignal* rs = const_cast<MSRailSignal*>(dynamic_cast<const MSRailSignal*>(link->getTLLogic()));
611 const MSDriveWay& cand = rs->getExistingDriveWay(link, myRoute.begin() + start, myRoute.end());
612 for (const MSDriveWay* dlFoe : dlFoes) {
613 if (std::find(cand.myFoes.begin(), cand.myFoes.end(), dlFoe) != cand.myFoes.end()) {
614 foundFoe = true;
615 const MSRailSignal* rs2 = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
616 MSRailSignalControl::getInstance().addWaitRelation(ego, rs2, *dlFoe->myTrains.begin(), nullptr);
617 }
618 }
619 }
620 }
621 start += 1;
622 }
623 if (!foundFoe) {
624 for (const MSDriveWay* dlFoe : dlFoes) {
625 const MSRailSignal* rs2 = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
626 MSRailSignalControl::getInstance().addWaitRelation(ego, rs2, *dlFoe->myTrains.begin(), nullptr);
627 break;
628 }
629 }
630 return true;
631 }
632 }
633 return false;
634}
635
636
637bool
639 if (ego != nullptr && !MSGlobals::gUseMesoSim) {
640 std::string joinVehicle = "";
642 if (stop != nullptr) {
643 joinVehicle = stop->join;
644 }
645 if (joinVehicle == "" && !ego->hasDeparted() && ego->getStops().size() > 1) {
646 // check one more stop
647 auto it = ego->getStops().begin();
648 std::advance(it, 1);
649 joinVehicle = it->pars.join;
650 }
651 if (joinVehicle != "") {
652#ifdef DEBUG_SIGNALSTATE
653 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
654 std::cout << " joinVehicle=" << joinVehicle << "\n";
655 }
656#endif
657 if (foe->getID() == joinVehicle && foe->isStopped()) {
658#ifdef DEBUG_SIGNALSTATE
659 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
660 std::cout << " ignore join-target '" << joinVehicle << "\n";
661 }
662#endif
663 return true;
664 }
665 }
666
667 if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
668#ifdef DEBUG_SIGNALSTATE
669 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
670 std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
671 }
672#endif
673 return true;
674 }
675 }
676 return false;
677}
678
679
680std::pair<bool, const MSDriveWay*>
681MSDriveWay::canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, const MSEdge* recurseSidingEnd) const {
682 auto it = mySidings.find(foe);
683 if (it != mySidings.end()) {
684 for (auto siding : it->second) {
685 // assume siding is usuable when computing state for unapproached signal (ego == nullptr)
686 if (ego == nullptr || siding.length >= ego->getLength()) {
687 // if the siding is already "reserved" by another vehicle we cannot use it here
688 const MSEdge* sidingEnd = myRoute[siding.end];
689 bool checkNext = false;
690 for (MSDriveWay* sidingApproach : myEndingDriveways[sidingEnd]) {
691 if (!sidingApproach->myTrains.empty() && *sidingApproach->myTrains.begin() == ego && sidingEnd == recurseSidingEnd) {
692 // check next siding if if exists
693 checkNext = true;
694#ifdef DEBUG_SIGNALSTATE
695 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
696 std::cout << " checkNext\n";
697 }
698#endif
699 continue;
700 }
701 if ((!sidingApproach->myTrains.empty() && *sidingApproach->myTrains.begin() != ego)
702 || std::find(myCurrentSidingCheck.begin(), myCurrentSidingCheck.end(), sidingEnd) != myCurrentSidingCheck.end()) {
703 // possibly the foe vehicle can use the other part of the siding
704 if (recurseSidingEnd == nullptr) {
705 const SUMOVehicle* foeVeh = nullptr;
706 if (!foe->myTrains.empty()) {
707 foeVeh = *foe->myTrains.begin();
708 } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
709 foeVeh = foe->myOrigin->getClosest().first;
710 }
711 if (foeVeh == nullptr) {
712 WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
713 continue;
714 }
715 const MSDriveWay* foe2 = foe->isSubDriveWay() ? foe->myParent : foe;
716 const MSDriveWay* this2 = foe2->getFoeOrSubFoe(this);
717#ifdef DEBUG_SIGNALSTATE
718 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
719 std::cout << " foe2=" << foe2->getID() << " this2=" << this2->getID() << "\n";
720 }
721#endif
722 if (this2 != nullptr && foe2->canUseSiding(foeVeh, this2, sidingEnd).first) {
723 continue;
724 }
725 }
726 // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation (#18416)
727#ifdef DEBUG_SIGNALSTATE
728 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
729 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
730 << " foeVeh=" << toString(foe->myTrains)
731 << " sidingEnd=" << sidingEnd->getID() << " sidingApproach=" << sidingApproach->getID() << " approaching=" << toString(sidingApproach->myTrains) << "\n";
732 }
733#endif
734 return std::make_pair(false, sidingApproach);
735 }
736 }
737 // vehicles approaching intermediate driveways could also make the siding unusable but would not show up as sidingApproaches
738 for (int i : siding.intermediateEnds) {
739 const MSEdge* intermediateEnd = myRoute[i];
740 for (MSDriveWay* intermediateApproach : myEndingDriveways[intermediateEnd]) {
741 if (!intermediateApproach->myTrains.empty()
742 && (*intermediateApproach->myTrains.begin() != ego || intermediateEnd == recurseSidingEnd)) {
743 SUMOVehicle* onApproach = *intermediateApproach->myTrains.begin();
744 if (std::find(onApproach->getCurrentRouteEdge(), onApproach->getRoute().end(), sidingEnd) == onApproach->getRoute().end()) {
745 // intermediate vehicle does not make use of the siding
746 continue;
747 }
748 // possibly the foe vehicle can use the other part of the siding
749 if (recurseSidingEnd == nullptr) {
750 const SUMOVehicle* foeVeh = nullptr;
751 if (!foe->myTrains.empty()) {
752 foeVeh = *foe->myTrains.begin();
753 } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
754 foeVeh = foe->myOrigin->getClosest().first;
755 }
756 if (foeVeh == nullptr) {
757 WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
758 continue;
759 }
760 const MSDriveWay* foe2 = foe->isSubDriveWay() ? foe->myParent : foe;
761 const MSDriveWay* this2 = foe2->getFoeOrSubFoe(this);
762 if (this2 != nullptr && foe2->canUseSiding(foeVeh, this2, intermediateEnd).first) {
763 continue;
764 }
765 }
766 // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation
767#ifdef DEBUG_SIGNALSTATE
768 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
769 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
770 << " foeVeh=" << toString(foe->myTrains)
771 << " sidingEnd=" << sidingEnd->getID() << " intermediateApproach=" << intermediateApproach->getID() << " approaching=" << toString(intermediateApproach->myTrains) << "\n";
772 }
773#endif
774 return std::make_pair(false, intermediateApproach);
775 }
776 }
777 }
778 if (checkNext) {
779 continue;
780 }
781#ifdef DEBUG_SIGNALSTATE
782 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
783 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
784 << " foeVeh=" << toString(foe->myTrains)
785 << " sidingEnd=" << sidingEnd->getID() << " usable\n";
786 }
787#endif
788 return std::make_pair(true, nullptr);
789 }
790 }
791 }
792#ifdef DEBUG_SIGNALSTATE
793 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
794 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID() << " noSidings\n";
795 }
796#endif
797 return std::make_pair(false, nullptr);
798}
799
800
801bool
803 const MSEdge* end = &myForward.back()->getEdge();
804 const auto it = mySidingDriveways.find(end);
805 if (it != mySidingDriveways.end()) {
806 for (const auto& item : it->second) {
807 if (!item.first->myTrains.empty() && !item.second->myTrains.empty()
808 && bidiBlockedBy(*item.second)) {
809 // we found two driveways that are in conflict and
810 // could make use of this siding. Inserting a vehicle here could create deadlock.
811#ifdef DEBUG_SIGNALSTATE
813 std::cout << SIMTIME << " sidingDeadlock insertionDw=" << getID() << " approachingDW=" << item.first->getID() << " foeDW=" << item.second->getID() << "\n";
814 }
815#endif
816 myCurrentSidingCheck.push_back(end);
817 if (veh->getLength() > end->getLength() && !MSGlobals::gUseMesoSim) {
818 double backDist = veh->getLength() - getForwardDistance((int)myForward.size() - 1);
819 const MSLane* lane = myForward.front();
820 const MSLane* prev = lane->getLogicalPredecessorLane();
821 while (backDist > 0 && prev != nullptr) {
822 backDist -= lane->getLength();
823 const MSLink* link = prev->getLinkTo(lane);
824 if (prev->isNormal() && link->getTLLogic() != nullptr
826 // inserted train back reaches onto this edge
827 myCurrentSidingCheck.push_back(&prev->getEdge());
828 }
829 lane = prev;
830 prev = lane->getLogicalPredecessorLane();
831 }
832 }
833 const bool requiredSiding = !item.first->canUseSiding(*item.first->myTrains.begin(), item.second).first;
835 if (requiredSiding) {
836 return true;
837 }
838 }
839 }
840 }
841 return false;
842}
843
844
845bool
846MSDriveWay::overlap(const MSDriveWay& other) const {
847 for (int i = 0; i < myCoreSize; i++) {
848 for (int j = 0; j < other.myCoreSize; j++) {
849 const MSEdge* edge = myRoute[i];
850 const MSEdge* edge2 = other.myRoute[j];
851 if (edge->getToJunction() == edge2->getToJunction()
852 || edge->getToJunction() == edge2->getFromJunction()
853 || edge->getFromJunction() == edge2->getFromJunction()) {
854 // XXX might be rail_crossing with parallel tracks
855 return true;
856 }
857 }
858 }
859 return false;
860}
861
862
863bool
865 for (const MSLane* lane : myForward) {
866 for (const MSLane* lane2 : other.myForward) {
867 if (lane == lane2) {
868 return true;
869 }
870 }
871 for (const MSLane* lane2 : other.myBidi) {
872 if (lane == lane2) {
873 if (bidiBlockedBy(other)) {
874 // it's only a deadlock if both trains block symmetrically
875 return true;
876 }
877 }
878 }
879 auto it = std::lower_bound(other.myBidiExtendedSorted.begin(), other.myBidiExtendedSorted.end(), lane);
880 if (it != other.myBidiExtendedSorted.end() && *it == lane) {
881 if (bidiBlockedBy(other)) {
882 // it's only a deadlock if both trains block symmetrically
883 return true;
884 }
885 }
886 }
887 return false;
888}
889
890
891bool
893 for (const MSLane* lane : myForward) {
894 for (const MSLane* lane2 : other.myForward) {
895 if (lane->isNormal() && lane2->isNormal() && lane->getEdge().getToJunction() == lane2->getEdge().getToJunction()) {
896 if (lane->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL
897 && lane == myForward.back()
898 && &lane->getEdge() != myRoute.back()) {
899 // switch/crossing is also a rail_signal (direct control) at the end of the forward section.
900 // (and the route continues)
901 // This means the conflict is already guarded
902 return false;
903 }
904 return true;
905 }
906 }
907 }
908 if (myOrigin != nullptr && other.myOrigin != nullptr
909 && myOrigin->getJunction() == other.myOrigin->getJunction()
910 //&& myForward.front()->isInternal() && other.myForward.front()->isInternal()
911 && myOrigin->getJunction()->getLogic() != nullptr
913 // switch/crossing is also a rail_signal (direct control)
914 if (!(myForward.front()->isInternal() && other.myForward.front()->isInternal())) {
915 return false;
916 }
917 return true;
918 }
919 if (other.myOrigin != nullptr && other.myForward.front()->isInternal()) {
920 for (int i = 0; i < (int)myForward.size() - 1; i++) {
921 const MSLane* lane = myForward[i];
922 if (lane->getToJunction() == other.myOrigin->getJunction()) {
923 const MSLane* next = myForward[i + 1];
924 const MSLink* link = lane->getLinkTo(next);
925 if (link && link->getTLLogic() == nullptr) {
926 // switch/crossing is also a rail_signal (direct control) but own link is uncontrolled
927 if (lane->getToJunction()->getLogic() != nullptr
928 && lane->getToJunction()->getLogic()->getFoesFor(link->getIndex()).test(other.myOrigin->getIndex())) {
929 // and links are in conflict
930 return true;
931 }
932 }
933 }
934 }
935 }
936 return false;
937}
938
939
940bool
942 for (const MSLane* lane : myBidi) {
943 for (const MSLane* lane2 : other.myForward) {
944 if (lane == lane2) {
945 return true;
946 }
947 }
948 }
949
950 for (const MSLane* lane2 : other.myForward) {
951 auto it = std::lower_bound(myBidiExtendedSorted.begin(), myBidiExtendedSorted.end(), lane2);
952 if (it != myBidiExtendedSorted.end() && *it == lane2) {
953 if (overlap(other)) {
954 return true;
955 }
956 }
957 }
958
959 return false;
960}
961
962
963bool
965 const MSLane* end = other.myForward.back();
966 for (const MSLane* lane : myBidi) {
967 if (lane == end) {
968 return true;
969 }
970 }
971 auto it = std::lower_bound(myBidiExtendedSorted.begin(), myBidiExtendedSorted.end(), end);
972 if (it != myBidiExtendedSorted.end() && *it == end) {
973 if (overlap(other)) {
974 return true;
975 }
976 }
977 return false;
978}
979
980bool
981MSDriveWay::forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck) {
982 int i = 0;
983 for (const MSEdge* edge2 : other.myRoute) {
984 if (i == other.myCoreSize) {
985 return false;
986 }
987 i++;
988 if (edge2 == myForward.front()->getNextNormal() && !secondCheck) {
989 // foe should not pass from behind through our own forward section
990 return false;
991 }
992 if (forward.count(edge2->getBidiEdge()) != 0) {
993 return true;
994 }
995 }
996 return false;
997}
998
999void
1005 if (myCoreSize != (int)myRoute.size()) {
1006 od.writeAttr("core", myCoreSize);
1007 }
1008 od.openTag("forward");
1010 od.closeTag();
1011 if (!isSubDriveWay()) {
1012 od.openTag("bidi");
1014 if (myBidiExtended.size() > 0) {
1015 od.lf();
1016 od << " ";
1017 od.writeAttr("deadlockCheck", toString(myBidiExtended));
1018 }
1019 od.closeTag();
1020 od.openTag("flank");
1022 od.closeTag();
1023
1024 od.openTag("conflictLinks");
1025
1026 std::vector<std::string> signals;
1027 for (MSLink* link : myConflictLinks) {
1028 signals.push_back(getTLLinkID(link));
1029 }
1030 od.writeAttr("signals", joinToStringSorting(signals, " "));
1031 od.closeTag();
1032
1033 std::vector<std::string> foes;
1034 for (MSDriveWay* dw : myFoes) {
1035 foes.push_back(dw->myID);
1036 }
1037 if (foes.size() > 0) {
1038 od.openTag("foes");
1039 od.writeAttr("driveWays", joinToStringSorting(foes, " "));
1040 od.closeTag();
1041 }
1042 for (auto item : mySidings) {
1043 od.openTag("sidings");
1044 od.writeAttr("foe", item.first->getID());
1045 for (auto siding : item.second) {
1046 od.openTag("siding");
1047 od.writeAttr("start", myRoute[siding.start]->getID());
1048 od.writeAttr("end", myRoute[siding.end]->getID());
1049 od.writeAttr("length", siding.length);
1050 if (siding.intermediateEnds.size() > 0) {
1051 std::vector<std::string> endEdges;
1052 for (int i : siding.intermediateEnds) {
1053 endEdges.push_back(myRoute[i]->getID());
1054 }
1055 od.writeAttr("intermediateEnds", endEdges);
1056 }
1057 od.closeTag();
1058 }
1059 od.closeTag();
1060 }
1061 for (auto item : myDeadlocks) {
1062 od.openTag("deadlock");
1063 od.writeAttr("foes", joinNamedToStringSorting(item, " "));
1064 od.closeTag();
1065 }
1066 }
1067 od.closeTag(); // driveWay
1068
1069 for (const MSDriveWay* sub : mySubDriveWays) {
1070 sub->writeBlocks(od);
1071 }
1072#ifdef DRIVEWAY_SANITY_CHECK
1073 std::set<MSDriveWay*> uFoes(myFoes.begin(), myFoes.end());
1074 if (uFoes.size() != myFoes.size()) {
1075 WRITE_WARNINGF("Duplicate foes in driveway '%'", getID());
1076
1077 }
1078#endif
1079}
1080
1081
1082void
1084 od.openTag(isSubDriveWay() ? "subDriveWay" : "driveWay");
1086 for (const VehicleEvent& ve : myVehicleEvents) {
1087 od.openTag(ve.isEntry ? "entry" : "exit");
1088 od.writeAttr(SUMO_ATTR_ID, ve.id);
1089 od.writeAttr(SUMO_ATTR_TIME, time2string(ve.time));
1090 od.writeAttr("reason", Notifications.getString(ve.reason));
1091 od.closeTag(); // event
1092 }
1093 od.closeTag(); // driveWay
1094
1095 for (const MSDriveWay* sub : mySubDriveWays) {
1096 sub->writeBlockVehicles(od);
1097 }
1098}
1099
1100
1101void
1104 LaneVisitedMap& visited,
1105 std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) {
1106 double length = 0;
1107 bool seekForwardSignal = true;
1108 bool seekBidiSwitch = true;
1109 bool foundUnsafeSwitch = false;
1110 MSLane* toLane = origin ? origin->getViaLaneOrLane() : (*next)->getLanes()[0];
1111 const std::string warnID = origin ? "rail signal " + getClickableTLLinkID(origin) : "insertion lane '" + toLane->getID() + "'";
1112#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1113 if (gDebugFlag4) std::cout << "buildRoute origin=" << warnID << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1114 << " visited=" << formatVisitedMap(visited) << "\n";
1115#endif
1116 while (true) {
1118 // typical block length in germany on main lines is 3-5km on branch lines up to 7km
1119 // special branches that are used by one train exclusively could also be up to 20km in length
1120 // minimum block size in germany is 37.5m (LZB)
1121 // larger countries (USA, Russia) might see blocks beyond 20km)
1122 if (seekForwardSignal && myBlockLengthWarnings.count(myRoute.front()) == 0) {
1123 WRITE_WARNINGF("Block after % exceeds maximum length (stopped searching after edge '%' (length=%m).",
1124 warnID, toLane->getEdge().getID(), length);
1125 myBlockLengthWarnings.insert(myRoute.front());
1126 }
1127 myAbortedBuild = true;
1128 // length exceeded
1129#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1130 if (gDebugFlag4) {
1131 std::cout << " abort: length=" << length << "\n";
1132 }
1133#endif
1134 return;
1135 }
1136#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1137 if (gDebugFlag4) {
1138 std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1139 }
1140#endif
1141 const MSEdge* current = &toLane->getEdge();
1142 if (current->isNormal()) {
1143 myRoute.push_back(current);
1144 if (next != end) {
1145 next++;
1146 }
1147 }
1148 appendMapIndex(visited, toLane);
1149 length += toLane->getLength();
1150 MSLane* bidi = toLane->getBidiLane();
1151 if (seekForwardSignal) {
1152 if (!foundUnsafeSwitch) {
1153 myForward.push_back(toLane);
1154 if (toLane->isNormal()) {
1156 }
1157 if (myForward.size() == 1) {
1158 myLane = toLane;
1161 s->addDetector(this, myLane->getIndex());
1162 } else {
1163 toLane->addMoveReminder(this, false);
1164 }
1165 }
1166 }
1167 } else if (bidi == nullptr) {
1168 if (toLane->isInternal() && toLane->getIncomingLanes().front().viaLink->isTurnaround()) {
1169#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1170 if (gDebugFlag4) {
1171 std::cout << " continue bidiSearch beyond turnaround\n";
1172 }
1173#endif
1174 } else {
1175 seekBidiSwitch = false;
1176#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1177 if (gDebugFlag4) {
1178 std::cout << " noBidi, abort search for bidiSwitch\n";
1179 }
1180#endif
1181 }
1182 }
1183 if (bidi != nullptr) {
1184 if (!seekForwardSignal && !foundUnsafeSwitch && bidi->isNormal()) {
1185 // look for switch that could protect from oncoming vehicles
1186 for (const MSLink* const link : bidi->getLinkCont()) {
1187 if (link->getDirection() == LinkDirection::TURN) {
1188 continue;
1189 }
1190 if (!myBidi.empty() && link->getViaLaneOrLane() != myBidi.back()) {
1191 myCoreSize = (int)myRoute.size() - 1;
1192 MSLink* used = const_cast<MSLink*>(bidi->getLinkTo(myBidi.back()));
1193#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1194 if (gDebugFlag4) {
1195 std::cout << " found unsafe switch " << link->getDescription() << " (used=" << (used == nullptr ? "NULL" : used->getDescription()) << ")\n";
1196 }
1197#endif
1198 // trains along our route beyond this switch might create deadlock
1199 foundUnsafeSwitch = true;
1200 // the switch itself must still be guarded to ensure safety
1201 if (used != nullptr) {
1202 // possibly nullptr if there was an intermediate section of unidirectional edges
1203 flankSwitches.insert(used);
1204 }
1205 break;
1206 }
1207 }
1208 }
1209 if (foundUnsafeSwitch) {
1210 myBidiExtended.push_back(bidi);
1211 } else {
1212 myBidi.push_back(bidi);
1213 }
1214 }
1215 const std::vector<MSLink*>& links = toLane->getLinkCont();
1216 toLane = nullptr;
1217 for (const MSLink* const link : links) {
1218 if ((next != end && &link->getLane()->getEdge() == *next)) {
1219 toLane = link->getViaLaneOrLane();
1220 if (link->getTLLogic() != nullptr && link->getTLIndex() >= 0 && link->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
1221 if (link == origin) {
1222 if (seekForwardSignal) {
1223 WRITE_WARNINGF(TL("Found circular block after % (% edges, length %)"), warnID, toString(myRoute.size()), toString(length));
1224 }
1225 //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1226 myAbortedBuild = true;
1227#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1228 if (gDebugFlag4) {
1229 std::cout << " abort: found circle\n";
1230 }
1231#endif
1232 return;
1233 }
1234 seekForwardSignal = false;
1235 myFoundSignal = true;
1236 seekBidiSwitch = bidi != nullptr;
1237#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1238 if (gDebugFlag4) {
1239 std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1240 }
1241#endif
1242 }
1243 //if (links.size() > 1 && !foundUnsafeSwitch) {
1244 if (isSwitch(link)) {
1245 // switch on driveway
1246 //std::cout << "mySwitchDriveWays " << getID() << " link=" << link->getDescription() << "\n";
1247 mySwitchDriveWays[link].push_back(this);
1248 }
1249 if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1250 // reversal on driveway
1251 myReversalDriveWays[current].push_back(this);
1252 myReversals.push_back(current);
1253 }
1254 break;
1255 }
1256 }
1257 if (toLane == nullptr) {
1258 if (next != end) {
1259 // no connection found, jump to next route edge
1260 toLane = (*next)->getLanes()[0];
1261#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1262 if (gDebugFlag4) {
1263 std::cout << " abort: turn-around or jump\n";
1264 }
1265#endif
1266 myFoundJump = true;
1267 return;
1268 } else {
1269#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1270 if (gDebugFlag4) {
1271 std::cout << " abort: no next lane available\n";
1272 }
1273#endif
1274 myTerminateRoute = true;
1275 return;
1276 }
1277 }
1278 }
1279 myBidiEnded = !seekBidiSwitch;
1280#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1281 if (gDebugFlag4) {
1282 std::cout << " normalEnd myBidiEnded=" << myBidiEnded << "\n";
1283 }
1284#endif
1285}
1286
1287
1288bool
1290 for (const MSLink* other : link->getLaneBefore()->getNormalPredecessorLane()->getLinkCont()) {
1291 if (other->getLane() != link->getLane() && !other->isTurnaround()) {
1292 return true;
1293 }
1294 }
1295 for (auto ili : link->getLane()->getIncomingLanes()) {
1296 if (ili.viaLink != link && !ili.viaLink->isTurnaround()) {
1297 return true;
1298 }
1299 }
1300 const MSLane* bidi = link->getLane()->getBidiLane();
1301 if (bidi != nullptr) {
1302 for (const MSLink* other : bidi->getLinkCont()) {
1303 if (other->getLane() != link->getLaneBefore()->getNormalPredecessorLane()->getBidiLane() && !other->isTurnaround()) {
1304 return true;
1305 }
1306 }
1307 }
1308 return false;
1309}
1310
1311
1312void
1313MSDriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited,
1314 bool allFoes, bool movingBlock, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1315#ifdef DEBUG_CHECK_FLANKS
1316 if (gDebugFlag4) {
1317 std::cout << " checkFlanks lanes=" << toString(lanes) << " allFoes=" << allFoes << "\n";
1318 }
1319#endif
1320 const MSLink* reverseOriginLink = originLink != nullptr && originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1321 ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1322 : nullptr;
1323 //std::cout << " originLink=" << originLink->getDescription() << "\n";
1324 if (reverseOriginLink != nullptr) {
1325 reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1326 //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1327 }
1328 for (int i = 0; i < (int)lanes.size(); i++) {
1329 const MSLane* lane = lanes[i];
1330 const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1331 const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1332 if (lane->isInternal()) {
1333 continue;
1334 }
1335 for (auto ili : lane->getIncomingLanes()) {
1336 if (ili.viaLink == originLink
1337 || ili.viaLink == reverseOriginLink
1338 || ili.viaLink->getDirection() == LinkDirection::TURN
1339 || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND
1340 || (originLink == nullptr && i == 0 && movingBlock)) {
1341 continue;
1342 }
1343 if (ili.lane != prev && ili.lane != next) {
1344#ifdef DEBUG_CHECK_FLANKS
1345 if (gDebugFlag4) {
1346 std::cout << " add flankSwitch junction=" << ili.viaLink->getJunction()->getID() << " index=" << ili.viaLink->getIndex() << " iLane=" << ili.lane->getID() << " prev=" << Named::getIDSecure(prev) << " targetLane=" << lane->getID() << " next=" << Named::getIDSecure(next) << "\n";
1347 }
1348#endif
1349 flankSwitches.insert(ili.viaLink);
1350 } else if (allFoes) {
1351 // link is part of the driveway, find foes that cross the driveway without entering
1352 checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1353 }
1354 }
1355 }
1356}
1357
1358
1359void
1360MSDriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1361#ifdef DEBUG_CHECK_FLANKS
1362 if (gDebugFlag4) {
1363 std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1364 }
1365#endif
1366 const MSJunction* junction = dwLink->getJunction();
1367 if (junction == nullptr) {
1368 return; // unregulated junction;
1369 }
1370 const MSJunctionLogic* logic = junction->getLogic();
1371 if (logic == nullptr) {
1372 return; // unregulated junction;
1373 }
1374 for (const MSEdge* in : junction->getIncoming()) {
1375 if (in->isInternal()) {
1376 continue;
1377 }
1378 for (MSLane* inLane : in->getLanes()) {
1379 const MSLane* inBidi = inLane->getBidiLane();
1380 if (isRailwayOrShared(inLane->getPermissions()) && visited.count(inLane) == 0 && (inBidi == nullptr || visited.count(inBidi) == 0)) {
1381 for (MSLink* link : inLane->getLinkCont()) {
1382 if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1383 && visited.count(link->getLane()) == 0) {
1384#ifdef DEBUG_CHECK_FLANKS
1385 if (gDebugFlag4) {
1386 std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1387 }
1388#endif
1389 if (link->getViaLane() == nullptr) {
1390 flankSwitches.insert(link);
1391 } else {
1392 flankSwitches.insert(link->getViaLane()->getLinkCont().front());
1393 }
1394 }
1395 }
1396 }
1397 }
1398 }
1399}
1400
1401void
1402MSDriveWay::findFlankProtection(MSLink* link, MSLink* origLink, const std::vector<const MSLane*>& flank) {
1403#ifdef DEBUG_CHECK_FLANKS
1404 if (gDebugFlag4) {
1405 std::cout << " findFlankProtection link=" << link->getDescription() << " origLink=" << origLink->getDescription() << "\n";
1406 }
1407#endif
1408 if (link->getCorrespondingEntryLink()->getTLLogic() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1409 MSLink* entry = const_cast<MSLink*>(link->getCorrespondingEntryLink());
1410 // guarded by signal
1411#ifdef DEBUG_CHECK_FLANKS
1412 if (gDebugFlag4) {
1413 std::cout << " flank guarded by " << entry->getTLLogic()->getID() << "\n";
1414 }
1415#endif
1416 // @note, technically it's enough to collect links from foe driveways
1417 // but this also adds "unused" conflict links which may aid comprehension
1418 myConflictLinks.push_back(entry);
1419 addFoes(entry);
1420 } else {
1421 const MSLane* lane = link->getLaneBefore();
1422 std::vector<MSLink*> predLinks;
1423 for (auto ili : lane->getIncomingLanes()) {
1424 if (!ili.viaLink->isTurnaround()) {
1425 predLinks.push_back(ili.viaLink);
1426 }
1427 }
1428 if (predLinks.size() > 1) {
1429 // this is a switch
1430#ifdef DEBUG_ADD_FOES
1431 if (gDebugFlag4) {
1432 std::cout << " predecessors of " << link->getDescription() << " isSwitch\n";
1433 }
1434#endif
1435 addSwitchFoes(link);
1436 for (MSLink* pred : predLinks) {
1437 addSwitchFoes(pred);
1438 }
1439 } else if (predLinks.size() == 1) {
1440 if (isSwitch(link)) {
1441 addSwitchFoes(link);
1442 } else {
1443 // continue upstream via single predecessor
1444 findFlankProtection(predLinks.front(), origLink, flank);
1445 }
1446 }
1447 // check for insertions
1448 if (myDepartureDriveways.count(&lane->getEdge()) != 0) {
1449 for (MSDriveWay* foe : myDepartureDriveways[&lane->getEdge()]) {
1450 if (flankConflict(*foe) || crossingConflict(*foe)) {
1451#ifdef DEBUG_ADD_FOES
1452 if (gDebugFlag4) {
1453 std::cout << " foe " << foe->getID() << " departs on flank=" << lane->getID() << "\n";
1454 }
1455#endif
1456 myFoes.push_back(foe);
1457 } else {
1458#ifdef DEBUG_ADD_FOES
1459 if (gDebugFlag4) {
1460 std::cout << " cand foe " << foe->getID() << " departs on flank=" << lane->getID() << " rejected\n";
1461 }
1462#endif
1463 }
1464 }
1465 }
1466 }
1467}
1468
1469
1470void
1472 auto it = mySwitchDriveWays.find(link);
1473 if (it != mySwitchDriveWays.end()) {
1474#ifdef DEBUG_ADD_FOES
1475 if (gDebugFlag4) {
1476 std::cout << " driveway " << myID << " addSwitchFoes for link " << link->getDescription() << "\n";
1477 }
1478#endif
1479 for (MSDriveWay* foe : it->second) {
1480 if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1481#ifdef DEBUG_ADD_FOES
1482 if (gDebugFlag4) std::cout << " foe=" << foe->myID
1483 << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this)
1484 << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1485#endif
1486 myFoes.push_back(foe);
1487 } else {
1488#ifdef DEBUG_ADD_FOES
1489 if (gDebugFlag4) {
1490 std::cout << " cand=" << foe->myID << "\n";
1491 }
1492#endif
1493 }
1494 }
1495 }
1496}
1497
1498
1500MSDriveWay::buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end) {
1501 // collect lanes and links that are relevant for setting this signal for the current driveWay
1502 // For each driveway we collect
1503 // - conflictLanes (signal must be red if any conflict lane is occupied)
1504 // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
1505 // - that cannot break in time (arrivalSpeedBraking > 0)
1506 // - approached by a vehicle with higher switching priority (see #3941)
1507 // These objects are construct in steps:
1508 //
1509 // forwardBlock
1510 // - search forward recursive from outgoing lane until controlled railSignal link found
1511 // -> add all found lanes to conflictLanes
1512 //
1513 // bidiBlock (if any forwardBlock edge has bidi edge)
1514 // - search bidi backward recursive until first switch
1515 // - from switch search backward recursive all other incoming until controlled rail signal link
1516 // -> add final links to conflictLinks
1517 //
1518 // flanks
1519 // - search backward recursive from flanking switches
1520 // until controlled railSignal link or protecting switch is found
1521 // -> add all found lanes to conflictLanes
1522 // -> add final links to conflictLinks
1523 MSDriveWay* dw = new MSDriveWay(link, id);
1524 LaneVisitedMap visited;
1525 std::vector<const MSLane*> before;
1526 MSLane* fromBidi = nullptr;
1527 if (link != nullptr) {
1528 appendMapIndex(visited, link->getLaneBefore());
1529 fromBidi = link->getLaneBefore()->getBidiLane();
1530 }
1531 std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitches; // list of switches that threaten the driveway and for which protection must be found
1532
1533 if (fromBidi != nullptr) {
1534 before.push_back(fromBidi);
1535 }
1536#ifdef DEBUG_BUILD_DRIVEWAY
1538#endif
1539 dw->buildRoute(link, first, end, visited, flankSwitches);
1540 dw->myBidiExtendedSorted.assign(dw->myBidiExtended.begin(), dw->myBidiExtended.end());
1541 std::sort(dw->myBidiExtendedSorted.begin(), dw->myBidiExtendedSorted.end());
1542 dw->myCoreSize = (int)dw->myRoute.size();
1543
1544 MSRailSignal* rs = link ? const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(link->getTLLogic())) : nullptr;
1545 const bool movingBlock = (rs && rs->isMovingBlock()) || (!rs &&
1546 (OptionsCont::getOptions().getBool("railsignal-moving-block")
1547 || MSRailSignalControl::isMovingBlock((*first)->getPermissions())));
1548
1549 dw->checkFlanks(link, dw->myForward, visited, true, movingBlock, flankSwitches);
1550 dw->checkFlanks(link, dw->myBidi, visited, false, movingBlock, flankSwitches);
1551 dw->checkFlanks(link, before, visited, true, movingBlock, flankSwitches);
1552 for (MSLink* fsLink : flankSwitches) {
1553#ifdef DEBUG_ADD_FOES
1554 if (DEBUG_COND_DW(dw)) {
1555 std::cout << " fsLink=" << fsLink->getDescription() << "\n";
1556 }
1557#endif
1558 dw->findFlankProtection(fsLink, fsLink, dw->myFlank);
1559 }
1560 std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitchesBidiExtended;
1561 dw->checkFlanks(link, dw->myBidiExtended, visited, false, movingBlock, flankSwitchesBidiExtended);
1562 for (MSLink* const flink : flankSwitchesBidiExtended) {
1563#ifdef DEBUG_ADD_FOES
1564 if (DEBUG_COND_DW(dw)) {
1565 std::cout << " fsLinkExtended=" << flink->getDescription() << "\n";
1566 }
1567#endif
1568 dw->findFlankProtection(flink, flink, dw->myBidiExtended);
1569 }
1570#ifdef DEBUG_BUILD_DRIVEWAY
1571 if (DEBUG_COND_DW(dw)) {
1572 std::cout << SIMTIME << " buildDriveWay " << dw->myID << " link=" << (link == nullptr ? "NULL" : link->getDescription())
1573 << "\n route=" << toString(dw->myRoute)
1574 << "\n forward=" << toString(dw->myForward)
1575 << "\n bidi=" << toString(dw->myBidi)
1576 << "\n bidiEx=" << toString(dw->myBidiExtended)
1577 << "\n flank=" << toString(dw->myFlank)
1578 << "\n flankSwitch=" << MSRailSignal::describeLinks(std::vector<MSLink*>(flankSwitches.begin(), flankSwitches.end()))
1579 << "\n coreSize=" << dw->myCoreSize
1580 << "\n";
1581 }
1582#endif
1583 if (!rs || !rs->isMovingBlock()) {
1584 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myForward.begin(), dw->myForward.end());
1585 }
1586 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myBidi.begin(), dw->myBidi.end());
1587 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myFlank.begin(), dw->myFlank.end());
1588 dw->addBidiFoes(rs, false);
1589 dw->addBidiFoes(rs, true);
1590 if (!movingBlock) {
1591 // add driveways that start on the same signal / lane
1592 dw->addParallelFoes(link, *first);
1593 }
1594 // add driveways that reverse along this driveways route
1595 dw->addReversalFoes(movingBlock);
1596 // make foes unique and symmetrical
1597 std::set<MSDriveWay*, ComparatorNumericalIdLess> uniqueFoes(dw->myFoes.begin(), dw->myFoes.end());
1598 dw->myFoes.clear();
1599 // check for self-intersecting forward-section in movingBlock mode
1600 if (movingBlock && uniqueFoes.count(dw) == 0) {
1601 std::map<const MSJunction*, std::vector<const MSLink*> > forwardJunctions;
1602 int iLast = (int)dw->myForward.size() - 1;
1603 bool selfIntersect = false;
1604 for (int i = 0; i < iLast && !selfIntersect; i++) {
1605 const MSLane* fw = dw->myForward[i];
1606 if (fw->isNormal()) {
1607 const MSJunction* fwTo = fw->getEdge().getToJunction();
1608 const MSLink* fwLink = fw->getLinkTo(dw->myForward[i + 1]);
1609 if (fwLink != nullptr) {
1610 for (const MSLink* link2 : forwardJunctions[fwTo]) {
1611 const std::vector<MSLink*>& foeLinks = fwLink->getFoeLinks();
1612 const std::vector<MSLink*>& foeLinks2 = link2->getFoeLinks();
1613 if (std::find(foeLinks.begin(), foeLinks.end(), link2) != foeLinks.end()
1614 || std::find(foeLinks2.begin(), foeLinks2.end(), fwLink) != foeLinks2.end()
1615 || fwLink->getLane()->getBidiLane() == link2->getLaneBefore()
1616 || link2->getLane()->getBidiLane() == fwLink->getLaneBefore()) {
1617 dw->myFoes.push_back(dw);
1618 selfIntersect = true;
1619#ifdef DEBUG_ADD_FOES
1620 if (DEBUG_COND_DW(dw)) {
1621 std::cout << " self-intersecting movingBlock for dw=" << dw->getID() << " at junction " << fwTo->getID() << " fwLink=" << fwLink->getDescription() << " link2=" << link2->getDescription() << "\n";
1622 }
1623#endif
1624 break;
1625 }
1626 }
1627 forwardJunctions[fwTo].push_back(fwLink);
1628 }
1629 }
1630 }
1631 }
1632 std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> uniqueCLink(dw->myConflictLinks.begin(), dw->myConflictLinks.end());
1633 const MSEdge* lastEdge = &dw->myForward.back()->getEdge();
1634 for (MSDriveWay* foe : uniqueFoes) {
1635 const MSEdge* foeLastEdge = &foe->myForward.back()->getEdge();
1636 const bool sameLast = foeLastEdge == lastEdge;
1637 if (sameLast && !movingBlock) {
1638 dw->myFoes.push_back(foe);
1639 if (foe != dw) {
1640 foe->myFoes.push_back(dw);
1641 }
1642 } else {
1643 if (foe->bidiBlockedByEnd(*dw)) {
1644#ifdef DEBUG_ADD_FOES
1645 if (DEBUG_COND_DW(dw)) {
1646 std::cout << " setting " << dw->getID() << " as foe of " << foe->getID() << "\n";
1647 }
1648#endif
1649 foe->myFoes.push_back(dw);
1650 foe->addSidings(dw);
1651 } else {
1652 dw->buildSubFoe(foe, movingBlock);
1653 }
1654 if (foe != dw) { // check for movingBlock
1655 if (dw->bidiBlockedByEnd(*foe)) {
1656#ifdef DEBUG_ADD_FOES
1657 if (DEBUG_COND_DW(dw)) {
1658 std::cout << " addFoeCheckSiding " << foe->getID() << "\n";
1659 }
1660#endif
1661 dw->myFoes.push_back(foe);
1662 dw->addSidings(foe);
1663 } else {
1664 foe->buildSubFoe(dw, movingBlock);
1665 }
1666 }
1667 }
1668 if (link) {
1669 foe->addConflictLink(link);
1670 }
1671 // ignore links that have the same start junction
1672 if (foe->myRoute.front()->getFromJunction() != dw->myRoute.front()->getFromJunction()) {
1673 for (auto ili : foe->myForward.front()->getIncomingLanes()) {
1674 if (ili.viaLink->getTLLogic() != nullptr) {
1675 // ignore links that originate on myBidi
1676 const MSLane* origin = ili.viaLink->getLaneBefore();
1677 if (std::find(dw->myBidi.begin(), dw->myBidi.end(), origin) == dw->myBidi.end()) {
1678 uniqueCLink.insert(ili.viaLink);
1679 }
1680 }
1681 }
1682 }
1683 }
1684 dw->myConflictLinks.clear();
1685 dw->myConflictLinks.insert(dw->myConflictLinks.begin(), uniqueCLink.begin(), uniqueCLink.end());
1686 myEndingDriveways[lastEdge].push_back(dw);
1687 if (!movingBlock) {
1688 // every driveway is it's own foe (also all driveways that depart in the same block)
1689 for (MSDriveWay* sameEnd : myEndingDriveways[lastEdge]) {
1690 if (uniqueFoes.count(sameEnd) == 0) {
1691 dw->myFoes.push_back(sameEnd);
1692 if (sameEnd != dw) {
1693 sameEnd->myFoes.push_back(dw);
1694 }
1695 }
1696 }
1697 }
1698#ifdef DEBUG_BUILD_DRIVEWAY
1699 if (DEBUG_COND_DW(dw)) {
1700 std::cout << dw->myID << " mb=" << movingBlock << " finalFoes " << toString(dw->myFoes) << "\n";
1701 }
1702 gDebugFlag4 = false;
1703#endif
1704 return dw;
1705}
1706
1707std::string
1709 return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
1710}
1711
1712std::string
1714 return link->getJunction()->getID() + "_" + toString(link->getIndex());
1715}
1716
1717std::string
1719 return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
1720}
1721
1722std::string
1724 UNUSED_PARAMETER(visited);
1725 /*
1726 std::vector<const MSLane*> lanes(visited.size(), nullptr);
1727 for (auto item : visited) {
1728 lanes[item.second] = item.first;
1729 }
1730 for (auto it = lanes.begin(); it != lanes.end();) {
1731 if (*it == nullptr) {
1732 it = lanes.erase(it);
1733 } else {
1734 it++;
1735 }
1736 }
1737 return toString(lanes);
1738 */
1739 return "dummy";
1740}
1741
1742
1743void
1745 // avoid undefined behavior from evaluation order
1746 const int tmp = (int)map.size();
1747 map[lane] = tmp;
1748}
1749
1750bool
1752 // @todo optimize: it is sufficient to check for specific edges (after each switch)
1753 auto itRoute = firstIt;
1754 auto itDwRoute = myRoute.begin();
1755 bool match = true;
1756 while (itRoute != endIt && itDwRoute != myRoute.end()) {
1757 if (*itRoute != *itDwRoute) {
1758 match = false;
1759#ifdef DEBUG_MATCH
1760 std::cout << " check dw=" << getID() << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
1761#endif
1762 break;
1763 }
1764 itRoute++;
1765 itDwRoute++;
1766 }
1767 // if the vehicle arrives before the end of this driveway,
1768 // we'd rather build a new driveway to avoid superfluous restrictions
1769 if (match && itDwRoute == myRoute.end()
1770 && (itRoute == endIt || myAbortedBuild || myBidiEnded || myFoundJump || isSubDriveWay())) {
1771 //std::cout << " using dw=" << "\n";
1772 if (itRoute != endIt) {
1773 // check whether the current route requires an extended driveway
1774 const MSEdge* next = *itRoute;
1775 const MSEdge* prev = myRoute.back();
1776 if (myFoundJump && prev->getBidiEdge() != next && prev->getBidiEdge() != nullptr
1777 && prev->isConnectedTo(*next, (SUMOVehicleClass)(SVC_RAIL_CLASSES & prev->getPermissions()))) {
1778#ifdef DEBUG_MATCH
1779 std::cout << " check dw=" << getID() << " prev=" << prev->getID() << " next=" << next->getID() << "\n";
1780#endif
1781 return false;
1782 }
1783 if (!myFoundJump && prev->getBidiEdge() == next && prev == &myForward.back()->getEdge()) {
1784 assert(isSubDriveWay() || myBidiEnded);
1785 // must not leave driveway via reversal
1786#ifdef DEBUG_MATCH
1787 std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, endIt)) << "\n";
1788#endif
1789 return false;
1790 }
1791 if (myForward.back()->isInternal() && myForward.back()->getNextNormal() != (*itRoute)) {
1792 // driveway is part of a direct-control conflict and continues elsewhere
1793#ifdef DEBUG_MATCH
1794 std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, itRoute)) << " (direct control)\n";
1795#endif
1796 return false;
1797 }
1798 }
1799 return !isSubDriveWay() || myParent->match(firstIt, endIt);
1800 }
1801 return false;
1802}
1803
1804void
1806#ifdef DEBUG_ADD_FOES
1807 if (gDebugFlag4) {
1808 std::cout << "driveway " << myID << " addFoes for link " << link->getDescription() << "\n";
1809 }
1810#endif
1811 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
1812 if (rs != nullptr) {
1813 for (MSDriveWay* foe : rs->retrieveDriveWays(link->getTLIndex())) {
1814#ifdef DEBUG_ADD_FOES
1815 if (gDebugFlag4) {
1816 std::cout << " cand foe=" << foe->myID << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this) << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1817 }
1818#endif
1819 if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1820#ifdef DEBUG_ADD_FOES
1821 if (gDebugFlag4) {
1822 std::cout << " foe=" << foe->myID << "\n";
1823 }
1824#endif
1825 myFoes.push_back(foe);
1826 }
1827 }
1828 }
1829}
1830
1831
1832void
1833MSDriveWay::addBidiFoes(const MSRailSignal* ownSignal, bool extended) {
1834#ifdef DEBUG_ADD_FOES
1835 if (gDebugFlag4) {
1836 std::cout << "driveway " << myID << " addBidiFoes extended=" << extended << "\n";
1837 }
1838#endif
1839 const std::vector<const MSLane*>& bidiLanes = extended ? myBidiExtended : myBidi;
1840 for (const MSLane* bidi : bidiLanes) {
1841 for (auto ili : bidi->getIncomingLanes()) {
1842 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(ili.viaLink->getTLLogic());
1843 if (rs != nullptr && rs != ownSignal &&
1844 std::find(bidiLanes.begin(), bidiLanes.end(), ili.lane) != bidiLanes.end()) {
1845 addFoes(ili.viaLink);
1846 }
1847 }
1848 const MSEdge* bidiEdge = &bidi->getEdge();
1849 if (myDepartureDriveways.count(bidiEdge) != 0) {
1850 for (MSDriveWay* foe : myDepartureDriveways[bidiEdge]) {
1851 if (flankConflict(*foe)) {
1852#ifdef DEBUG_ADD_FOES
1853 if (gDebugFlag4) {
1854 std::cout << " foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << "\n";
1855 }
1856#endif
1857 myFoes.push_back(foe);
1858 } else {
1859#ifdef DEBUG_ADD_FOES
1860 if (gDebugFlag4) {
1861 std::cout << " cand foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << " rejected\n";
1862 }
1863#endif
1864 }
1865 }
1866 }
1867 if (myDepartureDrivewaysEnds.count(bidiEdge) != 0) {
1868 for (MSDriveWay* foe : myDepartureDrivewaysEnds[bidiEdge]) {
1869 if (flankConflict(*foe)) {
1870#ifdef DEBUG_ADD_FOES
1871 if (gDebugFlag4) {
1872 std::cout << " foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << "\n";
1873 }
1874#endif
1875 myFoes.push_back(foe);
1876 } else {
1877#ifdef DEBUG_ADD_FOES
1878 if (gDebugFlag4) {
1879 std::cout << " cand foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << " rejected\n";
1880 }
1881#endif
1882 }
1883 }
1884 }
1885 }
1886}
1887
1888
1889void
1890MSDriveWay::addParallelFoes(const MSLink* link, const MSEdge* first) {
1891#ifdef DEBUG_ADD_FOES
1892 if (gDebugFlag4) {
1893 std::cout << "driveway " << myID << " addParallelFoes\n";
1894 }
1895#endif
1896 if (link) {
1897 addFoes(link);
1898 } else {
1899 auto it = myDepartureDriveways.find(first);
1900 if (it != myDepartureDriveways.end()) {
1901 for (MSDriveWay* foe : it->second) {
1902#ifdef DEBUG_ADD_FOES
1903 if (gDebugFlag4) {
1904 std::cout << " foe " << foe->getID() << " departs on first=" << first->getID() << "\n";
1905 }
1906#endif
1907 myFoes.push_back(foe);
1908 }
1909 }
1910 }
1911}
1912
1913
1914void
1916#ifdef DEBUG_ADD_FOES
1917 if (gDebugFlag4) {
1918 std::cout << "driveway " << myID << " addReversalFoes\n";
1919 }
1920#endif
1921 std::set<const MSEdge*> forward;
1922 for (const MSLane* lane : myForward) {
1923 if (lane->isNormal()) {
1924 forward.insert(&lane->getEdge());
1925 }
1926 }
1927 int i = 0;
1928 for (const MSEdge* e : myRoute) {
1929 if (forward.count(e) != 0 && !movingBlock) {
1930 // reversals in our own forward can be ignored because each driveway
1931 // is automatically a foe of itself by default
1932 continue;
1933 }
1934 if (i == myCoreSize) {
1935 break;
1936 }
1937 i++;
1938 auto it = myReversalDriveWays.find(e);
1939 if (it != myReversalDriveWays.end()) {
1940 for (MSDriveWay* foe : it->second) {
1941 // check whether the foe reverses into our own forward section
1942 // (it might reverse again or disappear via arrival)
1943#ifdef DEBUG_ADD_FOES
1944 //std::cout << " candidate foe " << foe->getID() << " reverses on edge=" << e->getID() << " forward=" << joinNamedToString(forward, " ") << " foeRoute=" << toString(foe->myRoute) << "\n";
1945#endif
1946 if (forwardRouteConflict(forward, *foe)) {
1947 std::set<const MSEdge*> foeForward;
1948 for (const MSLane* lane : foe->myForward) {
1949 if (lane->isNormal()) {
1950 foeForward.insert(&lane->getEdge());
1951 if (lane->getBidiLane() != nullptr) {
1952 foeForward.insert(lane->getEdge().getBidiEdge());
1953 }
1954 }
1955 }
1956#ifdef DEBUG_ADD_FOES
1957 if (gDebugFlag4) {
1958 std::cout << " reversal cand=" << foe->getID() << " foeForward " << toString(foeForward) << "\n";
1959 }
1960#endif
1961 if (foe->forwardRouteConflict(foeForward, *this, true)) {
1962#ifdef DEBUG_ADD_FOES
1963 if (gDebugFlag4) {
1964 std::cout << " foe " << foe->getID() << " reverses on edge=" << e->getID() << "\n";
1965 }
1966#endif
1967 myFoes.push_back(foe);
1968 }
1969 } else if (movingBlock && foe == this) {
1970#ifdef DEBUG_ADD_FOES
1971 if (gDebugFlag4) {
1972 std::cout << " dw " << getID() << " reverses on forward edge=" << e->getID() << " (movingBlock)\n";
1973 }
1974#endif
1975 myFoes.push_back(foe);
1976 }
1977 }
1978 }
1979 }
1980}
1981
1982
1983bool
1984MSDriveWay::buildSubFoe(MSDriveWay* foe, bool movingBlock) {
1985 // Subdriveways (Teilfahrstraße) model the resolution of a driving conflict
1986 // before a vehicle has left the driveway. This is possible when the driveway diverges from the foe
1987 // driveway at an earlier point (switch or crossing).
1988 //
1989 // We already know that the last edge of this driveway doesn't impact the foe (unless the driveway ends within the block).
1990 // Remove further edges from the end of the driveway (myForward) until the point of conflict is found.
1991 //
1992 // For movingBlock the logic is changed:
1993 // We remove the conflict-free part as before but then keep removing the conflict part until another non-conconflit part is found
1994 if (myForward.size() < foe->myForward.size() &&
1995 myForward == std::vector<const MSLane*>(foe->myForward.begin(), foe->myForward.begin() + myForward.size())) {
1996#ifdef DEBUG_BUILD_SUBDRIVEWAY
1997 if (gDebugFlag4) {
1998 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " is subpart of foe=" << foe->getID() << "\n";
1999 }
2000#endif
2001 foe->myFoes.push_back(this);
2002 return true;
2003 }
2004 int subLast = (int)myForward.size() - 2;
2005 if (movingBlock && myForward.back() == foe->myForward.back()) {
2006 subLast++;
2007 }
2008#ifdef DEBUG_BUILD_SUBDRIVEWAY
2009 if (subLast < 0) {
2010 if (gDebugFlag4) {
2011 std::cout << " " << getID() << " cannot build subDriveWay for foe " << foe->getID() << " because myForward has only a single lane\n";
2012 }
2013 }
2014#endif
2015 bool foundConflict = false;
2016 bool flankC = false;
2017 bool zipperC = false;
2018 bool crossC = false;
2019 while (subLast >= 0) {
2020 const MSLane* lane = myForward[subLast];
2021 const MSLink* tmpOrigin = subLast > 0 ? myForward[subLast - 1]->getLinkTo(lane) : myOrigin;
2022 MSDriveWay tmp(tmpOrigin, "tmp", true);
2023 tmp.myForward.push_back(lane);
2024 tmp.myBidi = myBidi;
2027 tmp.myRoute.push_back(lane->getNextNormal());
2028 tmp.myCoreSize = 1;
2029 flankC = tmp.flankConflict(*foe);
2030 const bool bidiConflict = std::find(foe->myBidi.begin(), foe->myBidi.end(), lane) != foe->myBidi.end();
2031 crossC = tmp.crossingConflict(*foe);
2032#ifdef DEBUG_BUILD_SUBDRIVEWAY
2033 if (gDebugFlag4) {
2034 std::cout << " subLast=" << subLast << " lane=" << lane->getID() << " fc=" << flankC << " cc=" << crossC << " bc=" << bidiConflict << "\n";
2035 }
2036#endif
2037 if (flankC || crossC || bidiConflict) {
2038 foundConflict = true;
2039 if (!movingBlock || bidiConflict) {
2040 break;
2041 }
2042 if (((flankC && lane->getFromJunction()->getType() == SumoXMLNodeType::ZIPPER)
2043 || (!flankC && lane->getToJunction()->getType() == SumoXMLNodeType::ZIPPER))
2044 && (isDepartDriveway()
2045 || getForwardDistance(flankC ? subLast - 1 : subLast) > myMovingBlockMaxDist)) {
2046 zipperC = true;
2047 foundConflict = false;
2048#ifdef DEBUG_BUILD_SUBDRIVEWAY
2049 if (gDebugFlag4) {
2050 std::cout << " ignored movingBlock zipperConflict\n";
2051 }
2052#endif
2053 if (!flankC && crossC) {
2054#ifdef DEBUG_BUILD_SUBDRIVEWAY
2055 if (gDebugFlag4) {
2056 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
2057 }
2058#endif
2059 return false;
2060 }
2061 }
2062 if (!flankC && crossC) {
2063 break;
2064 }
2065 } else if (foundConflict) {
2066 break;
2067 }
2068 subLast--;
2069 }
2070#ifdef DEBUG_BUILD_SUBDRIVEWAY
2071 if (gDebugFlag4) {
2072 std::cout << " subLastFinal=" << subLast << " movingBlock=" << movingBlock << " zipperC=" << zipperC << "\n";
2073 }
2074#endif
2075 if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
2076 //std::set<const MSEdge*> firstEdge;
2077 //firstEdge.insert(foe->myRoute.front());
2078
2080 ConstMSEdgeVector foeAfterForward(foe->myRoute.begin() + foe->myForwardEdgeCount,
2081 foe->myRoute.begin() + MIN2(foe->myRoute.size(), foe->myForwardEdgeCount + forward.size()));
2082 // @todo the check for forwardRouteConflict correctly reduces waiting in
2083 // test rail/reversal/consecutive_before_reversal but creates deadlock in
2084 // test rail/reversal/reversal_onRoute_beyond_core3b
2085 if (forward == foeAfterForward /*&& forwardRouteConflict(firstEdge, *this, true)*/) {
2086 foe->myFoes.push_back(this);
2087 // foe will get the sidings
2088 addSidings(foe, true);
2089#ifdef DEBUG_BUILD_SUBDRIVEWAY
2090 if (gDebugFlag4) {
2091 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " special case 1\n";
2092 }
2093#endif
2094 return true;
2095 }
2096 }
2097 if (subLast < 0) {
2098 if (movingBlock && zipperC) {
2099#ifdef DEBUG_BUILD_SUBDRIVEWAY
2100 if (gDebugFlag4) {
2101 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
2102 }
2103#endif
2104 return false;
2105 } else if (&myForward.back()->getEdge() == myRoute.back() && foe->forwardEndOnRoute(this)) {
2106 // driveway ends in the middle of the block and only the final edge overlaps with the foe driveWay
2107 foe->myFoes.push_back(this);
2108#ifdef DEBUG_BUILD_SUBDRIVEWAY
2109 if (gDebugFlag4) {
2110 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " foe endsOnForward\n";
2111 }
2112#endif
2113 } else if (foe->myTerminateRoute) {
2114 if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
2115 foe->myFoes.push_back(this);
2116 // foe will get the sidings
2117 addSidings(foe, true);
2118 }
2119#ifdef DEBUG_BUILD_SUBDRIVEWAY
2120 if (gDebugFlag4) {
2121 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " terminates\n";
2122 }
2123#endif
2124 } else if (myTerminateRoute && myBidi.size() <= myForward.size()) {
2125 foe->myFoes.push_back(this);
2126#ifdef DEBUG_BUILD_SUBDRIVEWAY
2127 if (gDebugFlag4) {
2128 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " terminates, foe=" << foe->getID() << "\n";
2129 }
2130#endif
2131 return true;
2132 } else if (foe->myReversals.size() % 2 == 1) {
2133#ifdef DEBUG_BUILD_SUBDRIVEWAY
2134 if (gDebugFlag4) {
2135 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " has " << foe->myReversals.size() << " reversals\n";
2136 }
2137#endif
2138 } else {
2139#ifdef DEBUG_BUILD_SUBDRIVEWAY
2140 if (gDebugFlag4) {
2141 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " failed\n";
2142 }
2143#endif
2144#ifdef SUBDRIVEWAY_WARN_NOCONFLICT
2145 WRITE_WARNINGF("No point of conflict found between driveway '%' and driveway '%' when creating sub-driveway", getID(), foe->getID());
2146#endif
2147 }
2148 return false;
2149 }
2150 int subSize = subLast + 1;
2151 for (MSDriveWay* cand : mySubDriveWays) {
2152 if ((int)cand->myForward.size() == subSize) {
2153 // can re-use existing sub-driveway
2154 foe->myFoes.push_back(cand);
2155 if (foe->bidiBlockedByEnd(*cand)) {
2156 foe->addSidings(cand);
2157 }
2158 cand->myFoes.push_back(foe);
2159#ifdef DEBUG_BUILD_SUBDRIVEWAY
2160 if (gDebugFlag4) {
2161 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " useExisting=" << cand->getID() << "\n";
2162 }
2163#endif
2164 return true;
2165 }
2166 }
2167 std::vector<const MSLane*> forward(myForward.begin(), myForward.begin() + subSize);
2168 std::vector<const MSEdge*> route;
2169 for (const MSLane* lane : forward) {
2170 if (lane->isNormal()) {
2171 route.push_back(&lane->getEdge());
2172 }
2173 }
2174 if (route.empty()) {
2175 if (subSize == 1 && crossC
2176 && forward.front()->getFromJunction() == foe->myForward.front()->getFromJunction()
2177 && forward.front()->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2178 assert(myForward.front()->isInternal());
2179 // sub-driveway ends after a single internal lane but since the route cannot be empty we add the next edge
2180 route.push_back(foe->myForward.front()->getEdge().getNormalSuccessor());
2181 } else {
2182#ifdef DEBUG_BUILD_SUBDRIVEWAY
2183 if (gDebugFlag4) {
2184 std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID() << " empty subRoute\n";
2185 }
2186#endif
2187 return false;
2188 }
2189 }
2190 if (myRoute.size() > route.size()) {
2191 // route continues. make sure the subDriveway does not end with a reversal
2192 const MSEdge* lastNormal = route.back();
2193 const MSEdge* nextNormal = myRoute[route.size()];
2194 if (lastNormal->getBidiEdge() == nextNormal) {
2195#ifdef DEBUG_BUILD_SUBDRIVEWAY
2196 if (gDebugFlag4) std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID()
2197 << " lastNormal=" << lastNormal->getID() << " nextNormal=" << nextNormal->getID() << " endWithReversal\n";
2198#endif
2199 return false;
2200 }
2201 }
2202 MSDriveWay* sub = new MSDriveWay(myOrigin, getID() + "." + toString(mySubDriveWays.size()));
2203 sub->myLane = myLane;
2204 sub->myParent = this;
2205 sub->myForward = forward;
2206 sub->myRoute = route;
2207 sub->myCoreSize = (int)sub->myRoute.size();
2208 myLane->addMoveReminder(sub, false);
2209
2210 // copy trains that are currently on this driveway (and associated entry events)
2211 for (SUMOVehicle* veh : myTrains) {
2212 auto itOnSub = std::find(sub->myRoute.begin(), sub->myRoute.end(), veh->getEdge());
2213 if (itOnSub != sub->myRoute.end()) {
2214 sub->myTrains.insert(veh);
2215 // non-zero is enough to avoid superfluous activation via activateReminders (and removal)
2216 const double pos = sub->myRoute.front()->getLength();
2217 dynamic_cast<MSBaseVehicle*>(veh)->addReminder(sub, pos);
2218 for (const VehicleEvent& ve : myVehicleEvents) {
2219 if (ve.id == veh->getID()) {
2220 sub->myVehicleEvents.push_back(ve);
2221 }
2222 }
2223 }
2224 }
2225
2226 foe->myFoes.push_back(sub);
2227 if (foe->bidiBlockedByEnd(*sub)) {
2228 foe->addSidings(sub);
2229 }
2230 sub->myFoes.push_back(foe);
2231 mySubDriveWays.push_back(sub);
2232#ifdef DEBUG_BUILD_SUBDRIVEWAY
2233 if (gDebugFlag4) {
2234 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " sub=" << sub->getID() << " route=" << toString(sub->myRoute) << "\n";
2235 }
2236#endif
2237 return true;
2238}
2239
2240
2241double
2243 assert(lastIndex < (int)myForward.size());
2244 double result = 0;
2245 for (int i = 0; i <= lastIndex; i++) {
2246 result += myForward[i]->getLength();
2247 }
2248 return result;
2249}
2250
2251
2252void
2254 const ConstMSEdgeVector& foeRoute = foe->isSubDriveWay() ? foe->myParent->myRoute : foe->myRoute;
2255 const MSEdge* foeEndBidi = foe->myForward.back()->getEdge().getBidiEdge();
2256 int foeForwardNormals = 0;
2257 for (auto lane : foe->myForward) {
2258 if (lane->isNormal()) {
2259 foeForwardNormals++;
2260 }
2261 }
2262 if (foeForwardNormals == (int)foeRoute.size()) {
2263#ifdef DEBUG_BUILD_SIDINGS
2264 if (gDebugFlag4) {
2265 std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " foeForwardNormals=" << foeForwardNormals << " frSize=" << foeRoute.size() << " aborted\n";
2266 }
2267#endif
2268 return;
2269 }
2270 auto foeSearchBeg = foeRoute.begin() + foeForwardNormals;
2271 auto foeSearchEnd = foeRoute.end();
2272 if (foeEndBidi == nullptr) {
2273 throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " noBidi\n");
2274 }
2275 // if foe is a subDriveway, the forward section may end on an internal edge which would not be found on myRoute
2276 foeEndBidi = foeEndBidi->getNormalSuccessor();
2277 std::set<const MSEdge*> foeForwardEdges(foeRoute.begin(), foeRoute.begin() + foeForwardNormals);
2278 int forwardNormals = 0;
2279 for (auto lane : myForward) {
2280 if (lane->isNormal()) {
2281 forwardNormals++;
2282 if (foeForwardEdges.count(&lane->getEdge()) != 0) {
2283#ifdef DEBUG_BUILD_SIDINGS
2284 if (gDebugFlag4) {
2285 std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " forwardEdge=" << lane->getEdge().getID() << " on foeForward (sidings unsafe)\n";
2286 }
2287#endif
2288 return;
2289 }
2290 }
2291 }
2292 int i;
2293 std::vector<int> start;
2294 std::vector<double> length;
2295 std::vector<std::vector<int> > intermediateRS;
2296 for (i = 0; i < (int)myRoute.size(); i++) {
2297 if (myRoute[i] == foeEndBidi) {
2298 break;
2299 }
2300 }
2301 if (i == (int)myRoute.size()) {
2302 throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " foeEndBidi=" + foeEndBidi->getID() + " not on route\n");
2303 }
2304 const MSEdge* next = myRoute[i];
2305#ifdef DEBUG_BUILD_SIDINGS
2306 if (gDebugFlag4) {
2307 std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " next=" << next->getID() << " foeForwardNormals=" << foeForwardNormals << " frSize=" << foeRoute.size() << " foeSearchBeg=" << (*foeSearchBeg)->getID() << " addToFoe=" << addToFoe << "\n";
2308 }
2309#endif
2310 i--;
2311 // look backward along our route starting at the final edge of the foe dw
2312 for (; i >= 0; i--) {
2313 const MSEdge* cur = myRoute[i];
2314 const bool curHasRS = hasRS(cur, next);
2315 if (curHasRS) {
2316 if (std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge()) == foeSearchEnd) {
2317 // we found a rail signal in a safe spot (not on the foe route)
2318 start.push_back(i);
2319 length.push_back(0);
2320 intermediateRS.push_back({});
2321 }
2322 }
2323 if (!start.empty()) {
2324 // move further backwards along the route to find the spot where it merges again with the foe route
2325 auto itFind = std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge());
2326 if (itFind != foeSearchEnd) {
2327#ifdef DEBUG_BUILD_SIDINGS
2328 if (gDebugFlag4) {
2329 std::cout << "endSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " curBidi=" << Named::getIDSecure(cur->getBidiEdge()) << " length=" << toString(length) << "\n";
2330 }
2331#endif
2332 const int firstIndex = i + 1;
2333 if (addToFoe) {
2334 auto& foeSidings = foe->mySidings[this];
2335 // indices must be mapped onto foe route;
2336 const MSEdge* first = myRoute[firstIndex];
2337 auto itFirst = std::find(foeRoute.begin(), foeRoute.end(), first);
2338 if (itFirst != foeRoute.end()) {
2339 for (int j = 0; j < (int)length.size(); j++) {
2340 const MSEdge* last = myRoute[start[j]];
2341 auto itLast = std::find(itFirst, foeRoute.end(), last);
2342 if (itLast != foeRoute.end()) {
2343 // @todo are intermediateRS relevant here?
2344 foeSidings.insert(foeSidings.begin(), Siding((int)(itFirst - foeRoute.begin()), (int)(itLast - foeRoute.begin()), length[j], {}));
2345#ifdef DEBUG_BUILD_SIDINGS
2346 if (gDebugFlag4) {
2347 std::cout << " found endSiding start=" << foeSidings.front().start << " end=" << foeSidings.front().end << " length=" << foeSidings.front().length << "\n";
2348 }
2349#endif
2350 if (foeSidings.size() > 2) {
2351 foeSidings.pop_back(); // only need the first 2 sidings
2352 }
2353 }
2354 }
2355 }
2356 } else {
2357 // pick up further rail signals between the start of the siding and the start of the current driveway
2358 std::vector<int> furtherRS;
2359 if (curHasRS) {
2360 furtherRS.push_back(i);
2361 }
2362 const MSEdge* next2 = cur;
2363 for (int i2 = i - 1; i2 >= forwardNormals; i2--) {
2364 const MSEdge* cur2 = myRoute[i2];
2365 if (hasRS(cur2, next2)) {
2366 furtherRS.push_back(i2);
2367 }
2368 next2 = cur2;
2369 }
2370 auto& foeSidings = mySidings[foe];
2371 for (int j = 0; j < (int)length.size(); j++) {
2372 intermediateRS[j].insert(intermediateRS[j].end(), furtherRS.begin(), furtherRS.end());
2373 foeSidings.insert(foeSidings.begin(), Siding(firstIndex, start[j], length[j], intermediateRS[j]));
2374#ifdef DEBUG_BUILD_SIDINGS
2375 if (gDebugFlag4) {
2376 std::cout << " found endSiding start=" << foeSidings.front().start << " end=" << foeSidings.front().end << " length=" << foeSidings.front().length << "\n";
2377 }
2378#endif
2379 if (foeSidings.size() > 2) {
2380 foeSidings.pop_back(); // only need the first 2 sidings
2381 }
2382 }
2383 }
2384 start.clear();
2385 length.clear();
2386 intermediateRS.clear();
2387 foeSearchBeg = itFind;
2388 } else {
2389 for (int j = 0; j < (int)length.size(); j++) {
2390 length[j] += cur->getLength();
2391 if (curHasRS && i != start[j]) {
2392 intermediateRS[j].push_back(i);
2393 }
2394 }
2395 }
2396 }
2397 next = cur;
2398 }
2399 // register in mySidingDriveways
2400 MSDriveWay* dw = addToFoe ? foe : this;
2401 MSDriveWay* dwFoe = addToFoe ? this : foe;
2402 auto it = dw->mySidings.find(dwFoe);
2403 if (it != dw->mySidings.end()) {
2404 for (const auto& siding : it->second) {
2405 mySidingDriveways[dw->myRoute[siding.end]].push_back(std::make_pair(dw, dwFoe));
2406 }
2407 }
2408}
2409
2410
2411bool
2412MSDriveWay::hasRS(const MSEdge* cur, const MSEdge* next) {
2414 // check if there is a controlled link between cur and next
2415 for (auto lane : cur->getLanes()) {
2416 for (const MSLink* link : lane->getLinkCont()) {
2417 if (&link->getLane()->getEdge() == next && link->getTLLogic() != nullptr) {
2418 return true;
2419 }
2420 }
2421 }
2422 }
2423 return false;
2424}
2425
2426
2427bool
2429 const MSEdge* foeForwardEnd = &foe->myForward.back()->getNormalPredecessorLane()->getEdge();
2430 return std::find(myRoute.begin(), myRoute.end(), foeForwardEnd) != myRoute.end();
2431}
2432
2433void
2435 if (link->getTLLogic() != nullptr) {
2436 // ignore links that originate on myBidi
2437 // and also links from the same junction as my own link
2438 const MSLane* origin = link->getLaneBefore();
2439 if (std::find(myBidi.begin(), myBidi.end(), origin) == myBidi.end()) {
2440 if (link->getJunction() != myRoute.front()->getFromJunction()) {
2441 if (std::find(myConflictLinks.begin(), myConflictLinks.end(), link) == myConflictLinks.end()) {
2442 myConflictLinks.push_back(const_cast<MSLink*>(link));
2443 }
2444 }
2445 }
2446 }
2447}
2448
2449void
2450MSDriveWay::addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes) {
2451 std::set<const MSDriveWay*> filtered;
2452 // we do not need to keep any of our own foes. If any of them were occupied then
2453 // foeDriveWayOccupied would return True without considering myDeadlocks
2454 for (const MSDriveWay* foe : deadlockFoes) {
2455 if (std::find(myFoes.begin(), myFoes.end(), foe) == myFoes.end()) {
2456 filtered.insert(foe);
2457 }
2458 }
2459 if (std::find(myDeadlocks.begin(), myDeadlocks.end(), filtered) == myDeadlocks.end()) {
2460 myDeadlocks.push_back(filtered);
2461 //std::cout << getID() << " deadlockFoes=" << toString(filtered) << "\n";
2462 }
2463}
2464
2465const MSDriveWay*
2467 const MSEdge* edge = init ? veh->getRoute().getEdges()[veh->getDepartEdge()] : veh->getEdge();
2469 for (const MSLane* lane : edge->getLanes()) {
2470 for (auto ili : lane->getIncomingLanes()) {
2471 const MSLink* entry = ili.viaLink->getCorrespondingEntryLink();
2472 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(entry->getTLLogic());
2473 if (rs != nullptr) {
2474 const MSDriveWay* dw = &const_cast<MSRailSignal*>(rs)->retrieveDriveWayForVeh(entry->getTLIndex(), veh);
2475 if (&dw->myForward.front()->getEdge() == edge) {
2476 return dw;
2477 }
2478 }
2479 }
2480 }
2481 }
2482 for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2483 auto matchStart = init ? veh->getRoute().begin() + veh->getDepartEdge() : veh->getCurrentRouteEdge();
2484 if (dw->match(matchStart, veh->getRoute().end())) {
2485 return dw;
2486 }
2487 }
2488 const std::string id = edge->getFromJunction()->getID() + ".d" + toString(myDepartDrivewayIndex[edge->getFromJunction()]++);
2489 MSDriveWay* dw = buildDriveWay(id, nullptr, veh->getCurrentRouteEdge(), veh->getRoute().end());
2490 myDepartureDriveways[edge].push_back(dw);
2491 myDepartureDrivewaysEnds[&dw->myForward.back()->getEdge()].push_back(dw);
2492 dw->setVehicle(veh->getID());
2493 return dw;
2494}
2495
2496
2497const std::vector<MSDriveWay*>&
2499 auto it = myEndingDriveways.find(edge);
2500 if (it == myEndingDriveways.end()) {
2501 return EMPTY_DRIVEWAY_VECTOR;
2502 } else {
2503 return it->second;
2504 }
2505}
2506
2507
2508void
2510 for (auto item : myDepartureDriveways) {
2511 const MSEdge* edge = item.first;
2512 if (item.second.size() > 0) {
2513 od.openTag("departJunction");
2515 for (const MSDriveWay* dw : item.second) {
2516 if (writeVehicles) {
2517 dw->writeBlockVehicles(od);
2518 } else {
2519 dw->writeBlocks(od);
2520 }
2521 }
2522 od.closeTag(); // departJunction
2523 }
2524 }
2525}
2526
2527void
2529 // all driveways are in myEndingDriveways which makes it convenient
2530 for (auto item : myEndingDriveways) {
2531 for (MSDriveWay* dw : item.second) {
2532 dw->_saveState(out);
2533 for (MSDriveWay* sub : dw->mySubDriveWays) {
2534 sub->_saveState(out);
2535 }
2536 }
2537 }
2538}
2539
2540void
2542 if (!myTrains.empty() || haveSubTrains()) {
2546 if (!myTrains.empty()) {
2547 std::vector<std::string> trainIDs;
2548 for (SUMOVehicle* veh : myTrains) {
2549 trainIDs.push_back(veh->getID());
2550 }
2551 out.writeAttr(SUMO_ATTR_VEHICLES, toString(trainIDs));
2552 }
2553 out.closeTag();
2554 }
2555}
2556
2557
2558bool
2560 for (MSDriveWay* sub : mySubDriveWays) {
2561 if (!sub->myTrains.empty()) {
2562 return true;
2563 }
2564 }
2565 return false;
2566}
2567
2568void
2570 if ((int)myDriveWayRouteLookup.size() < myGlobalDriveWayIndex) {
2571 for (auto item : myEndingDriveways) {
2572 for (MSDriveWay* dw : item.second) {
2573 myDriveWayRouteLookup[dw->myRoute] = dw;
2574 }
2575 }
2576 }
2578 bool ok;
2579 const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
2580 const std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), ok);
2581 ConstMSEdgeVector route;
2582 if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
2583 MSEdge::parseEdgesList(edges, route, id);
2584 }
2585 // missing driveways and subdriveways can be ignored. They may have been created
2586 // for vehicles that are not relevant at state loading time
2587 MSDriveWay* dw = nullptr;
2588 if (tag == SUMO_TAG_DRIVEWAY) {
2589 auto it = myDriveWayRouteLookup.find(route);
2590 if (it == myDriveWayRouteLookup.end()) {
2591 //WRITE_WARNING(TLF("Unknown driveWay '%' with route '%'", id, edges));
2592 return;
2593 }
2594 dw = it->second;
2595 myDriveWayLookup[id] = dw;
2596 } else {
2597 std::string parentID = id.substr(0, id.rfind('.'));
2598 auto it = myDriveWayLookup.find(parentID);
2599 if (it == myDriveWayLookup.end()) {
2600 //WRITE_WARNING(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2601 return;
2602 }
2603 MSDriveWay* parent = it->second;
2604 for (MSDriveWay* sub : parent->mySubDriveWays) {
2605 if (sub->myRoute == route) {
2606 dw = sub;
2607 break;
2608 }
2609 }
2610 if (dw == nullptr) {
2611 // missing subdriveways can be ignored. They may have been created
2612 // as foes for driveways that are not relevant at state loading time
2613 return;
2614 }
2615 }
2616 const std::string vehicles = attrs.getOpt<std::string>(SUMO_ATTR_VEHICLES, id.c_str(), ok, "");
2617 for (const std::string& vehID : StringTokenizer(vehicles).getVector()) {
2618 MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(c.getVehicle(vehID));
2619 if (veh == nullptr) {
2620 throw ProcessError(TLF("Unknown vehicle '%' in driveway '%'", vehID, id));
2621 }
2622 if (!dw->hasTrain(veh)) {
2623 dw->myTrains.insert(veh);
2624 veh->addReminder(dw);
2625 }
2626 }
2627}
2628
2629const MSDriveWay*
2630MSDriveWay::retrieveDepartDriveWay(const MSEdge* edge, const std::string& id) {
2631 for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2632 if (dw->getID() == id) {
2633 return dw;
2634 }
2635 }
2636 return nullptr;
2637}
2638
2639
2640bool
2642 return myTrains.count(veh) != 0;
2643}
2644
2645
2646double
2648 double result = 0;
2649 if (myParent != nullptr) {
2650 auto it = std::find(myParent->myForward.begin(), myParent->myForward.end(), myForward.back());
2651 assert(it != myParent->myForward.end());
2652 for (; it != myParent->myForward.end(); it++) {
2653 result += (*it)->getLength();
2654 }
2655 }
2656 return result;
2657}
2658
2659/****************************************************************************/
#define DEBUG_HELPER(obj)
#define DEBUG_COND_DW(obj)
#define DEBUG_COND_DW2
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:75
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:74
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition MSRoute.h:57
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:107
#define SIMSTEP
Definition SUMOTime.h:69
#define SIMTIME
Definition SUMOTime.h:70
bool isRailwayOrShared(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge or a shared road/rail edge.
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SUMO_TAG_SUBDRIVEWAY
@ SUMO_TAG_DRIVEWAY
Saved driveway information.
@ TURN
The link is a 180 degree turn.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ SUMO_ATTR_EDGES
the edges of a route
@ SUMO_ATTR_LANES
@ SUMO_ATTR_VEHICLES
@ SUMO_ATTR_VEHICLE
@ SUMO_ATTR_ID
@ SUMO_ATTR_TIME
trigger: the time of the step
bool gDebugFlag4
Definition StdDefs.cpp:47
T MIN2(T a, T b)
Definition StdDefs.h:80
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:374
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:347
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
Definition ToString.h:355
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition MELoop.cpp:397
A single mesoscopic segment (cell)
Definition MESegment.h:50
void addDetector(MSMoveReminder *data, int queueIndex=-1)
Adds a data collector for a detector to this segment.
The base class for microscopic and mesoscopic vehicles.
const SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
void addReminder(MSMoveReminder *rem, double pos=0)
Adds a MoveReminder dynamically.
bool isStopped() const
Returns whether the vehicle is at a stop.
SUMOTime getStartupDelay() const
Get the vehicle type's startupDelay.
Definition MSCFModel.h:309
void addFoes(const MSLink *link)
add all driveWays that start at the given link as foes
std::vector< MSLink * > myConflictLinks
Definition MSDriveWay.h:274
const SUMOVehicle * myActive
whether the current signal is switched green for a train approaching this block
Definition MSDriveWay.h:228
bool crossingConflict(const MSDriveWay &other) const
Whether there is a crossing conflict with the given driveway.
static std::string getJunctionLinkID(const MSLink *link)
return junctionID_junctionLinkIndex
static void clearState()
bool haveSubTrains() const
std::vector< MSDriveWay * > mySubDriveWays
Definition MSDriveWay.h:395
std::vector< std::set< const MSDriveWay * > > myDeadlocks
Definition MSDriveWay.h:390
bool myAbortedBuild
whether driveway building was aborted due to MAX_BLOCK_LENGTH
Definition MSDriveWay.h:244
bool buildSubFoe(MSDriveWay *foe, bool movingBlock)
std::set< SUMOVehicle *, ComparatorNumericalIdLess > myTrains
Definition MSDriveWay.h:385
static std::map< const MSJunction *, int > myDepartDrivewayIndex
Definition MSDriveWay.h:416
std::vector< const MSLane * > myBidiExtendedSorted
Definition MSDriveWay.h:262
static const std::vector< MSDriveWay * > EMPTY_DRIVEWAY_VECTOR
Definition MSDriveWay.h:429
void buildRoute(const MSLink *origin, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap &visited, std::set< MSLink *, MSLink::ComparatorNumericalLaneIdLess > &)
const MSDriveWay * getFoeOrSubFoe(const MSDriveWay *dw) const
return dw if it is a foe or a subDrivway of dw if it is a foe
static bool hasJoin(const SUMOVehicle *ego, const SUMOVehicle *foe)
bool isDepartDriveway() const
Definition MSDriveWay.h:166
static std::string getClickableTLLinkID(const MSLink *link)
return logicID_linkIndex in a way that allows clicking in sumo-gui
const MSLink * myOrigin
the link that enters this driveway or nullptr for a departure driveWay
Definition MSDriveWay.h:225
bool myTerminateRoute
Definition MSDriveWay.h:242
static double myMovingBlockMaxDist
Definition MSDriveWay.h:405
std::vector< const MSLane * > myBidi
Definition MSDriveWay.h:257
static std::vector< const MSEdge * > myCurrentSidingCheck
Definition MSDriveWay.h:424
static bool myWriteVehicles
Definition MSDriveWay.h:404
bool notifyReroute(SUMOTrafficObject &veh)
Called if the vehicle change it's route.
bool hasLinkConflict(const Approaching &closest, const MSLink *foeLink) const
Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link...
std::vector< const MSLane * > myBidiExtended
Definition MSDriveWay.h:261
MSDriveWay(const MSLink *origin, const std::string &id, bool temporary=false)
static bool hasRS(const MSEdge *cur, const MSEdge *next)
void addBidiFoes(const MSRailSignal *ownSignal, bool extended)
derive foe driveways based on myBidi or myBidiExtended
static const MSDriveWay * retrieveDepartDriveWay(const MSEdge *edge, const std::string &id)
static std::map< const MSEdge *, std::vector< std::pair< MSDriveWay *, MSDriveWay * > >, ComparatorNumericalIdLess > mySidingDriveways
all driveways that use a siding which ends on this edge as pair (dw, foe)
Definition MSDriveWay.h:423
void writeBlocks(OutputDevice &od) const
Write block items for this driveway.
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, Notification reason, const MSLane *enteredLane=0)
Called if the vehicle leaves the reminder's lane.
bool sidingDeadlock(const SUMOVehicle *veh) const
whether insertion on this driveway would cause deadlock in an approached siding
std::vector< const MSLane * > myForward
Definition MSDriveWay.h:252
std::vector< const MSEdge * > myReversals
track own occurences in myReversalDriveWays for cleanup in destructor
Definition MSDriveWay.h:398
static const std::vector< MSDriveWay * > & getEndingDriveWays(const MSEdge *edge)
std::map< const MSDriveWay *, std::vector< Siding >, ComparatorIdLess > mySidings
Definition MSDriveWay.h:389
void writeBlockVehicles(OutputDevice &od) const
virtual ~MSDriveWay()
Destructor.
bool match(MSRouteIterator firstIt, MSRouteIterator endIt) const
whether the give route matches this driveway
static void appendMapIndex(LaneVisitedMap &map, const MSLane *lane)
append to map by map index and avoid undefined behavior
bool overlap(const MSDriveWay &other) const
Whether this driveway (route) overlaps with the given one.
std::vector< const MSLane * > myFlank
Definition MSDriveWay.h:266
static std::string getTLLinkID(const MSLink *link)
return logicID_linkIndex
std::vector< const MSEdge * > myRoute
list of edges for matching against train routes
Definition MSDriveWay.h:231
std::map< const MSLane *, int, ComparatorNumericalIdLess > LaneVisitedMap
Definition MSDriveWay.h:45
static void writeDepatureBlocks(OutputDevice &od, bool writeVehicles)
static std::map< ConstMSEdgeVector, MSDriveWay * > myDriveWayRouteLookup
lookup table for state loading
Definition MSDriveWay.h:427
int getNumericalID() const
Definition MSDriveWay.h:133
static std::set< const MSEdge * > myBlockLengthWarnings
Definition MSDriveWay.h:406
static std::map< const MSEdge *, std::vector< MSDriveWay * > > myReversalDriveWays
all driveways reversing on the given switch (used to look up flank foes)
Definition MSDriveWay.h:412
static void init()
void _saveState(OutputDevice &out) const
static std::string formatVisitedMap(const LaneVisitedMap &visited)
print link descriptions
void checkFlanks(const MSLink *originLink, const std::vector< const MSLane * > &lanes, const LaneVisitedMap &visited, bool allFoes, bool movingBlock, std::set< MSLink *, MSLink::ComparatorNumericalLaneIdLess > &flankSwitches) const
static std::map< std::string, MSDriveWay * > myDriveWayLookup
Definition MSDriveWay.h:428
int matchesPastRoute(SUMOVehicle &sveh) const
void checkCrossingFlanks(MSLink *dwLink, const LaneVisitedMap &visited, std::set< MSLink *, MSLink::ComparatorNumericalLaneIdLess > &flankSwitches) const
bool flankConflict(const MSDriveWay &other) const
Whether there is a flank conflict with the given driveway.
bool conflictLaneOccupied(bool store=true, const SUMOVehicle *ego=nullptr) const
whether any of myConflictLanes is occupied (vehicles that are the target of a join must be ignored)
void addSwitchFoes(MSLink *link)
bool hasTrain(SUMOVehicle *veh) const
whether the given train is on this driveway
static std::map< const MSEdge *, std::vector< MSDriveWay * > > myDepartureDrivewaysEnds
all driveways that do not start at a rail signal (and are only used at departure) by end edge
Definition MSDriveWay.h:418
int myCoreSize
number of edges in myRoute where overlap with other driveways is forbidden
Definition MSDriveWay.h:234
double getForwardDistance(int lastIndex) const
compute distance along the forward section up to lastIndex
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
Definition MSDriveWay.h:43
void addConflictLink(const MSLink *link)
add symmetical conflict link for foes when building a new driveway
static void cleanup()
bool notifyLeaveBack(SUMOTrafficObject &veh, Notification reason, const MSLane *leftLane)
Called if the vehicle's back leaves the reminder's lane.
std::string myFirstVehicle
the first vehicle using this driveway
Definition MSDriveWay.h:401
bool forwardEndOnRoute(const MSDriveWay *foe) const
bool myFoundJump
Definition MSDriveWay.h:241
static void saveState(OutputDevice &out)
Save driveway occupancy into the given stream.
MSDriveWay * myParent
set to parent driveway if this is a subDriveway, nullptr otherwise
Definition MSDriveWay.h:248
static std::map< const MSEdge *, std::vector< MSDriveWay * >, ComparatorNumericalIdLess > myDepartureDriveways
all driveways that do not start at a rail signal (and are only used at departure)
Definition MSDriveWay.h:415
void setVehicle(const std::string &vehID)
Definition MSDriveWay.h:145
bool myBidiEnded
whether driveway building was aborted when no further bidi edge was found
Definition MSDriveWay.h:246
static bool mustYield(const Approaching &veh, const Approaching &foe)
Whether veh must yield to the foe train.
void findFlankProtection(MSLink *link, MSLink *origLink, const std::vector< const MSLane * > &flank)
void addSidings(MSDriveWay *foe, bool addToFoe=false)
add sidings for the given foe
void enterDriveWay(SUMOVehicle &sveh, Notification reason)
helper method for notifyEnter
bool bidiBlockedByEnd(const MSDriveWay &other) const
Whether there is a bidi conflict with the end of the given driveway.
static int myGlobalDriveWayIndex
Definition MSDriveWay.h:403
bool isSubDriveWay() const
Definition MSDriveWay.h:185
static MSDriveWay * buildDriveWay(const std::string &id, const MSLink *link, MSRouteIterator first, MSRouteIterator end)
construct a new driveway by searching along the given route until all block structures are found
bool myFoundSignal
whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
Definition MSDriveWay.h:240
static std::map< const MSLink *, std::vector< MSDriveWay * > > mySwitchDriveWays
all driveways passing the given switch (used to look up flank foes)
Definition MSDriveWay.h:409
void addReversalFoes(bool movingBlock)
derive foe driveways that enter the bidi section by reversing
int myForwardEdgeCount
number of normal edges in myForward
Definition MSDriveWay.h:237
void addDWDeadlock(const std::vector< const MSDriveWay * > &deadlockFoes)
static std::map< const MSEdge *, std::vector< MSDriveWay * >, ComparatorNumericalIdLess > myEndingDriveways
all driveways that end on the given edge
Definition MSDriveWay.h:421
bool foeDriveWayApproached() const
whether any of my Foes is being approached
static void loadState(const SUMOSAXAttributes &attrs, int tag)
bool forwardRouteConflict(std::set< const MSEdge * > forward, const MSDriveWay &other, bool secondCheck=false)
Whether the route of other passes into the forward section of this driveway.
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
Definition MSDriveWay.h:269
static const MSDriveWay * getDepartureDriveway(const SUMOVehicle *veh, bool init=false)
std::vector< MSDriveWay * > myFoes
Definition MSDriveWay.h:388
std::vector< VehicleEvent > myVehicleEvents
Definition MSDriveWay.h:387
static bool isSwitch(const MSLink *link)
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane)
Checks whether the reminder is activated by a vehicle entering the lane.
bool bidiBlockedBy(const MSDriveWay &other) const
Whether there is a bidi conflict with the given driveway.
bool reserve(const Approaching &closest, MSEdgeVector &occupied)
attempt reserve this driveway for the given vehicle
std::pair< bool, const MSDriveWay * > canUseSiding(const SUMOVehicle *ego, const MSDriveWay *foe, const MSEdge *recurseSidingEnd=nullptr) const
return whether a siding can be used. If a siding exist but is occupied, also return the occupied driv...
void addParallelFoes(const MSLink *link, const MSEdge *first)
derive foe driveways that start at the same signal
bool foeDriveWayOccupied(bool store, const SUMOVehicle *ego, MSEdgeVector &occupied) const
whether any of myFoes is occupied (vehicles that are the target of a join must be ignored)
double getParentRemainingLength() const
return for how much longer the parent driveway continues after the end of this subdriveway
A road/street connecting two junctions.
Definition MSEdge.h:78
static void clear()
Clears the dictionary.
Definition MSEdge.cpp:1163
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition MSEdge.h:659
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:169
static void parseEdgesList(const std::string &desc, ConstMSEdgeVector &into, const std::string &rid)
Parses the given string assuming it contains a list of edge ids divided by spaces.
Definition MSEdge.cpp:1183
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition MSEdge.cpp:1017
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:284
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:265
const MSJunction * getToJunction() const
Definition MSEdge.h:428
double getLength() const
return the length of the edge
Definition MSEdge.h:695
const MSJunction * getFromJunction() const
Definition MSEdge.h:424
bool isConnectedTo(const MSEdge &destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions=false) const
Definition MSEdge.h:245
static bool gUseMesoSim
Definition MSGlobals.h:106
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition MSGlobals.h:115
static SUMOTime gTimeToTeleportRSDeadlock
Definition MSGlobals.h:72
static double gMaxRailSignalBlockLength
The maximum length of a rail signal block.
Definition MSGlobals.h:192
The base class for an intersection.
Definition MSJunction.h:58
SumoXMLNodeType getType() const
return the type of this Junction
Definition MSJunction.h:133
virtual const MSJunctionLogic * getLogic() const
Definition MSJunction.h:141
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:108
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
Representation of a lane in the micro simulation.
Definition MSLane.h:84
static void clear()
Clears the dictionary.
Definition MSLane.cpp:2561
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2801
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2514
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:984
virtual void addMoveReminder(MSMoveReminder *rem, bool addToVehicles=true)
Add a move-reminder to move-reminder container.
Definition MSLane.cpp:362
const MSJunction * getToJunction() const
Definition MSLane.cpp:4833
double getLength() const
Returns the lane's length.
Definition MSLane.h:632
const MSJunction * getFromJunction() const
Definition MSLane.cpp:4827
int getIndex() const
Returns the lane's index.
Definition MSLane.h:668
MSLane * getLogicalPredecessorLane() const
get the most likely predecessor lane (sorted using by_connections_to_sorter). The result is cached in...
Definition MSLane.cpp:3271
bool isNormal() const
Definition MSLane.cpp:2675
bool isInternal() const
Definition MSLane.cpp:2669
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4782
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3296
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
Something on a lane to be noticed about vehicle movement.
const std::string & getDescription() const
Notification
Definition of a vehicle state.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
@ NOTIFICATION_REROUTE
The vehicle changed it's route.
@ NOTIFICATION_SEGMENT
The vehicle changes the segment (meso only)
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
@ NOTIFICATION_PARKING
The vehicle starts or ends parking.
static StringBijection< Notification > Notifications
MSLane * myLane
Lane on which the reminder works.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:201
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:402
void notifyApproach(const MSLink *link)
switch rail signal to active
void addWaitRelation(const SUMOVehicle *waits, const MSRailSignal *rs, const SUMOVehicle *reason, MSRailSignalConstraint *constraint=nullptr)
static MSRailSignalControl & getInstance()
static bool isUsingDriveWays(SVCPermissions svc)
static bool isMovingBlock(SVCPermissions svc)
A signal for rails.
bool isMovingBlock() const
const MSDriveWay & getExistingDriveWay(const MSLink *link, MSRouteIterator firstIt, MSRouteIterator endIt)
const MSDriveWay & retrieveDriveWayForVeh(int tlIndex, const SUMOVehicle *veh)
static std::string describeLinks(std::vector< MSLink * > links)
print link descriptions
bool constraintsAllow(const SUMOVehicle *veh, bool storeWaitRelation=false) const
whether the given vehicle is free to drive
static VehicleVector & rivalVehicles()
static bool storeVehicles()
const std::vector< MSDriveWay * > retrieveDriveWays(int tlIndex) const
static VehicleVector & priorityVehicles()
static std::vector< const MSDriveWay * > & blockingDriveWays()
static VehicleVector & blockingVehicles()
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:128
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition MSRoute.cpp:79
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
The parent class for traffic light logics.
TrafficLightType getLogicType() const
Returns the type of the logic.
The class responsible for building and deletion of vehicles.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
const MSCFModel & getCarFollowModel() const
Returns the vehicle type's car following model definition (const version)
Base class for objects which have an id.
Definition Named.h:53
std::string myID
The name of the object.
Definition Named.h:124
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
void lf()
writes a line feed if applicable
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false, const bool escape=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
Representation of a vehicle, person, or container.
virtual bool isVehicle() const
Whether it is a vehicle.
virtual const MSEdge * getCurrentEdge() const =0
Returns the edge (normal or internal) the object is currently at.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const MSLane * getBackLane() const =0
Returns the lane the where the rear of the object is currently at.
virtual SUMOTime getWaitingTime(const bool accumulated=false) const =0
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual const MSEdge * getEdge() const =0
Returns the (normal) route edge the object is currently at.
Representation of a vehicle.
Definition SUMOVehicle.h:63
virtual bool isStopped() const =0
Returns whether the vehicle is at a stop and waiting for a person or container to continue.
virtual int getDepartEdge() const =0
Returns the edge on which this vehicle shall depart.
virtual const std::list< MSStop > & getStops() const =0
virtual bool hasDeparted() const =0
Returns whether this vehicle has departed.
virtual double getLength() const =0
Returns the vehicles's length.
virtual bool isOnRoad() const =0
Returns the information whether the vehicle is on a road (is simulated)
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual int getRoutePosition() const =0
return index of edge within route
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
virtual const SUMOVehicleParameter::Stop * getNextStopParameter() const =0
Returns parameters of the next stop or nullptr.
virtual const MSRoute & getRoute() const =0
Returns the current route.
Definition of vehicle stop (position and duration)
std::string join
the id of the vehicle (train portion) to which this vehicle shall be joined
const std::string & getString(const T key) const
get string
std::vector< std::string > getVector()
return vector of strings
#define UNUSED_PARAMETER(x)
Function-object for stable sorting of objects with numerical ids.
Definition Named.h:38