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<ConstMSEdgeVector, MSDriveWay*> MSDriveWay::myDriveWayRouteLookup;
74std::map<std::string, MSDriveWay*> MSDriveWay::myDriveWayLookup;
75
76// ---------------------------------------------------------------------------
77// static initialisation methods
78// ---------------------------------------------------------------------------
79void
81 myWriteVehicles = OptionsCont::getOptions().isSet("railsignal-vehicle-output");
82 myMovingBlockMaxDist = OptionsCont::getOptions().getFloat("railsignal.moving-block.max-dist");
83}
84
85// ===========================================================================
86// MSDriveWay method definitions
87// ===========================================================================
88
89
90MSDriveWay::MSDriveWay(const MSLink* origin, const std::string& id, bool temporary) :
91 MSMoveReminder("DriveWay_" + (temporary ? "tmp" : id)),
92 Named(id),
93 myNumericalID(temporary ? -1 : myGlobalDriveWayIndex++),
94 myOrigin(origin),
95 myActive(nullptr),
96 myCoreSize(0),
97 myForwardEdgeCount(0),
98 myFoundSignal(false),
99 myFoundJump(false),
100 myTerminateRoute(false),
101 myAbortedBuild(false),
102 myBidiEnded(false),
103 myIsSubDriveway(false)
104{}
105
106
108 for (const MSDriveWay* sub : mySubDriveWays) {
109 delete sub;
110 }
111 mySubDriveWays.clear();
112}
113
114void
117 myBlockLengthWarnings.clear();
118 myWriteVehicles = false;
119
120 for (auto item : myDepartureDriveways) {
121 for (MSDriveWay* dw : item.second) {
122 delete dw;
123 }
124 }
131}
132
133void
135 for (auto item : myEndingDriveways) {
136 for (MSDriveWay* dw : item.second) {
137 dw->myTrains.clear();
138 }
139 }
140}
141
142
143bool
145#ifdef DEBUG_MOVEREMINDER
146 std::cout << SIMTIME << " notifyEnter " << getDescription() << " veh=" << veh.getID() << " lane=" << (MSGlobals::gUseMesoSim ? veh.getEdge()->getID() : Named::getIDSecure(enteredLane)) << " reason=" << reason << "\n";
147#endif
148 if (veh.isVehicle() && (enteredLane == myLane || (MSGlobals::gUseMesoSim && veh.getEdge() == &myLane->getEdge()))
149 && (reason == NOTIFICATION_DEPARTED || reason == NOTIFICATION_JUNCTION || reason == NOTIFICATION_PARKING)) {
150 SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
151 MSRouteIterator firstIt = std::find(sveh.getCurrentRouteEdge(), sveh.getRoute().end(), myLane->getNextNormal());
152 if (match(firstIt, sveh.getRoute().end())) {
153 if (myTrains.count(&sveh) == 0) {
154 enterDriveWay(sveh, reason);
155 }
156 return true;
157 }
158 } else if (reason == NOTIFICATION_REROUTE) {
159 assert(veh.isVehicle());
160 SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
161 assert(myTrains.count(&sveh) == 0);
162 int movedPast = matchesPastRoute(sveh);
163 // vehicle must still be one the drivway
164 if (movedPast >= 0 && movedPast < myForwardEdgeCount) {
165 enterDriveWay(sveh, reason);
166 return true;
167 }
168 }
169 return false;
170}
171
172
173bool
174MSDriveWay::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, Notification reason, const MSLane* enteredLane) {
175 UNUSED_PARAMETER(enteredLane);
176#ifdef DEBUG_MOVEREMINDER
177 std::cout << SIMTIME << " notifyLeave " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(enteredLane) << " reason=" << toString(reason) << "\n";
178#endif
179 if (veh.isVehicle()) {
180 // leaving network with departure, teleport etc
182 myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
183 if (myWriteVehicles) {
184 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
185 }
186 return false;
188 // notifyLeave is called before moving the route iterator
189 const MSLane* leftLane = (*(dynamic_cast<SUMOVehicle&>(veh).getCurrentRouteEdge()))->getLanes().front();
190 return notifyLeaveBack(veh, reason, leftLane);
191 } else {
192 return true;
193 }
194 } else {
195 return false;
196 }
197}
198
199
200bool
202#ifdef DEBUG_MOVEREMINDER
203 std::cout << SIMTIME << " notifyLeaveBack " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(leftLane) << " reason=" << toString(reason) << "\n";
204#endif
205 if (veh.isVehicle()) {
206 if (leftLane == myForward.back() && (veh.getBackLane() != leftLane->getBidiLane() || MSGlobals::gUseMesoSim)) {
207 myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
208 if (myWriteVehicles) {
209 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
210 }
211 return false;
212 } else {
213 return true;
214 }
215 } else {
216 return false;
217 }
218}
219
220
221bool
223#ifdef DEBUG_MOVEREMINDER
224 std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << "\n";
225#endif
226 assert(veh.isVehicle());
227 SUMOVehicle* sveh = dynamic_cast<SUMOVehicle*>(&veh);
228 assert(myTrains.count(sveh) != 0);
229 if (matchesPastRoute(*sveh) >= 0) {
230 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
231 return true;
232 }
233 // no match found, remove
234 myTrains.erase(sveh);
235 if (myWriteVehicles) {
237 }
238 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " invalid\n";
239 return false;
240}
241
242
243int
245 // look backwards along the route to find the driveway lane
246 const ConstMSEdgeVector& routeEdges = sveh.getRoute().getEdges();
247 for (int i = sveh.getRoutePosition(); i >= 0; i--) {
248 if (routeEdges[i] == myLane->getNextNormal()) {
249 MSRouteIterator firstIt = routeEdges.begin() + i;
250 if (match(firstIt, sveh.getRoute().end())) {
251 // driveway is still valid after rerouting
252 //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
253 return sveh.getRoutePosition() - i;
254 }
255 break;
256 }
257 }
258 return -1;
259}
260
261
262void
264 myTrains.insert(&sveh);
265 if (myOrigin != nullptr) {
267 }
268 for (const MSDriveWay* foe : myFoes) {
269 if (foe->myOrigin != nullptr) {
271 }
272 }
273 if (myWriteVehicles) {
274 myVehicleEvents.push_back(VehicleEvent(SIMSTEP, true, sveh.getID(), reason));
275 }
276}
277
278bool
279MSDriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
280 if (foeDriveWayOccupied(true, closest.first, occupied)) {
281 return false;
282 }
283 for (MSLink* foeLink : myConflictLinks) {
284 if (hasLinkConflict(closest, foeLink)) {
285#ifdef DEBUG_SIGNALSTATE
286 if (gDebugFlag4 || DEBUG_HELPER(closest.first)) {
287 std::cout << getID() << " linkConflict with " << getTLLinkID(foeLink) << "\n";
288 }
289#endif
290 return false;
291 }
292 }
293 myActive = closest.first;
294 return true;
295}
296
297
298bool
299MSDriveWay::hasLinkConflict(const Approaching& veh, const MSLink* foeLink) const {
300#ifdef DEBUG_SIGNALSTATE_PRIORITY
301 if (gDebugFlag4) {
302 std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << " ego=" << Named::getIDSecure(veh.first) << "\n";
303 }
304#endif
305 if (foeLink->getApproaching().size() > 0) {
306 Approaching foe = foeLink->getClosest();
307#ifdef DEBUG_SIGNALSTATE_PRIORITY
308 if (gDebugFlag4) {
309 std::cout << " approaching foe=" << foe.first->getID() << "\n";
310 }
311#endif
312 if (foe.first == veh.first) {
313 return false;
314 }
315 const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
316 assert(foeTLL != nullptr);
317 const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
318 MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
319 if (foeRS != nullptr) {
320 const MSDriveWay& foeDriveWay = foeRS->retrieveDriveWayForVeh(foeLink->getTLIndex(), foe.first);
321 MSEdgeVector occupied;
322 if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied) ||
323 !foeRS->constraintsAllow(foe.first) ||
324 !overlap(foeDriveWay) ||
325 !isFoeOrSubFoe(&foeDriveWay) ||
326 canUseSiding(veh.first, &foeDriveWay).first) {
327#ifdef DEBUG_SIGNALSTATE_PRIORITY
328 if (gDebugFlag4) {
329 if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied)) {
330 std::cout << " foe blocked\n";
331 } else if (!foeRS->constraintsAllow(foe.first)) {
332 std::cout << " foe constrained\n";
333 } else if (!overlap(foeDriveWay)) {
334 std::cout << " no overlap with foeDW=" << foeDriveWay.getID() << "\n";
335 } else if (!isFoeOrSubFoe(&foeDriveWay)) {
336 std::cout << " foeDW=" << foeDriveWay.getID() << " is not a foe to " << getID() << "\n";
337 } else if (canUseSiding(veh.first, &foeDriveWay).first) {
338 std::cout << " use siding\n";
339 }
340 }
341#endif
342 return false;
343 }
344#ifdef DEBUG_SIGNALSTATE_PRIORITY
345 if (gDebugFlag4) {
346 std::cout
347 << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
348 << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
349 << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
350 << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
351 << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
352 << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
353 << "\n";
354 }
355#endif
356 const bool yield = mustYield(veh, foe);
358 MSRailSignal::rivalVehicles().push_back(foe.first);
359 if (yield) {
360 MSRailSignal::priorityVehicles().push_back(foe.first);
361 }
362 }
363 return yield;
364 }
365 }
366 return false;
367}
368
369
370bool
372 if (std::find(myFoes.begin(), myFoes.end(), foe) != myFoes.end()) {
373 return true;
374 }
375 for (const MSDriveWay* sub : foe->mySubDriveWays) {
376 if (isFoeOrSubFoe(sub)) {
377 return true;
378 }
379 }
380 return false;
381}
382
383
384bool
386 if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
387 if (foe.second.arrivalTime == veh.second.arrivalTime) {
388 if (foe.first->getSpeed() == veh.first->getSpeed()) {
389 if (foe.second.dist == veh.second.dist) {
390 if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
391 return foe.first->getNumericalID() < veh.first->getNumericalID();
392 } else {
393 return foe.first->getWaitingTime() > veh.first->getWaitingTime();
394 }
395 } else {
396 return foe.second.dist < veh.second.dist;
397 }
398 } else {
399 return foe.first->getSpeed() > veh.first->getSpeed();
400 }
401 } else {
402 return foe.second.arrivalTime < veh.second.arrivalTime;
403 }
404 } else {
405 return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
406 }
407}
408
409
410bool
411MSDriveWay::conflictLaneOccupied(bool store, const SUMOVehicle* ego) const {
412 for (const MSLane* lane : myConflictLanes) {
413 if (!lane->isEmpty()) {
414 std::string joinVehicle = "";
415 if (ego != nullptr && !MSGlobals::gUseMesoSim) {
417 if (stop != nullptr) {
418 joinVehicle = stop->join;
419 }
420 }
421#ifdef DEBUG_SIGNALSTATE
422 if (gDebugFlag4) {
423 std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
424 if (joinVehicle != "") {
425 std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
426 lane->releaseVehicles();
427 }
428 }
429#endif
430 if (lane->getVehicleNumberWithPartials() == 1) {
431 MSVehicle* foe = lane->getLastAnyVehicle();
432 if (joinVehicle != "") {
433 if (foe->getID() == joinVehicle && foe->isStopped()) {
434#ifdef DEBUG_SIGNALSTATE
435 if (gDebugFlag4) {
436 std::cout << " ignore join-target '" << joinVehicle << "\n";
437 }
438#endif
439 continue;
440 }
441 }
442 if (ego != nullptr) {
443 if (foe == ego && std::find(myForward.begin(), myForward.end(), lane) == myForward.end()) {
444#ifdef DEBUG_SIGNALSTATE
445 if (gDebugFlag4) {
446 std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
447 }
448#endif
449 continue;
450 }
451 if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
452#ifdef DEBUG_SIGNALSTATE
453 if (gDebugFlag4) {
454 std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
455 }
456#endif
457 continue;
458 }
459 }
460 }
461 if (MSRailSignal::storeVehicles() && store) {
462 MSRailSignal::blockingVehicles().push_back(lane->getLastAnyVehicle());
463 }
464 return true;
465 }
466 }
467 return false;
468}
469
470
471bool
473 for (const MSDriveWay* foeDW : myFoes) {
474 if (foeDW->myOrigin != nullptr && foeDW->myOrigin->getApproaching().size() > 0) {
475#ifdef DEBUG_SIGNALSTATE
476 if (gDebugFlag4) {
477 std::cout << SIMTIME << " foeLink=" << foeDW->myOrigin->getDescription() << " approachedBy=" << foeDW->myOrigin->getApproaching().begin()->first->getID() << "\n";
478 }
479#endif
480 return true;
481 }
482 }
483 return false;
484}
485
486
487bool
488MSDriveWay::foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const {
489 for (const MSDriveWay* foeDW : myFoes) {
490 if (!foeDW->myTrains.empty()) {
491#ifdef DEBUG_SIGNALSTATE
492 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
493 std::cout << SIMTIME << " " << getID() << " foeDriveWay " << foeDW->getID() << " occupied ego=" << Named::getIDSecure(ego) << " foeVeh=" << toString(foeDW->myTrains) << "\n";
494 }
495#endif
496 if (foeDW->myTrains.size() == 1) {
497 SUMOVehicle* foe = *foeDW->myTrains.begin();
498 if (foe == ego) {
499#ifdef DEBUG_SIGNALSTATE
500 if (gDebugFlag4 || DEBUG_HELPER(ego)) {
501 std::cout << " ignore ego as foe '" << Named::getIDSecure(ego) << "\n";
502 }
503#endif
504 continue;
505 }
506 if (hasJoin(ego, foe)) {
507 continue;
508 }
509 }
510 std::pair<bool, const MSDriveWay*> useSiding = canUseSiding(ego, foeDW);
511#ifdef DEBUG_SIGNALSTATE
512 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
513 auto it = mySidings.find(foeDW);
514 int numSidings = 0;
515 if (it != mySidings.end()) {
516 numSidings = it->second.size();
517 }
518 std::cout << " useSiding=" << useSiding.first << " sidingFoe=" << Named::getIDSecure(useSiding.second) << " numSidings=" << numSidings << "\n";
519 }
520#endif
521 if (useSiding.first) {
522 continue;
523 } else {
524 if (MSRailSignal::storeVehicles() && store) {
525 for (SUMOVehicle* foe : foeDW->myTrains) {
526 MSRailSignal::blockingVehicles().push_back(foe);
527 }
528 MSRailSignal::blockingDriveWays().push_back(foeDW);
529 }
530 for (const SUMOVehicle* foe : foeDW->myTrains) {
531 occupied.push_back(const_cast<MSEdge*>(foe->getEdge()));
532 MSEdge* bidi = const_cast<MSEdge*>(foe->getEdge()->getBidiEdge());
533 if (bidi != nullptr) {
534 occupied.push_back(bidi);
535 }
537 }
538 if (ego != nullptr && MSGlobals::gTimeToTeleportRSDeadlock > 0
539 && (ego->getWaitingTime() > ego->getVehicleType().getCarFollowModel().getStartupDelay() || !ego->isOnRoad())) {
540 // if there is an occupied siding, it becomes part of the waitRelation
541 SUMOVehicle* foe = *(useSiding.second == nullptr ? foeDW : useSiding.second)->myTrains.begin();
542 const MSRailSignal* rs = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
544 }
545 return true;
546 }
547 } else if (foeDW != this && isDepartDriveway() && !foeDW->isDepartDriveway()) {
548 if (foeDW->myOrigin->getApproaching().size() > 0) {
549 Approaching foeA = foeDW->myOrigin->getClosest();
550 const SUMOVehicle* foe = foeA.first;
551 if (foeA.second.dist < foe->getBrakeGap(true)) {
552 MSRouteIterator firstIt = std::find(foe->getCurrentRouteEdge(), foe->getRoute().end(), foeDW->myRoute.front());
553 if (firstIt != foe->getRoute().end()) {
554 if (foeDW->match(firstIt, foe->getRoute().end())) {
555 bool useSiding = canUseSiding(ego, foeDW).first;
556#ifdef DEBUG_SIGNALSTATE
557 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
558 std::cout << SIMTIME << " " << getID() << " blocked by " << foeDW->getID() << " (approached by " << foe->getID() << ") useSiding=" << useSiding << "\n";
559 }
560#endif
561 if (useSiding) {
562 //std::cout << SIMTIME << " " << getID() << " ego=" << ego->getID() << " foeDW=" << foeDW->getID() << " myFoes=" << toString(myFoes) << "\n";
563 continue;
564 } else {
565 return true;
566 }
567 }
568 }
569 }
570 }
571 }
572 }
573 for (const std::set<const MSDriveWay*>& dlFoes : myDeadlocks) {
574 bool allOccupied = true;
575 for (const MSDriveWay* dlFoe : dlFoes) {
576 if (dlFoe->myTrains.empty()) {
577 allOccupied = false;
578 //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck clear " << dlFoe->getID() << "\n";
579 break;
580 }
581 }
582 if (allOccupied) {
583#ifdef DEBUG_SIGNALSTATE
584 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
585 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck " << joinNamedToString(dlFoes, " ") << "\n";
586 }
587#endif
588 for (const MSDriveWay* dlFoe : dlFoes) {
589 MSRailSignal::blockingDriveWays().push_back(dlFoe);
590 }
591 return true;
592 }
593 }
594 return false;
595}
596
597
598bool
600 if (ego != nullptr && !MSGlobals::gUseMesoSim) {
601 std::string joinVehicle = "";
603 if (stop != nullptr) {
604 joinVehicle = stop->join;
605 }
606 if (joinVehicle == "" && !ego->hasDeparted() && ego->getStops().size() > 1) {
607 // check one more stop
608 auto it = ego->getStops().begin();
609 std::advance(it, 1);
610 joinVehicle = it->pars.join;
611 }
612 if (joinVehicle != "") {
613#ifdef DEBUG_SIGNALSTATE
614 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
615 std::cout << " joinVehicle=" << joinVehicle << "\n";
616 }
617#endif
618 if (foe->getID() == joinVehicle && foe->isStopped()) {
619#ifdef DEBUG_SIGNALSTATE
620 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
621 std::cout << " ignore join-target '" << joinVehicle << "\n";
622 }
623#endif
624 return true;
625 }
626 }
627
628 if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
629#ifdef DEBUG_SIGNALSTATE
630 if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
631 std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
632 }
633#endif
634 return true;
635 }
636 }
637 return false;
638}
639
640
641std::pair<bool, const MSDriveWay*>
642MSDriveWay::canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse) const {
643 auto it = mySidings.find(foe);
644 if (it != mySidings.end()) {
645 for (auto siding : it->second) {
646 // assume siding is usuable when computing state for unapproached signal (ego == nullptr)
647 if (ego == nullptr || siding.length >= ego->getLength()) {
648 // if the siding is already "reserved" by another vehicle we cannot use it here
649 const MSEdge* sidingEnd = myRoute[siding.end];
650 for (MSDriveWay* sidingApproach : myEndingDriveways[sidingEnd]) {
651 if (!sidingApproach->myTrains.empty()) {
652 // possibly the foe vehicle can use the other part of the siding
653 if (recurse) {
654 const SUMOVehicle* foeVeh = nullptr;
655 if (!foe->myTrains.empty()) {
656 foeVeh = *foe->myTrains.begin();
657 } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
658 foeVeh = foe->myOrigin->getClosest().first;
659 }
660 if (foeVeh == nullptr) {
661 WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
662 continue;
663 }
664 if (foe->canUseSiding(foeVeh, this, false).first) {
665 continue;
666 }
667 }
668 // possibly the foe vehicle
669 // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation
670#ifdef DEBUG_SIGNALSTATE
671 if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
672 std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
673 << " foeVeh=" << toString(foe->myTrains)
674 << " sidingEnd=" << sidingEnd->getID() << " sidingApproach=" << sidingApproach->getID() << " approaching=" << toString(sidingApproach->myTrains) << "\n";
675 }
676#endif
677 return std::make_pair(false, sidingApproach);
678 }
679 }
680 //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
681 // << " foeVeh=" << toString(foe->myTrains)
682 // << " sidingEnd=" << sidingEnd->getID() << "usable\n";
683 return std::make_pair(true, nullptr);
684 }
685 }
686 }
687 return std::make_pair(false, nullptr);
688}
689
690bool
691MSDriveWay::overlap(const MSDriveWay& other) const {
692 for (int i = 0; i < myCoreSize; i++) {
693 for (int j = 0; j < other.myCoreSize; j++) {
694 const MSEdge* edge = myRoute[i];
695 const MSEdge* edge2 = other.myRoute[j];
696 if (edge->getToJunction() == edge2->getToJunction()
697 || edge->getToJunction() == edge2->getFromJunction()
698 || edge->getFromJunction() == edge2->getFromJunction()) {
699 // XXX might be rail_crossing with parallel tracks
700 return true;
701 }
702 }
703 }
704 return false;
705}
706
707
708bool
710 for (const MSLane* lane : myForward) {
711 for (const MSLane* lane2 : other.myForward) {
712 if (lane == lane2) {
713 return true;
714 }
715 }
716 for (const MSLane* lane2 : other.myBidi) {
717 if (lane == lane2) {
718 if (bidiBlockedBy(other)) {
719 // it's only a deadlock if both trains block symmetrically
720 return true;
721 }
722 }
723 }
724 for (const MSLane* lane2 : other.myBidiExtended) {
725 if (lane == lane2) {
726 if (bidiBlockedBy(other)) {
727 // it's only a deadlock if both trains block symmetrically
728 return true;
729 }
730 }
731 }
732 }
733 return false;
734}
735
736
737bool
739 for (const MSLane* lane : myForward) {
740 for (const MSLane* lane2 : other.myForward) {
741 if (lane->isNormal() && lane2->isNormal() && lane->getEdge().getToJunction() == lane2->getEdge().getToJunction()) {
742 return true;
743 }
744 }
745 }
746 if (myOrigin != nullptr && other.myOrigin != nullptr
747 && myOrigin->getJunction() == other.myOrigin->getJunction()
748 //&& myForward.front()->isInternal() && other.myForward.front()->isInternal()
749 && myOrigin->getJunction()->getLogic() != nullptr
751 // switch/crossing is also a rail_signal (direct control)
752 if (!(myForward.front()->isInternal() && other.myForward.front()->isInternal())) {
753 return false;
754 }
755 return true;
756 }
757 if (other.myOrigin != nullptr && other.myForward.front()->isInternal()) {
758 for (int i = 0; i < (int)myForward.size() - 1; i++) {
759 const MSLane* lane = myForward[i];
760 if (lane->getToJunction() == other.myOrigin->getJunction()) {
761 const MSLane* next = myForward[i + 1];
762 const MSLink* link = lane->getLinkTo(next);
763 if (link && link->getTLLogic() == nullptr) {
764 // switch/crossing is also a rail_signal (direct control) but own link is uncontrolled
765 if (lane->getToJunction()->getLogic() != nullptr
766 && lane->getToJunction()->getLogic()->getFoesFor(link->getIndex()).test(other.myOrigin->getIndex())) {
767 // and links are in conflict
768 return true;
769 }
770 }
771 }
772 }
773 }
774 return false;
775}
776
777
778bool
780 for (const MSLane* lane : myBidi) {
781 for (const MSLane* lane2 : other.myForward) {
782 if (lane == lane2) {
783 return true;
784 }
785 }
786 }
787 for (const MSLane* lane : myBidiExtended) {
788 for (const MSLane* lane2 : other.myForward) {
789 if (lane == lane2) {
790 if (overlap(other)) {
791 return true;
792 }
793 }
794 }
795 }
796 return false;
797}
798
799
800bool
802 const MSLane* end = other.myForward.back();
803 for (const MSLane* lane : myBidi) {
804 if (lane == end) {
805 return true;
806 }
807 }
808 for (const MSLane* lane : myBidiExtended) {
809 if (lane == end) {
810 if (overlap(other)) {
811 return true;
812 }
813 }
814 }
815 return false;
816}
817
818bool
819MSDriveWay::forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck) {
820 int i = 0;
821 for (const MSEdge* edge2 : other.myRoute) {
822 if (i == other.myCoreSize) {
823 return false;
824 }
825 i++;
826 if (edge2 == myForward.front()->getNextNormal() && !secondCheck) {
827 // foe should not pass from behind through our own forward section
828 return false;
829 }
830 if (forward.count(edge2->getBidiEdge()) != 0) {
831 return true;
832 }
833 }
834 return false;
835}
836
837void
843 if (myCoreSize != (int)myRoute.size()) {
844 od.writeAttr("core", myCoreSize);
845 }
846 od.openTag("forward");
848 od.closeTag();
849 if (!myIsSubDriveway) {
850 od.openTag("bidi");
852 if (myBidiExtended.size() > 0) {
853 od.lf();
854 od << " ";
855 od.writeAttr("deadlockCheck", toString(myBidiExtended));
856 }
857 od.closeTag();
858 od.openTag("flank");
860 od.closeTag();
861
862 od.openTag("conflictLinks");
863
864 std::vector<std::string> signals;
865 for (MSLink* link : myConflictLinks) {
866 signals.push_back(getTLLinkID(link));
867 }
868 od.writeAttr("signals", joinToStringSorting(signals, " "));
869 od.closeTag();
870
871 std::vector<std::string> foes;
872 for (MSDriveWay* dw : myFoes) {
873 foes.push_back(dw->myID);
874 }
875 if (foes.size() > 0) {
876 od.openTag("foes");
877 od.writeAttr("driveWays", joinToStringSorting(foes, " "));
878 od.closeTag();
879 }
880 for (auto item : mySidings) {
881 od.openTag("sidings");
882 od.writeAttr("foe", item.first->getID());
883 for (auto siding : item.second) {
884 od.openTag("siding");
885 od.writeAttr("start", myRoute[siding.start]->getID());
886 od.writeAttr("end", myRoute[siding.end]->getID());
887 od.writeAttr("length", siding.length);
888 od.closeTag();
889 }
890 od.closeTag();
891 }
892 for (auto item : myDeadlocks) {
893 od.openTag("deadlock");
894 od.writeAttr("foes", joinNamedToStringSorting(item, " "));
895 od.closeTag();
896 }
897 }
898 od.closeTag(); // driveWay
899
900 for (const MSDriveWay* sub : mySubDriveWays) {
901 sub->writeBlocks(od);
902 }
903#ifdef DRIVEWAY_SANITY_CHECK
904 std::set<MSDriveWay*> uFoes(myFoes.begin(), myFoes.end());
905 if (uFoes.size() != myFoes.size()) {
906 WRITE_WARNINGF("Duplicate foes in driveway '%'", getID());
907
908 }
909#endif
910}
911
912
913void
915 od.openTag(myIsSubDriveway ? "subDriveWay" : "driveWay");
917 for (const VehicleEvent& ve : myVehicleEvents) {
918 od.openTag(ve.isEntry ? "entry" : "exit");
919 od.writeAttr(SUMO_ATTR_ID, ve.id);
921 od.writeAttr("reason", Notifications.getString(ve.reason));
922 od.closeTag(); // event
923 }
924 od.closeTag(); // driveWay
925
926 for (const MSDriveWay* sub : mySubDriveWays) {
927 sub->writeBlockVehicles(od);
928 }
929}
930
931
932void
935 LaneVisitedMap& visited,
936 std::set<MSLink*>& flankSwitches) {
937 double length = 0;
938 bool seekForwardSignal = true;
939 bool seekBidiSwitch = true;
940 bool foundUnsafeSwitch = false;
941 MSLane* toLane = origin ? origin->getViaLaneOrLane() : (*next)->getLanes()[0];
942 const std::string warnID = origin ? "rail signal " + getClickableTLLinkID(origin) : "insertion lane '" + toLane->getID() + "'";
943#ifdef DEBUG_DRIVEWAY_BUILDROUTE
945 if (gDebugFlag4) std::cout << "buildRoute origin=" << warnID << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
946 << " visited=" << formatVisitedMap(visited) << "\n";
947#endif
948 while (true) {
950 // typical block length in germany on main lines is 3-5km on branch lines up to 7km
951 // special branches that are used by one train exclusively could also be up to 20km in length
952 // minimum block size in germany is 37.5m (LZB)
953 // larger countries (USA, Russia) might see blocks beyond 20km)
954 if (seekForwardSignal && myBlockLengthWarnings.count(myRoute.front()) == 0) {
955 WRITE_WARNINGF("Block after % exceeds maximum length (stopped searching after edge '%' (length=%m).",
956 warnID, toLane->getEdge().getID(), length);
957 myBlockLengthWarnings.insert(myRoute.front());
958 }
959 myAbortedBuild = true;
960 // length exceeded
961#ifdef DEBUG_DRIVEWAY_BUILDROUTE
962 if (gDebugFlag4) {
963 std::cout << " abort: length=" << length << "\n";
964 }
965#endif
966 return;
967 }
968#ifdef DEBUG_DRIVEWAY_BUILDROUTE
969 if (gDebugFlag4) {
970 std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
971 }
972#endif
973 const MSEdge* current = &toLane->getEdge();
974 if (current->isNormal()) {
975 myRoute.push_back(current);
976 if (next != end) {
977 next++;
978 }
979 }
980 appendMapIndex(visited, toLane);
981 length += toLane->getLength();
982 MSLane* bidi = toLane->getBidiLane();
983 if (seekForwardSignal) {
984 if (!foundUnsafeSwitch) {
985 myForward.push_back(toLane);
986 if (toLane->isNormal()) {
988 }
989 if (myForward.size() == 1) {
990 myLane = toLane;
993 s->addDetector(this, myLane->getIndex());
994 } else {
995 toLane->addMoveReminder(this, false);
996 }
997 }
998 }
999 } else if (bidi == nullptr) {
1000 if (toLane->isInternal() && toLane->getIncomingLanes().front().viaLink->isTurnaround()) {
1001#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1002 if (gDebugFlag4) {
1003 std::cout << " continue bidiSearch beyond turnaround\n";
1004 }
1005#endif
1006 } else {
1007 seekBidiSwitch = false;
1008#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1009 if (gDebugFlag4) {
1010 std::cout << " noBidi, abort search for bidiSwitch\n";
1011 }
1012#endif
1013 }
1014 }
1015 if (bidi != nullptr) {
1016 if (!seekForwardSignal && !foundUnsafeSwitch && bidi->isNormal()) {
1017 // look for switch that could protect from oncoming vehicles
1018 for (const MSLink* const link : bidi->getLinkCont()) {
1019 if (link->getDirection() == LinkDirection::TURN) {
1020 continue;
1021 }
1022 if (!myBidi.empty() && link->getViaLaneOrLane() != myBidi.back()) {
1023 myCoreSize = (int)myRoute.size() - 1;
1024 MSLink* used = const_cast<MSLink*>(bidi->getLinkTo(myBidi.back()));
1025#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1026 if (gDebugFlag4) {
1027 std::cout << " found unsafe switch " << link->getDescription() << " (used=" << (used == nullptr ? "NULL" : used->getDescription()) << ")\n";
1028 }
1029#endif
1030 // trains along our route beyond this switch might create deadlock
1031 foundUnsafeSwitch = true;
1032 // the switch itself must still be guarded to ensure safety
1033 if (used != nullptr) {
1034 // possibly nullptr if there was an intermediate section of unidirectional edges
1035 flankSwitches.insert(used);
1036 }
1037 break;
1038 }
1039 }
1040 }
1041 if (foundUnsafeSwitch) {
1042 myBidiExtended.push_back(bidi);
1043 } else {
1044 myBidi.push_back(bidi);
1045 }
1046 }
1047 const std::vector<MSLink*>& links = toLane->getLinkCont();
1048 toLane = nullptr;
1049 for (const MSLink* const link : links) {
1050 if ((next != end && &link->getLane()->getEdge() == *next)
1051 && isRailwayOrShared(link->getViaLaneOrLane()->getPermissions())) {
1052 toLane = link->getViaLaneOrLane();
1053 if (link->getTLLogic() != nullptr && link->getTLIndex() >= 0 && link->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
1054 if (link == origin) {
1055 if (seekForwardSignal) {
1056 WRITE_WARNINGF(TL("Found circular block after % (% edges, length %)"), warnID, toString(myRoute.size()), toString(length));
1057 }
1058 //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1059 myAbortedBuild = true;
1060#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1061 if (gDebugFlag4) {
1062 std::cout << " abort: found circle\n";
1063 }
1064#endif
1065 return;
1066 }
1067 seekForwardSignal = false;
1068 myFoundSignal = true;
1069 seekBidiSwitch = bidi != nullptr;
1070#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1071 if (gDebugFlag4) {
1072 std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1073 }
1074#endif
1075 }
1076 //if (links.size() > 1 && !foundUnsafeSwitch) {
1077 if (isSwitch(link)) {
1078 // switch on driveway
1079 //std::cout << "mySwitchDriveWays " << getID() << " link=" << link->getDescription() << "\n";
1080 mySwitchDriveWays[link].push_back(this);
1081 }
1082 if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1083 // reversal on driveway
1084 myReversalDriveWays[current].push_back(this);
1085 myReversals.push_back(current);
1086 }
1087 break;
1088 }
1089 }
1090 if (toLane == nullptr) {
1091 if (next != end) {
1092 // no connection found, jump to next route edge
1093 toLane = (*next)->getLanes()[0];
1094#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1095 if (gDebugFlag4) {
1096 std::cout << " abort: turn-around or jump\n";
1097 }
1098#endif
1099 myFoundJump = true;
1100 return;
1101 } else {
1102#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1103 if (gDebugFlag4) {
1104 std::cout << " abort: no next lane available\n";
1105 }
1106#endif
1107 myTerminateRoute = true;
1108 return;
1109 }
1110 }
1111 }
1112 myBidiEnded = !seekBidiSwitch;
1113#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1114 if (gDebugFlag4) {
1115 std::cout << " normalEnd myBidiEnded=" << myBidiEnded << "\n";
1116 }
1117#endif
1118}
1119
1120
1121bool
1123 for (const MSLink* other : link->getLaneBefore()->getNormalPredecessorLane()->getLinkCont()) {
1124 if (other->getLane() != link->getLane() && !other->isTurnaround()) {
1125 return true;
1126 }
1127 }
1128 for (auto ili : link->getLane()->getIncomingLanes()) {
1129 if (ili.viaLink != link && !ili.viaLink->isTurnaround()) {
1130 return true;
1131 }
1132 }
1133 const MSLane* bidi = link->getLane()->getBidiLane();
1134 if (bidi != nullptr) {
1135 for (const MSLink* other : bidi->getLinkCont()) {
1136 if (other->getLane() != link->getLaneBefore()->getNormalPredecessorLane()->getBidiLane() && !other->isTurnaround()) {
1137 return true;
1138 }
1139 }
1140 }
1141 return false;
1142}
1143
1144
1145void
1146MSDriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes, bool movingBlock, std::set<MSLink*>& flankSwitches) const {
1147#ifdef DEBUG_CHECK_FLANKS
1148 std::cout << " checkFlanks lanes=" << toString(lanes) << " allFoes=" << allFoes << "\n";
1149#endif
1150 const MSLink* reverseOriginLink = originLink != nullptr && originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1151 ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1152 : nullptr;
1153 //std::cout << " originLink=" << originLink->getDescription() << "\n";
1154 if (reverseOriginLink != nullptr) {
1155 reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1156 //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1157 }
1158 for (int i = 0; i < (int)lanes.size(); i++) {
1159 const MSLane* lane = lanes[i];
1160 const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1161 const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1162 if (lane->isInternal()) {
1163 continue;
1164 }
1165 for (auto ili : lane->getIncomingLanes()) {
1166 if (ili.viaLink == originLink
1167 || ili.viaLink == reverseOriginLink
1168 || ili.viaLink->getDirection() == LinkDirection::TURN
1169 || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND
1170 || (originLink == nullptr && i == 0 && movingBlock)) {
1171 continue;
1172 }
1173 if (ili.lane != prev && ili.lane != next) {
1174#ifdef DEBUG_CHECK_FLANKS
1175 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";
1176#endif
1177 flankSwitches.insert(ili.viaLink);
1178 } else if (allFoes) {
1179 // link is part of the driveway, find foes that cross the driveway without entering
1180 checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1181 }
1182 }
1183 }
1184}
1185
1186
1187void
1188MSDriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*>& flankSwitches) const {
1189#ifdef DEBUG_CHECK_FLANKS
1190 std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1191#endif
1192 const MSJunction* junction = dwLink->getJunction();
1193 if (junction == nullptr) {
1194 return; // unregulated junction;
1195 }
1196 const MSJunctionLogic* logic = junction->getLogic();
1197 if (logic == nullptr) {
1198 return; // unregulated junction;
1199 }
1200 for (const MSEdge* in : junction->getIncoming()) {
1201 if (in->isInternal()) {
1202 continue;
1203 }
1204 for (MSLane* inLane : in->getLanes()) {
1205 const MSLane* inBidi = inLane->getBidiLane();
1206 if (isRailwayOrShared(inLane->getPermissions()) && visited.count(inLane) == 0 && (inBidi == nullptr || visited.count(inBidi) == 0)) {
1207 for (MSLink* link : inLane->getLinkCont()) {
1208 if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1209 && visited.count(link->getLane()) == 0) {
1210#ifdef DEBUG_CHECK_FLANKS
1211 std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1212#endif
1213 if (link->getViaLane() == nullptr) {
1214 flankSwitches.insert(link);
1215 } else {
1216 flankSwitches.insert(link->getViaLane()->getLinkCont().front());
1217 }
1218 }
1219 }
1220 }
1221 }
1222 }
1223}
1224
1225void
1226MSDriveWay::findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank) {
1227#ifdef DEBUG_CHECK_FLANKS
1228 std::cout << " findFlankProtection link=" << link->getDescription() << " origLink=" << origLink->getDescription() << "\n";
1229#endif
1230 if (link->getCorrespondingEntryLink()->getTLLogic() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1231 MSLink* entry = const_cast<MSLink*>(link->getCorrespondingEntryLink());
1232 // guarded by signal
1233#ifdef DEBUG_CHECK_FLANKS
1234 std::cout << " flank guarded by " << entry->getTLLogic()->getID() << "\n";
1235#endif
1236 // @note, technically it's enough to collect links from foe driveways
1237 // but this also adds "unused" conflict links which may aid comprehension
1238 myConflictLinks.push_back(entry);
1239 addFoes(entry);
1240 } else {
1241 const MSLane* lane = link->getLaneBefore();
1242 std::vector<MSLink*> predLinks;
1243 for (auto ili : lane->getIncomingLanes()) {
1244 if (!ili.viaLink->isTurnaround()) {
1245 predLinks.push_back(ili.viaLink);
1246 }
1247 }
1248 if (predLinks.size() > 1) {
1249 // this is a switch
1250#ifdef DEBUG_ADD_FOES
1251 std::cout << " predecessors of " << link->getDescription() << " isSwitch\n";
1252#endif
1253 for (MSLink* pred : predLinks) {
1254 addSwitchFoes(pred);
1255 }
1256 } else if (predLinks.size() == 1) {
1257 if (isSwitch(link)) {
1258 addSwitchFoes(link);
1259 } else {
1260 // continue upstream via single predecessor
1261 findFlankProtection(predLinks.front(), origLink, flank);
1262 }
1263 }
1264 // check for insertions
1265 if (myDepartureDriveways.count(&lane->getEdge()) != 0) {
1266 for (MSDriveWay* foe : myDepartureDriveways[&lane->getEdge()]) {
1267 if (flankConflict(*foe) || crossingConflict(*foe)) {
1268#ifdef DEBUG_ADD_FOES
1269 std::cout << " foe " << foe->getID() << " departs on flank=" << lane->getID() << "\n";
1270#endif
1271 myFoes.push_back(foe);
1272 } else {
1273#ifdef DEBUG_ADD_FOES
1274 std::cout << " cand foe " << foe->getID() << " departs on flank=" << lane->getID() << " rejected\n";
1275#endif
1276 }
1277 }
1278 }
1279 }
1280}
1281
1282
1283void
1285 auto it = mySwitchDriveWays.find(link);
1286 if (it != mySwitchDriveWays.end()) {
1287#ifdef DEBUG_ADD_FOES
1288 std::cout << " driveway " << myID << " addSwitchFoes for link " << link->getDescription() << "\n";
1289#endif
1290 for (MSDriveWay* foe : it->second) {
1291 if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1292#ifdef DEBUG_ADD_FOES
1293 std::cout << " foe=" << foe->myID
1294 << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this)
1295 << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1296#endif
1297 myFoes.push_back(foe);
1298 } else {
1299#ifdef DEBUG_ADD_FOES
1300 std::cout << " cand=" << foe->myID << "\n";
1301#endif
1302 }
1303 }
1304 }
1305}
1306
1307
1309MSDriveWay::buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end) {
1310 // collect lanes and links that are relevant for setting this signal for the current driveWay
1311 // For each driveway we collect
1312 // - conflictLanes (signal must be red if any conflict lane is occupied)
1313 // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
1314 // - that cannot break in time (arrivalSpeedBraking > 0)
1315 // - approached by a vehicle with higher switching priority (see #3941)
1316 // These objects are construct in steps:
1317 //
1318 // forwardBlock
1319 // - search forward recursive from outgoing lane until controlled railSignal link found
1320 // -> add all found lanes to conflictLanes
1321 //
1322 // bidiBlock (if any forwardBlock edge has bidi edge)
1323 // - search bidi backward recursive until first switch
1324 // - from switch search backward recursive all other incoming until controlled rail signal link
1325 // -> add final links to conflictLinks
1326 //
1327 // flanks
1328 // - search backward recursive from flanking switches
1329 // until controlled railSignal link or protecting switch is found
1330 // -> add all found lanes to conflictLanes
1331 // -> add final links to conflictLinks
1332 MSDriveWay* dw = new MSDriveWay(link, id);
1333 LaneVisitedMap visited;
1334 std::vector<const MSLane*> before;
1335 MSLane* fromBidi = nullptr;
1336 if (link != nullptr) {
1337 appendMapIndex(visited, link->getLaneBefore());
1338 fromBidi = link->getLaneBefore()->getBidiLane();
1339 }
1340 std::set<MSLink*> flankSwitches; // list of switches that threaten the driveway and for which protection must be found
1341
1342 if (fromBidi != nullptr) {
1343 before.push_back(fromBidi);
1344 }
1345 dw->buildRoute(link, first, end, visited, flankSwitches);
1346 dw->myCoreSize = (int)dw->myRoute.size();
1347
1348 MSRailSignal* rs = link ? const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(link->getTLLogic())) : nullptr;
1349 const bool movingBlock = (rs && rs->isMovingBlock()) || (!rs &&
1350 (OptionsCont::getOptions().getBool("railsignal-moving-block")
1351 || MSRailSignalControl::isMovingBlock((*first)->getPermissions())));
1352
1353 dw->checkFlanks(link, dw->myForward, visited, true, movingBlock, flankSwitches);
1354 dw->checkFlanks(link, dw->myBidi, visited, false, movingBlock, flankSwitches);
1355 dw->checkFlanks(link, before, visited, true, movingBlock, flankSwitches);
1356 for (MSLink* fsLink : flankSwitches) {
1357#ifdef DEBUG_ADD_FOES
1358 if (DEBUG_COND_DW(dw)) {
1359 std::cout << " fsLink=" << fsLink->getDescription() << "\n";
1360 }
1361#endif
1362 dw->findFlankProtection(fsLink, fsLink, dw->myFlank);
1363 }
1364 std::set<MSLink*> flankSwitchesBidiExtended;
1365 dw->checkFlanks(link, dw->myBidiExtended, visited, false, movingBlock, flankSwitchesBidiExtended);
1366 for (MSLink* const flink : flankSwitchesBidiExtended) {
1367#ifdef DEBUG_ADD_FOES
1368 if (DEBUG_COND_DW(dw)) {
1369 std::cout << " fsLinkExtended=" << flink->getDescription() << "\n";
1370 }
1371#endif
1372 dw->findFlankProtection(flink, flink, dw->myBidiExtended);
1373 }
1374#ifdef DEBUG_BUILD_DRIVEWAY
1375 if (DEBUG_COND_DW(dw)) {
1376 std::cout << SIMTIME << " buildDriveWay " << dw->myID << " link=" << (link == nullptr ? "NULL" : link->getDescription())
1377 << "\n route=" << toString(dw->myRoute)
1378 << "\n forward=" << toString(dw->myForward)
1379 << "\n bidi=" << toString(dw->myBidi)
1380 << "\n bidiEx=" << toString(dw->myBidiExtended)
1381 << "\n flank=" << toString(dw->myFlank)
1382 << "\n flankSwitch=" << MSRailSignal::describeLinks(std::vector<MSLink*>(flankSwitches.begin(), flankSwitches.end()))
1383 << "\n coreSize=" << dw->myCoreSize
1384 << "\n";
1385 }
1386#endif
1387 if (!rs || !rs->isMovingBlock()) {
1388 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myForward.begin(), dw->myForward.end());
1389 }
1390 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myBidi.begin(), dw->myBidi.end());
1391 dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myFlank.begin(), dw->myFlank.end());
1392 dw->addBidiFoes(rs, false);
1393 dw->addBidiFoes(rs, true);
1394 if (!movingBlock) {
1395 // add driveways that start on the same signal / lane
1396 dw->addParallelFoes(link, *first);
1397 }
1398 // add driveways that reverse along this driveways route
1399 dw->addReversalFoes(movingBlock);
1400 // make foes unique and symmetrical
1401 std::set<MSDriveWay*, ComparatorNumericalIdLess> uniqueFoes(dw->myFoes.begin(), dw->myFoes.end());
1402 dw->myFoes.clear();
1403 // check for self-intersecting forward-section in movingBlock mode
1404 if (movingBlock && uniqueFoes.count(dw) == 0) {
1405 std::set<const MSJunction*> forwardJunctions;
1406 for (const MSLane* fw : dw->myForward) {
1407 if (fw->isNormal()) {
1408 const MSJunction* fwTo = fw->getEdge().getToJunction();
1409 if (forwardJunctions.count(fwTo) == 1) {
1410 dw->myFoes.push_back(dw);
1411#ifdef DEBUG_ADD_FOES
1412 if (DEBUG_COND_DW(dw)) {
1413 std::cout << " self-intersecting movingBlock for dw=" << dw->getID() << "\n";
1414 }
1415#endif
1416 break;
1417 }
1418 forwardJunctions.insert(fwTo);
1419 }
1420 }
1421 }
1422 std::set<MSLink*> uniqueCLink(dw->myConflictLinks.begin(), dw->myConflictLinks.end());
1423 const MSEdge* lastEdge = &dw->myForward.back()->getEdge();
1424 for (MSDriveWay* foe : uniqueFoes) {
1425 const MSEdge* foeLastEdge = &foe->myForward.back()->getEdge();
1426 const bool sameLast = foeLastEdge == lastEdge;
1427 if (sameLast && !movingBlock) {
1428 dw->myFoes.push_back(foe);
1429 if (foe != dw) {
1430 foe->myFoes.push_back(dw);
1431 }
1432 } else {
1433 if (foe->bidiBlockedByEnd(*dw)) {
1434#ifdef DEBUG_ADD_FOES
1435 if (DEBUG_COND_DW(dw)) {
1436 std::cout << " setting " << dw->getID() << " as foe of " << foe->getID() << "\n";
1437 }
1438#endif
1439 foe->myFoes.push_back(dw);
1440 foe->addSidings(dw);
1441 } else {
1442 dw->buildSubFoe(foe, movingBlock);
1443 }
1444 if (foe != dw) { // check for movingBlock
1445 if (dw->bidiBlockedByEnd(*foe)) {
1446#ifdef DEBUG_ADD_FOES
1447 if (DEBUG_COND_DW(dw)) {
1448 std::cout << " addFoeCheckSiding " << foe->getID() << "\n";
1449 }
1450#endif
1451 dw->myFoes.push_back(foe);
1452 dw->addSidings(foe);
1453 } else {
1454 foe->buildSubFoe(dw, movingBlock);
1455 }
1456 }
1457 }
1458 if (link) {
1459 foe->addConflictLink(link);
1460 }
1461 // ignore links that have the same start junction
1462 if (foe->myRoute.front()->getFromJunction() != dw->myRoute.front()->getFromJunction()) {
1463 for (auto ili : foe->myForward.front()->getIncomingLanes()) {
1464 if (ili.viaLink->getTLLogic() != nullptr) {
1465 // ignore links that originate on myBidi
1466 const MSLane* origin = ili.viaLink->getLaneBefore();
1467 if (std::find(dw->myBidi.begin(), dw->myBidi.end(), origin) == dw->myBidi.end()) {
1468 uniqueCLink.insert(ili.viaLink);
1469 }
1470 }
1471 }
1472 }
1473 }
1474 dw->myConflictLinks.clear();
1475 dw->myConflictLinks.insert(dw->myConflictLinks.begin(), uniqueCLink.begin(), uniqueCLink.end());
1476 myEndingDriveways[lastEdge].push_back(dw);
1477 if (!movingBlock) {
1478 // every driveway is it's own foe (also all driveways that depart in the same block)
1479 for (MSDriveWay* sameEnd : myEndingDriveways[lastEdge]) {
1480 if (uniqueFoes.count(sameEnd) == 0) {
1481 dw->myFoes.push_back(sameEnd);
1482 if (sameEnd != dw) {
1483 sameEnd->myFoes.push_back(dw);
1484 }
1485 }
1486 }
1487 }
1488#ifdef DEBUG_BUILD_DRIVEWAY
1489 if (DEBUG_COND_DW(dw)) {
1490 std::cout << dw->myID << " mb=" << movingBlock << " finalFoes " << toString(dw->myFoes) << "\n";
1491 }
1492#endif
1493 return dw;
1494}
1495
1496std::string
1498 return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
1499}
1500
1501std::string
1503 return link->getJunction()->getID() + "_" + toString(link->getIndex());
1504}
1505
1506std::string
1508 return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
1509}
1510
1511std::string
1513 UNUSED_PARAMETER(visited);
1514 /*
1515 std::vector<const MSLane*> lanes(visited.size(), nullptr);
1516 for (auto item : visited) {
1517 lanes[item.second] = item.first;
1518 }
1519 for (auto it = lanes.begin(); it != lanes.end();) {
1520 if (*it == nullptr) {
1521 it = lanes.erase(it);
1522 } else {
1523 it++;
1524 }
1525 }
1526 return toString(lanes);
1527 */
1528 return "dummy";
1529}
1530
1531
1532void
1534 // avoid undefined behavior from evaluation order
1535 const int tmp = (int)map.size();
1536 map[lane] = tmp;
1537}
1538
1539bool
1541 // @todo optimize: it is sufficient to check for specific edges (after each switch)
1542 auto itRoute = firstIt;
1543 auto itDwRoute = myRoute.begin();
1544 bool match = true;
1545 while (itRoute != endIt && itDwRoute != myRoute.end()) {
1546 if (*itRoute != *itDwRoute) {
1547 match = false;
1548#ifdef DEBUG_MATCH
1549 std::cout << " check dw=" << getID() << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
1550#endif
1551 break;
1552 }
1553 itRoute++;
1554 itDwRoute++;
1555 }
1556 // if the vehicle arrives before the end of this driveway,
1557 // we'd rather build a new driveway to avoid superfluous restrictions
1558 if (match && itDwRoute == myRoute.end()
1559 && (itRoute == endIt || myAbortedBuild || myBidiEnded || myFoundJump || myIsSubDriveway)) {
1560 //std::cout << " using dw=" << "\n";
1561 if (itRoute != endIt) {
1562 // check whether the current route requires an extended driveway
1563 const MSEdge* next = *itRoute;
1564 const MSEdge* prev = myRoute.back();
1565 if (myFoundJump && prev->getBidiEdge() != next && prev->getBidiEdge() != nullptr
1566 && prev->isConnectedTo(*next, (SUMOVehicleClass)(SVC_RAIL_CLASSES & prev->getPermissions()))) {
1567#ifdef DEBUG_MATCH
1568 std::cout << " check dw=" << getID() << " prev=" << prev->getID() << " next=" << next->getID() << "\n";
1569#endif
1570 return false;
1571 }
1572 if (!myFoundJump && prev->getBidiEdge() == next && prev == &myForward.back()->getEdge()) {
1573 assert(myIsSubDriveway || myBidiEnded);
1574 // must not leave driveway via reversal
1575#ifdef DEBUG_MATCH
1576 std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, endIt)) << "\n";
1577#endif
1578 return false;
1579 }
1580 if (myForward.back()->isInternal() && myForward.back()->getNextNormal() != (*itRoute)) {
1581 // driveway is part of a direct-control conflict and continues elsewhere
1582#ifdef DEBUG_MATCH
1583 std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, itRoute)) << " (direct control)\n";
1584#endif
1585 return false;
1586 }
1587 }
1588 return true;
1589 }
1590 return false;
1591}
1592
1593void
1595#ifdef DEBUG_ADD_FOES
1596 std::cout << "driveway " << myID << " addFoes for link " << link->getDescription() << "\n";
1597#endif
1598 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
1599 if (rs != nullptr) {
1600 for (MSDriveWay* foe : rs->retrieveDriveWays(link->getTLIndex())) {
1601#ifdef DEBUG_ADD_FOES
1602 std::cout << " cand foe=" << foe->myID << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this) << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1603#endif
1604 if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1605#ifdef DEBUG_ADD_FOES
1606 std::cout << " foe=" << foe->myID << "\n";
1607#endif
1608 myFoes.push_back(foe);
1609 }
1610 }
1611 }
1612}
1613
1614
1615void
1616MSDriveWay::addBidiFoes(const MSRailSignal* ownSignal, bool extended) {
1617#ifdef DEBUG_ADD_FOES
1618 std::cout << "driveway " << myID << " addBidiFoes extended=" << extended << "\n";
1619#endif
1620 const std::vector<const MSLane*>& bidiLanes = extended ? myBidiExtended : myBidi;
1621 for (const MSLane* bidi : bidiLanes) {
1622 for (auto ili : bidi->getIncomingLanes()) {
1623 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(ili.viaLink->getTLLogic());
1624 if (rs != nullptr && rs != ownSignal &&
1625 std::find(bidiLanes.begin(), bidiLanes.end(), ili.lane) != bidiLanes.end()) {
1626 addFoes(ili.viaLink);
1627 }
1628 }
1629 const MSEdge* bidiEdge = &bidi->getEdge();
1630 if (myDepartureDriveways.count(bidiEdge) != 0) {
1631 for (MSDriveWay* foe : myDepartureDriveways[bidiEdge]) {
1632 if (flankConflict(*foe)) {
1633#ifdef DEBUG_ADD_FOES
1634 std::cout << " foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << "\n";
1635#endif
1636 myFoes.push_back(foe);
1637 } else {
1638#ifdef DEBUG_ADD_FOES
1639 std::cout << " cand foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << " rejected\n";
1640#endif
1641 }
1642 }
1643 }
1644 if (myDepartureDrivewaysEnds.count(bidiEdge) != 0) {
1645 for (MSDriveWay* foe : myDepartureDrivewaysEnds[bidiEdge]) {
1646 if (flankConflict(*foe)) {
1647#ifdef DEBUG_ADD_FOES
1648 std::cout << " foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << "\n";
1649#endif
1650 myFoes.push_back(foe);
1651 } else {
1652#ifdef DEBUG_ADD_FOES
1653 std::cout << " cand foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << " rejected\n";
1654#endif
1655 }
1656 }
1657 }
1658 }
1659}
1660
1661
1662void
1663MSDriveWay::addParallelFoes(const MSLink* link, const MSEdge* first) {
1664#ifdef DEBUG_ADD_FOES
1665 std::cout << "driveway " << myID << " addParallelFoes\n";
1666#endif
1667 if (link) {
1668 addFoes(link);
1669 } else {
1670 auto it = myDepartureDriveways.find(first);
1671 if (it != myDepartureDriveways.end()) {
1672 for (MSDriveWay* foe : it->second) {
1673#ifdef DEBUG_ADD_FOES
1674 std::cout << " foe " << foe->getID() << " departs on first=" << first->getID() << "\n";
1675#endif
1676 myFoes.push_back(foe);
1677 }
1678 }
1679 }
1680}
1681
1682
1683void
1685#ifdef DEBUG_ADD_FOES
1686 std::cout << "driveway " << myID << " addReversalFoes\n";
1687#endif
1688 std::set<const MSEdge*> forward;
1689 for (const MSLane* lane : myForward) {
1690 if (lane->isNormal()) {
1691 forward.insert(&lane->getEdge());
1692 }
1693 }
1694 int i = 0;
1695 for (const MSEdge* e : myRoute) {
1696 if (forward.count(e) != 0 && !movingBlock) {
1697 // reversals in our own forward can be ignored because each driveway
1698 // is automatically a foe of itself by default
1699 continue;
1700 }
1701 if (i == myCoreSize) {
1702 break;
1703 }
1704 i++;
1705 auto it = myReversalDriveWays.find(e);
1706 if (it != myReversalDriveWays.end()) {
1707 for (MSDriveWay* foe : it->second) {
1708 // check whether the foe reverses into our own forward section
1709 // (it might reverse again or disappear via arrival)
1710#ifdef DEBUG_ADD_FOES
1711 //std::cout << " candidate foe " << foe->getID() << " reverses on edge=" << e->getID() << " forward=" << joinNamedToString(forward, " ") << " foeRoute=" << toString(foe->myRoute) << "\n";
1712#endif
1713 if (forwardRouteConflict(forward, *foe)) {
1714 std::set<const MSEdge*> foeForward;
1715 for (const MSLane* lane : foe->myForward) {
1716 if (lane->isNormal()) {
1717 foeForward.insert(&lane->getEdge());
1718 if (lane->getBidiLane() != nullptr) {
1719 foeForward.insert(lane->getEdge().getBidiEdge());
1720 }
1721 }
1722 }
1723#ifdef DEBUG_ADD_FOES
1724 std::cout << " reversal cand=" << foe->getID() << " foeForward " << toString(foeForward) << "\n";
1725#endif
1726 if (foe->forwardRouteConflict(foeForward, *this, true)) {
1727#ifdef DEBUG_ADD_FOES
1728 std::cout << " foe " << foe->getID() << " reverses on edge=" << e->getID() << "\n";
1729#endif
1730 myFoes.push_back(foe);
1731 }
1732 } else if (movingBlock && foe == this) {
1733#ifdef DEBUG_ADD_FOES
1734 std::cout << " dw " << getID() << " reverses on forward edge=" << e->getID() << " (movingBlock)\n";
1735#endif
1736 myFoes.push_back(foe);
1737 }
1738 }
1739 }
1740 }
1741}
1742
1743
1744bool
1745MSDriveWay::buildSubFoe(MSDriveWay* foe, bool movingBlock) {
1746 // Subdriveways (Teilfahrstraße) model the resolution of a driving conflict
1747 // before a vehicle has left the driveway. This is possible when the driveway diverges from the foe
1748 // driveway at an earlier point (switch or crossing).
1749 //
1750 // We already know that the last edge of this driveway doesn't impact the foe (unless the driveway ends within the block).
1751 // Remove further edges from the end of the driveway (myForward) until the point of conflict is found.
1752 //
1753 // For movingBlock the logic is changed:
1754 // We remove the conflict-free part as before but then keep removing the conflict part until another non-conconflit part is found
1755 if (myForward.size() < foe->myForward.size() &&
1756 myForward == std::vector<const MSLane*>(foe->myForward.begin(), foe->myForward.begin() + myForward.size())) {
1757#ifdef DEBUG_BUILD_SUBDRIVEWAY
1758 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " is subpart of foe=" << foe->getID() << "\n";
1759#endif
1760 foe->myFoes.push_back(this);
1761 return true;
1762 }
1763 int subLast = (int)myForward.size() - 2;
1764 if (movingBlock && myForward.back() == foe->myForward.back()) {
1765 subLast++;
1766 }
1767#ifdef DEBUG_BUILD_SUBDRIVEWAY
1768 if (subLast < 0) {
1769 std::cout << " " << getID() << " cannot build subDriveWay for foe " << foe->getID() << " because myForward has only a single lane\n";
1770 }
1771#endif
1772 bool foundConflict = false;
1773 bool flankC = false;
1774 bool zipperC = false;
1775 bool crossC = false;
1776 while (subLast >= 0) {
1777 const MSLane* lane = myForward[subLast];
1778 const MSLink* tmpOrigin = subLast > 0 ? myForward[subLast - 1]->getLinkTo(lane) : myOrigin;
1779 MSDriveWay tmp(tmpOrigin, "tmp", true);
1780 tmp.myForward.push_back(lane);
1781 flankC = tmp.flankConflict(*foe);
1782 const bool bidiConflict = std::find(foe->myBidi.begin(), foe->myBidi.end(), lane) != foe->myBidi.end();
1783 crossC = tmp.crossingConflict(*foe);
1784#ifdef DEBUG_BUILD_SUBDRIVEWAY
1785 std::cout << " subLast=" << subLast << " lane=" << lane->getID() << " fc=" << flankC << " cc=" << crossC << " bc=" << bidiConflict << "\n";
1786#endif
1787 if (flankC || crossC || bidiConflict) {
1788 foundConflict = true;
1789 if (!movingBlock || bidiConflict) {
1790 break;
1791 }
1792 if (((flankC && lane->getFromJunction()->getType() == SumoXMLNodeType::ZIPPER)
1793 || (!flankC && lane->getToJunction()->getType() == SumoXMLNodeType::ZIPPER))
1794 && (isDepartDriveway()
1795 || getForwardDistance(flankC ? subLast - 1 : subLast) > myMovingBlockMaxDist)) {
1796 zipperC = true;
1797 foundConflict = false;
1798#ifdef DEBUG_BUILD_SUBDRIVEWAY
1799 std::cout << " ignored movingBlock zipperConflict\n";
1800#endif
1801 if (!flankC && crossC) {
1802#ifdef DEBUG_BUILD_SUBDRIVEWAY
1803 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
1804#endif
1805 return false;
1806 }
1807 }
1808 if (!flankC && crossC) {
1809 break;
1810 }
1811 } else if (foundConflict) {
1812 break;
1813 }
1814 subLast--;
1815 }
1816#ifdef DEBUG_BUILD_SUBDRIVEWAY
1817 std::cout << " subLastFina=" << subLast << " movingBlock=" << movingBlock << " zipperC=" << zipperC << "\n";
1818#endif
1819 if (subLast < 0) {
1820 if (movingBlock && zipperC) {
1821#ifdef DEBUG_BUILD_SUBDRIVEWAY
1822 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
1823#endif
1824 return false;
1825 } else if (&myForward.back()->getEdge() == myRoute.back() && foe->forwardEndOnRoute(this)) {
1826 // driveway ends in the middle of the block and only the final edge overlaps with the foe driveWay
1827 foe->myFoes.push_back(this);
1828#ifdef DEBUG_BUILD_SUBDRIVEWAY
1829 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " foe endsOnForward\n";
1830#endif
1831 } else if (foe->myTerminateRoute) {
1832 if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
1833 foe->myFoes.push_back(this);
1834 // foe will get the sidings
1835 addSidings(foe, true);
1836 }
1837#ifdef DEBUG_BUILD_SUBDRIVEWAY
1838 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " terminates\n";
1839#endif
1840 } else if (myTerminateRoute && myBidi.size() <= myForward.size()) {
1841 foe->myFoes.push_back(this);
1842#ifdef DEBUG_BUILD_SUBDRIVEWAY
1843 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " terminates, foe=" << foe->getID() << "\n";
1844#endif
1845 return true;
1846 } else if (foe->myReversals.size() % 2 == 1) {
1847#ifdef DEBUG_BUILD_SUBDRIVEWAY
1848 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " has " << foe->myReversals.size() << " reversals\n";
1849#endif
1850 } else {
1851#ifdef DEBUG_BUILD_SUBDRIVEWAY
1852 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " failed\n";
1853#endif
1854#ifdef SUBDRIVEWAY_WARN_NOCONFLICT
1855 WRITE_WARNINGF("No point of conflict found between driveway '%' and driveway '%' when creating sub-driveway", getID(), foe->getID());
1856#endif
1857 }
1858 return false;
1859 }
1860 int subSize = subLast + 1;
1861 for (MSDriveWay* cand : mySubDriveWays) {
1862 if ((int)cand->myForward.size() == subSize) {
1863 // can re-use existing sub-driveway
1864 foe->myFoes.push_back(cand);
1865 cand->myFoes.push_back(foe);
1866#ifdef DEBUG_BUILD_SUBDRIVEWAY
1867 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " useExisting=" << cand->getID() << "\n";
1868#endif
1869 return true;
1870 }
1871 }
1872 std::vector<const MSLane*> forward(myForward.begin(), myForward.begin() + subSize);
1873 std::vector<const MSEdge*> route;
1874 for (const MSLane* lane : forward) {
1875 if (lane->isNormal()) {
1876 route.push_back(&lane->getEdge());
1877 }
1878 }
1879 if (route.empty()) {
1880 if (subSize == 1 && crossC
1881 && forward.front()->getFromJunction() == foe->myForward.front()->getFromJunction()
1882 && forward.front()->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1883 assert(myForward.front()->isInternal());
1884 // sub-driveway ends after a single internal lane but since the route cannot be empty we add the next edge
1885 route.push_back(foe->myForward.front()->getEdge().getNormalSuccessor());
1886 } else {
1887#ifdef DEBUG_BUILD_SUBDRIVEWAY
1888 std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID() << " empty subRoute\n";
1889#endif
1890 return false;
1891 }
1892 }
1893 if (myRoute.size() > route.size()) {
1894 // route continues. make sure the subDriveway does not end with a reversal
1895 const MSEdge* lastNormal = route.back();
1896 const MSEdge* nextNormal = myRoute[route.size()];
1897 if (lastNormal->getBidiEdge() == nextNormal) {
1898#ifdef DEBUG_BUILD_SUBDRIVEWAY
1899 std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID()
1900 << " lastNormal=" << lastNormal->getID() << " nextNormal=" << nextNormal->getID() << " endWithReversal\n";
1901#endif
1902 return false;
1903 }
1904 }
1905 MSDriveWay* sub = new MSDriveWay(myOrigin, getID() + "." + toString(mySubDriveWays.size()));
1906 sub->myLane = myLane;
1907 sub->myIsSubDriveway = true;
1908 sub->myForward = forward;
1909 sub->myRoute = route;
1910 sub->myCoreSize = (int)sub->myRoute.size();
1911 myLane->addMoveReminder(sub, false);
1912
1913 // copy trains that are currently on this driveway (and associated entry events)
1914 for (SUMOVehicle* veh : myTrains) {
1915 auto itOnSub = std::find(sub->myRoute.begin(), sub->myRoute.end(), veh->getEdge());
1916 if (itOnSub != sub->myRoute.end()) {
1917 sub->myTrains.insert(veh);
1918 // non-zero is enough to avoid superfluous activation via activateReminders (and removal)
1919 const double pos = sub->myRoute.front()->getLength();
1920 dynamic_cast<MSBaseVehicle*>(veh)->addReminder(sub, pos);
1921 for (const VehicleEvent& ve : myVehicleEvents) {
1922 if (ve.id == veh->getID()) {
1923 sub->myVehicleEvents.push_back(ve);
1924 }
1925 }
1926 }
1927 }
1928
1929 foe->myFoes.push_back(sub);
1930 sub->myFoes.push_back(foe);
1931 mySubDriveWays.push_back(sub);
1932#ifdef DEBUG_BUILD_SUBDRIVEWAY
1933 std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " sub=" << sub->getID() << " route=" << toString(sub->myRoute) << "\n";
1934#endif
1935 return true;
1936}
1937
1938
1939double
1941 assert(lastIndex < (int)myForward.size());
1942 double result = 0;
1943 for (int i = 0; i <= lastIndex; i++) {
1944 result += myForward[i]->getLength();
1945 }
1946 return result;
1947}
1948
1949
1950void
1952 const MSEdge* foeEndBidi = foe->myForward.back()->getEdge().getBidiEdge();
1953 int forwardNormals = 0;
1954 for (auto lane : foe->myForward) {
1955 if (lane->isNormal()) {
1956 forwardNormals++;
1957 }
1958 }
1959 if (forwardNormals == (int)foe->myRoute.size()) {
1960#ifdef DEBUG_BUILD_SIDINGS
1961 std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " forwardNormals=" << forwardNormals << " frSize=" << foe->myRoute.size() << " aborted\n";
1962#endif
1963 return;
1964 }
1965 auto foeSearchBeg = foe->myRoute.begin() + forwardNormals;
1966 auto foeSearchEnd = foe->myRoute.end();
1967 if (foeEndBidi == nullptr) {
1968 throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " noBidi\n");
1969 }
1970 int i;
1971 std::vector<int> start;
1972 std::vector<double> length;
1973 for (i = 0; i < (int)myRoute.size(); i++) {
1974 if (myRoute[i] == foeEndBidi) {
1975 break;
1976 }
1977 }
1978 if (i == (int)myRoute.size()) {
1979 throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " foeEndBidi=" + foeEndBidi->getID() + " not on route\n");
1980 }
1981 const MSEdge* next = myRoute[i];
1982#ifdef DEBUG_BUILD_SIDINGS
1983 std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " next=" << next->getID() << " forwardNormals=" << forwardNormals << " frSize=" << foe->myRoute.size() << " foeSearchBeg=" << (*foeSearchBeg)->getID() << "\n";
1984#endif
1985 i--;
1986 for (; i >= 0; i--) {
1987 const MSEdge* cur = myRoute[i];
1988 if (hasRS(cur, next)) {
1989 if (std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge()) == foeSearchEnd) {
1990 start.push_back(i);
1991 length.push_back(0);
1992 }
1993 }
1994 if (!start.empty()) {
1995 auto itFind = std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge());
1996 if (itFind != foeSearchEnd) {
1997#ifdef DEBUG_BUILD_SIDINGS
1998 std::cout << "endSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " curBidi=" << Named::getIDSecure(cur->getBidiEdge()) << " length=" << toString(length) << "\n";
1999#endif
2000 const int firstIndex = i + 1;
2001 if (addToFoe) {
2002 auto& foeSidings = foe->mySidings[this];
2003 // indices must be mapped onto foe route;
2004 const MSEdge* first = myRoute[firstIndex];
2005 auto itFirst = std::find(foe->myRoute.begin(), foe->myRoute.end(), first);
2006 if (itFirst != foe->myRoute.end()) {
2007 for (int j = 0; j < (int)length.size(); j++) {
2008 const MSEdge* last = myRoute[start[j]];
2009 auto itLast = std::find(itFirst, foe->myRoute.end(), last);
2010 if (itLast != foe->myRoute.end()) {
2011 foeSidings.insert(foeSidings.begin(), Siding((int)(itFirst - foe->myRoute.begin()), (int)(itLast - foe->myRoute.begin()), length[j]));
2012 }
2013 }
2014 }
2015 } else {
2016 auto& foeSidings = mySidings[foe];
2017 for (int j = 0; j < (int)length.size(); j++) {
2018 foeSidings.insert(foeSidings.begin(), Siding(firstIndex, start[j], length[j]));
2019 }
2020 }
2021 start.clear();
2022 length.clear();
2023 foeSearchBeg = itFind;
2024 } else {
2025 for (int j = 0; j < (int)length.size(); j++) {
2026 length[j] += cur->getLength();
2027 }
2028 }
2029 }
2030 next = cur;
2031 }
2032}
2033
2034
2035bool
2036MSDriveWay::hasRS(const MSEdge* cur, const MSEdge* next) {
2038 // check if there is a controlled link between cur and next
2039 for (auto lane : cur->getLanes()) {
2040 for (const MSLink* link : lane->getLinkCont()) {
2041 if (&link->getLane()->getEdge() == next && link->getTLLogic() != nullptr) {
2042 return true;
2043 }
2044 }
2045 }
2046 }
2047 return false;
2048}
2049
2050
2051bool
2053 const MSEdge* foeForwardEnd = &foe->myForward.back()->getNormalPredecessorLane()->getEdge();
2054 return std::find(myRoute.begin(), myRoute.end(), foeForwardEnd) != myRoute.end();
2055}
2056
2057void
2059 if (link->getTLLogic() != nullptr) {
2060 // ignore links that originate on myBidi
2061 // and also links from the same junction as my own link
2062 const MSLane* origin = link->getLaneBefore();
2063 if (std::find(myBidi.begin(), myBidi.end(), origin) == myBidi.end()) {
2064 if (link->getJunction() != myRoute.front()->getFromJunction()) {
2065 if (std::find(myConflictLinks.begin(), myConflictLinks.end(), link) == myConflictLinks.end()) {
2066 myConflictLinks.push_back(const_cast<MSLink*>(link));
2067 }
2068 }
2069 }
2070 }
2071}
2072
2073void
2074MSDriveWay::addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes) {
2075 std::set<const MSDriveWay*> filtered;
2076 for (const MSDriveWay* foe : deadlockFoes) {
2077 if (std::find(myFoes.begin(), myFoes.end(), foe) == myFoes.end()) {
2078 filtered.insert(foe);
2079 }
2080 }
2081 if (std::find(myDeadlocks.begin(), myDeadlocks.end(), filtered) == myDeadlocks.end()) {
2082 myDeadlocks.push_back(filtered);
2083 //std::cout << getID() << " deadlockFoes=" << toString(deadlockFoes) << "\n";
2084 }
2085}
2086
2087const MSDriveWay*
2089 const MSEdge* edge = init ? veh->getRoute().getEdges()[veh->getDepartEdge()] : veh->getEdge();
2090 assert(isRailwayOrShared(edge->getPermissions()));
2092 for (const MSLane* lane : edge->getLanes()) {
2093 for (auto ili : lane->getIncomingLanes()) {
2094 const MSLink* entry = ili.viaLink->getCorrespondingEntryLink();
2095 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(entry->getTLLogic());
2096 if (rs != nullptr) {
2097 const MSDriveWay* dw = &const_cast<MSRailSignal*>(rs)->retrieveDriveWayForVeh(entry->getTLIndex(), veh);
2098 if (&dw->myForward.front()->getEdge() == edge) {
2099 return dw;
2100 }
2101 }
2102 }
2103 }
2104 }
2105 for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2106 auto matchStart = init ? veh->getRoute().begin() + veh->getDepartEdge() : veh->getCurrentRouteEdge();
2107 if (dw->match(matchStart, veh->getRoute().end())) {
2108 return dw;
2109 }
2110 }
2111 const std::string id = edge->getFromJunction()->getID() + ".d" + toString(myDepartDrivewayIndex[edge->getFromJunction()]++);
2112 MSDriveWay* dw = buildDriveWay(id, nullptr, veh->getCurrentRouteEdge(), veh->getRoute().end());
2113 myDepartureDriveways[edge].push_back(dw);
2114 myDepartureDrivewaysEnds[&dw->myForward.back()->getEdge()].push_back(dw);
2115 dw->setVehicle(veh->getID());
2116 return dw;
2117}
2118
2119
2120void
2122 for (auto item : myDepartureDriveways) {
2123 const MSEdge* edge = item.first;
2124 if (item.second.size() > 0) {
2125 od.openTag("departJunction");
2127 for (const MSDriveWay* dw : item.second) {
2128 if (writeVehicles) {
2129 dw->writeBlockVehicles(od);
2130 } else {
2131 dw->writeBlocks(od);
2132 }
2133 }
2134 od.closeTag(); // departJunction
2135 }
2136 }
2137}
2138
2139void
2141 // all driveways are in myEndingDriveways which makes it convenient
2142 for (auto item : myEndingDriveways) {
2143 for (MSDriveWay* dw : item.second) {
2144 dw->_saveState(out);
2145 for (MSDriveWay* sub : dw->mySubDriveWays) {
2146 sub->_saveState(out);
2147 }
2148 }
2149 }
2150}
2151
2152void
2154 if (!myTrains.empty() || haveSubTrains()) {
2158 if (!myTrains.empty()) {
2159 std::vector<std::string> trainIDs;
2160 for (SUMOVehicle* veh : myTrains) {
2161 trainIDs.push_back(veh->getID());
2162 }
2163 out.writeAttr(SUMO_ATTR_VEHICLES, toString(trainIDs));
2164 }
2165 out.closeTag();
2166 }
2167}
2168
2169
2170bool
2172 for (MSDriveWay* sub : mySubDriveWays) {
2173 if (!sub->myTrains.empty()) {
2174 return true;
2175 }
2176 }
2177 return false;
2178}
2179
2180void
2182 if ((int)myDriveWayRouteLookup.size() < myGlobalDriveWayIndex) {
2183 for (auto item : myEndingDriveways) {
2184 for (MSDriveWay* dw : item.second) {
2185 myDriveWayRouteLookup[dw->myRoute] = dw;
2186 }
2187 }
2188 }
2190 bool ok;
2191 const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
2192 const std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), ok);
2193 ConstMSEdgeVector route;
2194 if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
2195 MSEdge::parseEdgesList(edges, route, id);
2196 }
2197 MSDriveWay* dw = nullptr;
2198 if (tag == SUMO_TAG_DRIVEWAY) {
2199 auto it = myDriveWayRouteLookup.find(route);
2200 if (it == myDriveWayRouteLookup.end()) {
2201 //WRITE_WARNING(TLF("Unknown driveWay '%' with route '%'", id, edges));
2202 //return;
2203 throw ProcessError(TLF("Unknown driveWay '%' with route '%'", id, edges));
2204 }
2205 dw = it->second;
2206 myDriveWayLookup[id] = dw;
2207 } else {
2208 std::string parentID = id.substr(0, id.rfind('.'));
2209 auto it = myDriveWayLookup.find(parentID);
2210 if (it == myDriveWayLookup.end()) {
2211 //WRITE_WARNING(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2212 //return;
2213 throw ProcessError(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2214 }
2215 MSDriveWay* parent = it->second;
2216 for (MSDriveWay* sub : parent->mySubDriveWays) {
2217 if (sub->myRoute == route) {
2218 dw = sub;
2219 break;
2220 }
2221 }
2222 if (dw == nullptr) {
2223 // missing subdriveways can be ignored. They may have been created
2224 // as foes for driveways that are not relevant at state loading time
2225 return;
2226 }
2227 }
2228 const std::string vehicles = attrs.getOpt<std::string>(SUMO_ATTR_VEHICLES, id.c_str(), ok, "");
2229 for (const std::string& vehID : StringTokenizer(vehicles).getVector()) {
2230 MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(c.getVehicle(vehID));
2231 if (veh == nullptr) {
2232 throw ProcessError(TLF("Unknown vehicle '%' in driveway '%'", vehID, id));
2233 }
2234 if (!dw->hasTrain(veh)) {
2235 dw->myTrains.insert(veh);
2236 veh->addReminder(dw);
2237 }
2238 }
2239}
2240
2241const MSDriveWay*
2242MSDriveWay::retrieveDepartDriveWay(const MSEdge* edge, const std::string& id) {
2243 for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2244 if (dw->getID() == id) {
2245 return dw;
2246 }
2247 }
2248 return nullptr;
2249}
2250
2251
2252bool
2254 return myTrains.count(veh) != 0;
2255}
2256
2257/****************************************************************************/
#define DEBUG_HELPER(obj)
#define DEBUG_COND_DW(obj)
#define DEBUG_COND_DW2
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
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:91
#define SIMSTEP
Definition SUMOTime.h:64
#define SIMTIME
Definition SUMOTime.h:65
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:46
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:332
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:305
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
Definition ToString.h:313
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition MELoop.cpp:330
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:293
void addFoes(const MSLink *link)
add all driveWays that start at the given link as foes
std::vector< MSLink * > myConflictLinks
Definition MSDriveWay.h:252
const SUMOVehicle * myActive
whether the current signal is switched green for a train approaching this block
Definition MSDriveWay.h:208
bool crossingConflict(const MSDriveWay &other) const
Wether 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
bool myIsSubDriveway
Definition MSDriveWay.h:227
std::vector< MSDriveWay * > mySubDriveWays
Definition MSDriveWay.h:370
std::vector< std::set< const MSDriveWay * > > myDeadlocks
Definition MSDriveWay.h:365
bool myAbortedBuild
whether driveway building was aborted due to MAX_BLOCK_LENGTH
Definition MSDriveWay.h:224
bool buildSubFoe(MSDriveWay *foe, bool movingBlock)
std::set< SUMOVehicle *, ComparatorNumericalIdLess > myTrains
Definition MSDriveWay.h:360
static std::map< const MSJunction *, int > myDepartDrivewayIndex
Definition MSDriveWay.h:391
static bool hasJoin(const SUMOVehicle *ego, const SUMOVehicle *foe)
bool isDepartDriveway() const
Definition MSDriveWay.h:159
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:205
bool myTerminateRoute
Definition MSDriveWay.h:222
static double myMovingBlockMaxDist
Definition MSDriveWay.h:380
std::vector< const MSLane * > myBidi
Definition MSDriveWay.h:236
static bool myWriteVehicles
Definition MSDriveWay.h:379
void checkCrossingFlanks(MSLink *dwLink, const LaneVisitedMap &visited, std::set< MSLink * > &flankSwitches) const
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...
void findFlankProtection(MSLink *link, MSLink *origLink, std::vector< const MSLane * > &flank)
std::vector< const MSLane * > myBidiExtended
Definition MSDriveWay.h:240
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)
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.
std::vector< const MSLane * > myForward
Definition MSDriveWay.h:231
std::vector< const MSEdge * > myReversals
track own occurences in myReversalDriveWays for cleanup in destructor
Definition MSDriveWay.h:373
std::map< const MSDriveWay *, std::vector< Siding >, ComparatorIdLess > mySidings
Definition MSDriveWay.h:364
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
Wether this driveway (route) overlaps with the given one.
void buildRoute(const MSLink *origin, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap &visited, std::set< MSLink * > &)
std::vector< const MSLane * > myFlank
Definition MSDriveWay.h:244
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:211
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:399
static std::set< const MSEdge * > myBlockLengthWarnings
Definition MSDriveWay.h:381
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:387
static void init()
void _saveState(OutputDevice &out) const
static std::string formatVisitedMap(const LaneVisitedMap &visited)
print link descriptions
static std::map< std::string, MSDriveWay * > myDriveWayLookup
Definition MSDriveWay.h:400
int matchesPastRoute(SUMOVehicle &sveh) const
bool flankConflict(const MSDriveWay &other) const
Wether 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:393
int myCoreSize
number of edges in myRoute where overlap with other driveways is forbidden
Definition MSDriveWay.h:214
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:376
bool forwardEndOnRoute(const MSDriveWay *foe) const
bool myFoundJump
Definition MSDriveWay.h:221
void checkFlanks(const MSLink *originLink, const std::vector< const MSLane * > &lanes, const LaneVisitedMap &visited, bool allFoes, bool movingBlock, std::set< MSLink * > &flankSwitches) const
static void saveState(OutputDevice &out)
Save driveway occupancy into the given stream.
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:390
void setVehicle(const std::string &vehID)
Definition MSDriveWay.h:142
bool myBidiEnded
whether driveway building was aborted when no further bidi edge was found
Definition MSDriveWay.h:226
static bool mustYield(const Approaching &veh, const Approaching &foe)
Whether veh must yield to the foe train.
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
Wether there is a bidi conflict with the end of the given driveway.
static int myGlobalDriveWayIndex
Definition MSDriveWay.h:378
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:220
static std::map< const MSLink *, std::vector< MSDriveWay * > > mySwitchDriveWays
all driveways passing the given switch (used to look up flank foes)
Definition MSDriveWay.h:384
bool isFoeOrSubFoe(const MSDriveWay *foe) const
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:217
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:396
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)
Wether the route of other passes into the forward section of this driveway.
std::pair< bool, const MSDriveWay * > canUseSiding(const SUMOVehicle *ego, const MSDriveWay *foe, bool recurse=true) const
return whether a siding can be used. If a siding exist but is occupied, also return the occupied driv...
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
Definition MSDriveWay.h:247
static const MSDriveWay * getDepartureDriveway(const SUMOVehicle *veh, bool init=false)
std::vector< MSDriveWay * > myFoes
Definition MSDriveWay.h:363
std::vector< VehicleEvent > myVehicleEvents
Definition MSDriveWay.h:362
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
Wether there is a bidi conflict with the given driveway.
bool reserve(const Approaching &closest, MSEdgeVector &occupied)
attempt reserve this driveway for the given vehicle
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)
A road/street connecting two junctions.
Definition MSEdge.h:77
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition MSEdge.h:658
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
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:1138
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:283
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:264
const MSJunction * getToJunction() const
Definition MSEdge.h:427
double getLength() const
return the length of the edge
Definition MSEdge.h:694
const MSJunction * getFromJunction() const
Definition MSEdge.h:423
bool isConnectedTo(const MSEdge &destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions=false) const
Definition MSEdge.h:244
static bool gUseMesoSim
Definition MSGlobals.h:106
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition MSGlobals.h:112
static SUMOTime gTimeToTeleportRSDeadlock
Definition MSGlobals.h:72
static double gMaxRailSignalBlockLength
The maximum length of a rail signal block.
Definition MSGlobals.h:189
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
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2758
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2471
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:966
virtual void addMoveReminder(MSMoveReminder *rem, bool addToVehicles=true)
Add a move-reminder to move-reminder container.
Definition MSLane.cpp:359
const MSJunction * getToJunction() const
Definition MSLane.cpp:4742
double getLength() const
Returns the lane's length.
Definition MSLane.h:617
const MSJunction * getFromJunction() const
Definition MSLane.cpp:4736
int getIndex() const
Returns the lane's index.
Definition MSLane.h:653
bool isNormal() const
Definition MSLane.cpp:2632
bool isInternal() const
Definition MSLane.cpp:2626
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4691
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:775
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3253
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:735
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:187
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:392
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 isMovingBlock(SVCPermissions svc)
A signal for rails.
bool isMovingBlock() const
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.
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:54
std::string myID
The name of the object.
Definition Named.h:125
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:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
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 & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
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 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 int getRoutePosition() const =0
return index of edge within route
virtual const MSEdge * getEdge() const =0
Returns the 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 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:39