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