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