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