Line data Source code
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 : /****************************************************************************/
14 : /// @file MSDriveWay.cpp
15 : /// @author Jakob Erdmann
16 : /// @date December 2021
17 : ///
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 :
24 : #include <utils/xml/SUMOSAXAttributes.h>
25 : #include <utils/common/StringUtils.h>
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>
31 : #include <microsim/MSVehicleControl.h>
32 : #include <microsim/MSJunctionLogic.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 : // ===========================================================================
70 : int MSDriveWay::myGlobalDriveWayIndex(0);
71 : int MSDriveWay::myNumWarnings(0);
72 : bool MSDriveWay::myWriteVehicles(false);
73 : std::map<const MSLink*, std::vector<MSDriveWay*> > MSDriveWay::mySwitchDriveWays;
74 : std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myReversalDriveWays;
75 : std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myDepartureDriveways;
76 : std::map<const MSJunction*, int> MSDriveWay::myDepartDrivewayIndex;
77 : std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myDepartureDrivewaysEnds;
78 : std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myEndingDriveways;
79 : std::map<ConstMSEdgeVector, MSDriveWay*> MSDriveWay::myDriveWayRouteLookup;
80 : std::map<std::string, MSDriveWay*> MSDriveWay::myDriveWayLookup;
81 :
82 : // ---------------------------------------------------------------------------
83 : // static initialisation methods
84 : // ---------------------------------------------------------------------------
85 : void
86 42995 : MSDriveWay::init() {
87 42995 : myWriteVehicles = OptionsCont::getOptions().isSet("railsignal-vehicle-output");
88 42995 : }
89 :
90 : // ===========================================================================
91 : // MSDriveWay method definitions
92 : // ===========================================================================
93 :
94 :
95 15661 : MSDriveWay::MSDriveWay(const MSLink* origin, const std::string& id, bool temporary) :
96 31322 : MSMoveReminder("DriveWay_" + (temporary ? "tmp" : id)),
97 : Named(id),
98 7606 : myNumericalID(temporary ? -1 : myGlobalDriveWayIndex++),
99 15661 : myOrigin(origin),
100 15661 : myMaxFlankLength(0),
101 15661 : myActive(nullptr),
102 15661 : myCoreSize(0),
103 15661 : myFoundSignal(false),
104 15661 : myFoundJump(false),
105 15661 : myTerminateRoute(false),
106 15661 : myAbortedBuild(false),
107 15661 : myBidiEnded(false),
108 54589 : myIsSubDriveway(false)
109 15661 : {}
110 :
111 :
112 23267 : MSDriveWay::~MSDriveWay() {
113 17333 : for (const MSDriveWay* sub : mySubDriveWays) {
114 1672 : delete sub;
115 : }
116 : mySubDriveWays.clear();
117 70250 : }
118 :
119 : void
120 40275 : MSDriveWay::cleanup() {
121 40275 : myGlobalDriveWayIndex = 0;
122 40275 : myNumWarnings = 0;
123 40275 : myWriteVehicles = false;
124 :
125 42763 : for (auto item : myDepartureDriveways) {
126 5079 : for (MSDriveWay* dw : item.second) {
127 2591 : delete dw;
128 : }
129 : }
130 : MSDriveWay::mySwitchDriveWays.clear();
131 : MSDriveWay::myReversalDriveWays.clear();
132 : MSDriveWay::myDepartureDriveways.clear();
133 : MSDriveWay::myDepartDrivewayIndex.clear();
134 : MSDriveWay::myDepartureDrivewaysEnds.clear();
135 : MSDriveWay::myEndingDriveways.clear();
136 40275 : }
137 :
138 : void
139 177 : MSDriveWay::clearState() {
140 202 : for (auto item : myEndingDriveways) {
141 50 : for (MSDriveWay* dw : item.second) {
142 : dw->myTrains.clear();
143 : }
144 : }
145 177 : }
146 :
147 :
148 : bool
149 19165 : MSDriveWay::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
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 38330 : if (veh.isVehicle() && (enteredLane == myLane || (MSGlobals::gUseMesoSim && veh.getEdge() == &myLane->getEdge()))
156 38330 : && (reason == NOTIFICATION_DEPARTED || reason == NOTIFICATION_JUNCTION || reason == NOTIFICATION_PARKING)) {
157 19110 : SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
158 19110 : MSRouteIterator firstIt = std::find(sveh.getCurrentRouteEdge(), sveh.getRoute().end(), myLane->getNextNormal());
159 19104 : if (myTrains.count(&sveh) == 0 && match(firstIt, sveh.getRoute().end())) {
160 16338 : myTrains.insert(&sveh);
161 16338 : if (myOrigin != nullptr) {
162 10986 : MSRailSignalControl::getInstance().notifyApproach(myOrigin);
163 : }
164 43564 : for (const MSDriveWay* foe : myFoes) {
165 27226 : if (foe->myOrigin != nullptr) {
166 19663 : MSRailSignalControl::getInstance().notifyApproach(foe->myOrigin);
167 : }
168 : }
169 16338 : if (myWriteVehicles) {
170 1390 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, true, veh.getID(), reason));
171 : }
172 16338 : return true;
173 : }
174 : }
175 : return false;
176 : }
177 :
178 :
179 : bool
180 78215 : MSDriveWay::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 78215 : if (veh.isVehicle()) {
187 : // leaving network with departure, teleport etc
188 78215 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
189 5128 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
190 5128 : if (myWriteVehicles) {
191 372 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
192 : }
193 5128 : return false;
194 73087 : } else if (MSGlobals::gUseMesoSim && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
195 : // notifyLeave is called before moving the route iterator
196 6010 : const MSLane* leftLane = (*(dynamic_cast<SUMOVehicle&>(veh).getCurrentRouteEdge()))->getLanes().front();
197 6010 : return notifyLeaveBack(veh, reason, leftLane);
198 : } else {
199 : return true;
200 : }
201 : } else {
202 : return false;
203 : }
204 : }
205 :
206 :
207 : bool
208 59531 : MSDriveWay::notifyLeaveBack(SUMOTrafficObject& veh, Notification reason, const MSLane* leftLane) {
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 59531 : if (veh.isVehicle()) {
215 59531 : if (leftLane == myForward.back() && (veh.getBackLane() != leftLane->getBidiLane() || MSGlobals::gUseMesoSim)) {
216 11332 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
217 11332 : if (myWriteVehicles) {
218 1018 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
219 : }
220 11332 : return false;
221 : } else {
222 48199 : return true;
223 : }
224 : } else {
225 : return false;
226 : }
227 : }
228 :
229 :
230 : bool
231 447371 : MSDriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
232 447371 : if (foeDriveWayOccupied(true, closest.first, occupied)) {
233 : return false;
234 : }
235 398225 : for (MSLink* foeLink : myConflictLinks) {
236 114925 : 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 283300 : myActive = closest.first;
246 283300 : return true;
247 : }
248 :
249 :
250 : bool
251 114925 : MSDriveWay::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 114925 : if (foeLink->getApproaching().size() > 0) {
258 38612 : 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 38612 : if (foe.first == veh.first) {
265 38612 : return false;
266 : }
267 : const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
268 : assert(foeTLL != nullptr);
269 34305 : const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
270 : MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
271 34305 : if (foeRS != nullptr) {
272 34305 : const MSDriveWay& foeDriveWay = foeRS->retrieveDriveWayForVeh(foeLink->getTLIndex(), foe.first);
273 : MSEdgeVector occupied;
274 53858 : if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied) ||
275 32148 : !foeRS->constraintsAllow(foe.first) ||
276 24620 : !overlap(foeDriveWay) ||
277 46330 : !isFoeOrSubFoe(&foeDriveWay) ||
278 9789 : 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 24607 : 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 9698 : const bool yield = mustYield(veh, foe);
309 9698 : if (MSRailSignal::storeVehicles()) {
310 540 : MSRailSignal::rivalVehicles().push_back(foe.first);
311 540 : if (yield) {
312 315 : MSRailSignal::priorityVehicles().push_back(foe.first);
313 : }
314 : }
315 9698 : return yield;
316 34305 : }
317 : }
318 : return false;
319 : }
320 :
321 :
322 : bool
323 21071 : MSDriveWay::isFoeOrSubFoe(const MSDriveWay* foe) const {
324 21071 : if (std::find(myFoes.begin(), myFoes.end(), foe) != myFoes.end()) {
325 : return true;
326 : }
327 15083 : for (const MSDriveWay* sub : foe->mySubDriveWays) {
328 9046 : if (isFoeOrSubFoe(sub)) {
329 : return true;
330 : }
331 : }
332 : return false;
333 : }
334 :
335 :
336 : bool
337 9698 : MSDriveWay::mustYield(const Approaching& veh, const Approaching& foe) {
338 9698 : if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
339 5428 : if (foe.second.arrivalTime == veh.second.arrivalTime) {
340 540 : if (foe.first->getSpeed() == veh.first->getSpeed()) {
341 522 : if (foe.second.dist == veh.second.dist) {
342 490 : if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
343 472 : return foe.first->getNumericalID() < veh.first->getNumericalID();
344 : } else {
345 18 : return foe.first->getWaitingTime() > veh.first->getWaitingTime();
346 : }
347 : } else {
348 32 : return foe.second.dist < veh.second.dist;
349 : }
350 : } else {
351 18 : return foe.first->getSpeed() > veh.first->getSpeed();
352 : }
353 : } else {
354 4888 : return foe.second.arrivalTime < veh.second.arrivalTime;
355 : }
356 : } else {
357 4270 : return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
358 : }
359 : }
360 :
361 :
362 : bool
363 16035 : MSDriveWay::conflictLaneOccupied(bool store, const SUMOVehicle* ego) const {
364 204411 : for (const MSLane* lane : myConflictLanes) {
365 : if (!lane->isEmpty()) {
366 4410 : std::string joinVehicle = "";
367 4410 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
368 0 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
369 0 : if (stop != nullptr) {
370 0 : 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 4410 : if (lane->getVehicleNumberWithPartials() == 1) {
383 4410 : MSVehicle* foe = lane->getLastAnyVehicle();
384 4410 : if (joinVehicle != "") {
385 0 : 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 0 : continue;
392 : }
393 : }
394 4410 : if (ego != nullptr) {
395 0 : 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 0 : continue;
402 : }
403 0 : 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 0 : continue;
410 : }
411 : }
412 : }
413 4410 : if (MSRailSignal::storeVehicles() && store) {
414 4410 : MSRailSignal::blockingVehicles().push_back(lane->getLastAnyVehicle());
415 : }
416 : return true;
417 : }
418 : }
419 11625 : return false;
420 : }
421 :
422 :
423 : bool
424 7782671 : MSDriveWay::foeDriveWayApproached() const {
425 15642969 : for (const MSDriveWay* foeDW : myFoes) {
426 15584675 : 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 :
439 : bool
440 8714008 : MSDriveWay::foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const {
441 25375418 : for (const MSDriveWay* foeDW : myFoes) {
442 17290485 : 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 651060 : if (foeDW->myTrains.size() == 1) {
449 650814 : SUMOVehicle* foe = *foeDW->myTrains.begin();
450 650814 : 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 22085 : continue;
457 : }
458 631942 : if (hasJoin(ego, foe)) {
459 36 : continue;
460 : }
461 : }
462 632152 : 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 632152 : if (useSiding.first) {
474 3177 : continue;
475 : } else {
476 628975 : if (MSRailSignal::storeVehicles() && store) {
477 740 : for (SUMOVehicle* foe : foeDW->myTrains) {
478 370 : MSRailSignal::blockingVehicles().push_back(foe);
479 : }
480 370 : MSRailSignal::blockingDriveWays().push_back(foeDW);
481 : }
482 1258428 : for (const SUMOVehicle* foe : foeDW->myTrains) {
483 629453 : occupied.push_back(const_cast<MSEdge*>(foe->getEdge()));
484 629453 : MSEdge* bidi = const_cast<MSEdge*>(foe->getEdge()->getBidiEdge());
485 629453 : if (bidi != nullptr) {
486 457619 : occupied.push_back(bidi);
487 : }
488 : /// @todo: if foe occupies more than one edge we should add all of them to the occupied vector
489 : }
490 211149 : if (ego != nullptr && MSGlobals::gTimeToTeleportRSDeadlock > 0
491 797488 : && (ego->getWaitingTime() > ego->getVehicleType().getCarFollowModel().getStartupDelay() || !ego->isOnRoad())) {
492 : // if there is an occupied siding, it becomes part of the waitRelation
493 87432 : SUMOVehicle* foe = *(useSiding.second == nullptr ? foeDW : useSiding.second)->myTrains.begin();
494 87432 : const MSRailSignal* rs = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
495 87432 : MSRailSignalControl::getInstance().addWaitRelation(ego, rs, foe);
496 : }
497 628975 : return true;
498 : }
499 16639425 : } else if (foeDW != this && isDepartDriveway() && !foeDW->isDepartDriveway()) {
500 8741 : if (foeDW->myOrigin->getApproaching().size() > 0) {
501 1416 : Approaching foeA = foeDW->myOrigin->getClosest();
502 1416 : const SUMOVehicle* foe = foeA.first;
503 1416 : if (foeA.second.dist < foe->getBrakeGap(true)) {
504 134 : MSRouteIterator firstIt = std::find(foe->getCurrentRouteEdge(), foe->getRoute().end(), foeDW->myRoute.front());
505 134 : if (firstIt != foe->getRoute().end()) {
506 134 : if (foeDW->match(firstIt, foe->getRoute().end())) {
507 100 : 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 100 : if (useSiding) {
514 : //std::cout << SIMTIME << " " << getID() << " ego=" << ego->getID() << " foeDW=" << foeDW->getID() << " myFoes=" << toString(myFoes) << "\n";
515 0 : continue;
516 : } else {
517 100 : return true;
518 : }
519 : }
520 : }
521 : }
522 : }
523 : }
524 : }
525 8085993 : for (const std::set<const MSDriveWay*>& dlFoes : myDeadlocks) {
526 : bool allOccupied = true;
527 10984 : for (const MSDriveWay* dlFoe : dlFoes) {
528 8292 : 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 3752 : 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 9148 : for (const MSDriveWay* dlFoe : dlFoes) {
541 6456 : MSRailSignal::blockingDriveWays().push_back(dlFoe);
542 : }
543 : return true;
544 : }
545 : }
546 : return false;
547 : }
548 :
549 :
550 : bool
551 631942 : MSDriveWay::hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe) {
552 631942 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
553 172690 : std::string joinVehicle = "";
554 172690 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
555 172690 : if (stop != nullptr) {
556 87278 : joinVehicle = stop->join;
557 : }
558 172690 : if (joinVehicle == "" && !ego->hasDeparted() && ego->getStops().size() > 1) {
559 : // check one more stop
560 5984 : auto it = ego->getStops().begin();
561 : std::advance(it, 1);
562 5984 : joinVehicle = it->pars.join;
563 : }
564 172690 : if (joinVehicle != "") {
565 : #ifdef DEBUG_SIGNALSTATE
566 : if (gDebugFlag4 || DEBUG_COND_DW) {
567 : std::cout << " joinVehicle=" << joinVehicle << "\n";
568 : }
569 : #endif
570 345 : 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 172666 : 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 :
593 : std::pair<bool, const MSDriveWay*>
594 645167 : MSDriveWay::canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse) const {
595 : auto it = mySidings.find(foe);
596 645167 : if (it != mySidings.end()) {
597 11726 : for (auto siding : it->second) {
598 : // assume siding is usuable when computing state for unapproached signal (ego == nullptr)
599 10934 : if (ego == nullptr || siding.length >= ego->getLength()) {
600 : // if the siding is already "reserved" by another vehicle we cannot use it here
601 7583 : const MSEdge* sidingEnd = myRoute[siding.end];
602 15272 : for (MSDriveWay* sidingApproach : myEndingDriveways[sidingEnd]) {
603 11794 : if (!sidingApproach->myTrains.empty()) {
604 : // possibly the foe vehicle can use the other part of the siding
605 4315 : if (recurse) {
606 : const SUMOVehicle* foeVeh = nullptr;
607 3126 : if (!foe->myTrains.empty()) {
608 3118 : foeVeh = *foe->myTrains.begin();
609 8 : } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
610 8 : foeVeh = foe->myOrigin->getClosest().first;
611 : }
612 3126 : if (foeVeh == nullptr) {
613 0 : WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
614 0 : continue;
615 : }
616 3126 : if (foe->canUseSiding(foeVeh, this, false).first) {
617 210 : 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 4105 : 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 3478 : return std::make_pair(true, nullptr);
636 : }
637 : }
638 : }
639 637584 : return std::make_pair(false, nullptr);
640 : }
641 :
642 : bool
643 15593 : MSDriveWay::overlap(const MSDriveWay& other) const {
644 35021 : for (int i = 0; i < myCoreSize; i++) {
645 141814 : for (int j = 0; j < other.myCoreSize; j++) {
646 122386 : const MSEdge* edge = myRoute[i];
647 122386 : const MSEdge* edge2 = other.myRoute[j];
648 : if (edge->getToJunction() == edge2->getToJunction()
649 122386 : || 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 :
659 : bool
660 19012 : MSDriveWay::flankConflict(const MSDriveWay& other) const {
661 48132 : for (const MSLane* lane : myForward) {
662 182734 : for (const MSLane* lane2 : other.myForward) {
663 149095 : if (lane == lane2) {
664 : return true;
665 : }
666 : }
667 283949 : for (const MSLane* lane2 : other.myBidi) {
668 252662 : if (lane == lane2) {
669 4403 : if (bidiBlockedBy(other)) {
670 : // it's only a deadlock if both trains block symmetrically
671 : return true;
672 : }
673 : }
674 : }
675 257845 : for (const MSLane* lane2 : other.myBidiExtended) {
676 228725 : if (lane == lane2) {
677 7583 : 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 :
688 : bool
689 12119 : MSDriveWay::crossingConflict(const MSDriveWay& other) const {
690 34627 : for (const MSLane* lane : myForward) {
691 116307 : for (const MSLane* lane2 : other.myForward) {
692 93799 : if (lane->isNormal() && lane2->isNormal() && lane->getEdge().getToJunction() == lane2->getEdge().getToJunction()) {
693 : return true;
694 : }
695 : }
696 : }
697 : return false;
698 : }
699 :
700 :
701 : bool
702 12258 : MSDriveWay::bidiBlockedBy(const MSDriveWay& other) const {
703 85416 : for (const MSLane* lane : myBidi) {
704 302144 : for (const MSLane* lane2 : other.myForward) {
705 228986 : if (lane == lane2) {
706 : return true;
707 : }
708 : }
709 : }
710 42023 : for (const MSLane* lane : myBidiExtended) {
711 145617 : for (const MSLane* lane2 : other.myForward) {
712 113092 : if (lane == lane2) {
713 1831 : if (overlap(other)) {
714 : return true;
715 : }
716 : }
717 : }
718 : }
719 : return false;
720 : }
721 :
722 :
723 : bool
724 6566 : MSDriveWay::bidiBlockedByEnd(const MSDriveWay& other) const {
725 6566 : const MSLane* end = other.myForward.back();
726 46019 : for (const MSLane* lane : myBidi) {
727 41958 : if (lane == end) {
728 : return true;
729 : }
730 : }
731 17592 : for (const MSLane* lane : myBidiExtended) {
732 14698 : if (lane == end) {
733 1167 : if (overlap(other)) {
734 : return true;
735 : }
736 : }
737 : }
738 : return false;
739 : }
740 :
741 : bool
742 1012 : MSDriveWay::forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck) {
743 : int i = 0;
744 4135 : for (const MSEdge* edge2 : other.myRoute) {
745 4057 : if (i == other.myCoreSize) {
746 : return false;
747 : }
748 4057 : i++;
749 4057 : 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 :
760 : void
761 5790 : MSDriveWay::writeBlocks(OutputDevice& od) const {
762 10029 : od.openTag(myIsSubDriveway ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
763 5790 : od.writeAttr(SUMO_ATTR_ID, myID);
764 5790 : od.writeAttr(SUMO_ATTR_VEHICLE, myFirstVehicle);
765 5790 : od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
766 5790 : if (myCoreSize != (int)myRoute.size()) {
767 0 : od.writeAttr("core", myCoreSize);
768 : }
769 5790 : od.openTag("forward");
770 5790 : od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
771 5790 : od.closeTag();
772 5790 : if (!myIsSubDriveway) {
773 4239 : od.openTag("bidi");
774 8478 : od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
775 4239 : if (myBidiExtended.size() > 0) {
776 1027 : od.lf();
777 1027 : od << " ";
778 2054 : od.writeAttr("deadlockCheck", toString(myBidiExtended));
779 : }
780 4239 : od.closeTag();
781 4239 : od.openTag("flank");
782 4239 : od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
783 4239 : od.closeTag();
784 :
785 8478 : od.openTag("conflictLinks");
786 :
787 : std::vector<std::string> signals;
788 7156 : for (MSLink* link : myConflictLinks) {
789 5834 : signals.push_back(getTLLinkID(link));
790 : }
791 8478 : od.writeAttr("signals", joinToStringSorting(signals, " "));
792 8478 : od.closeTag();
793 :
794 : std::vector<std::string> foes;
795 15349 : for (MSDriveWay* dw : myFoes) {
796 11110 : foes.push_back(dw->myID);
797 : }
798 4239 : if (foes.size() > 0) {
799 4215 : od.openTag("foes");
800 8430 : od.writeAttr("driveWays", joinToStringSorting(foes, " "));
801 8430 : od.closeTag();
802 : }
803 4614 : for (auto item : mySidings) {
804 375 : od.openTag("sidings");
805 750 : od.writeAttr("foe", item.first->getID());
806 903 : for (auto siding : item.second) {
807 528 : od.openTag("siding");
808 528 : od.writeAttr("start", myRoute[siding.start]->getID());
809 528 : od.writeAttr("end", myRoute[siding.end]->getID());
810 528 : od.writeAttr("length", siding.length);
811 1056 : od.closeTag();
812 : }
813 750 : od.closeTag();
814 : }
815 4320 : for (auto item : myDeadlocks) {
816 81 : od.openTag("deadlock");
817 162 : od.writeAttr("foes", joinNamedToStringSorting(item, " "));
818 162 : od.closeTag();
819 : }
820 4239 : }
821 11580 : od.closeTag(); // driveWay
822 :
823 7341 : for (const MSDriveWay* sub : mySubDriveWays) {
824 1551 : sub->writeBlocks(od);
825 : }
826 : #ifdef DRIVEWAY_SANITY_CHECK
827 5790 : std::set<MSDriveWay*> uFoes(myFoes.begin(), myFoes.end());
828 5790 : if (uFoes.size() != myFoes.size()) {
829 0 : WRITE_WARNINGF("Duplicate foes in driveway '%'", getID());
830 :
831 : }
832 : #endif
833 5790 : }
834 :
835 :
836 : void
837 550 : MSDriveWay::writeBlockVehicles(OutputDevice& od) const {
838 974 : od.openTag(myIsSubDriveway ? "subDriveWay" : "driveWay");
839 550 : od.writeAttr(SUMO_ATTR_ID, myID);
840 1940 : for (const VehicleEvent& ve : myVehicleEvents) {
841 2085 : od.openTag(ve.isEntry ? "entry" : "exit");
842 1390 : od.writeAttr(SUMO_ATTR_ID, ve.id);
843 1390 : od.writeAttr(SUMO_ATTR_TIME, time2string(ve.time));
844 1390 : od.writeAttr("reason", ve.reason);
845 2780 : od.closeTag(); // event
846 : }
847 1100 : od.closeTag(); // driveWay
848 :
849 676 : for (const MSDriveWay* sub : mySubDriveWays) {
850 126 : sub->writeBlockVehicles(od);
851 : }
852 550 : }
853 :
854 :
855 : void
856 5934 : MSDriveWay::buildRoute(const MSLink* origin, double length,
857 : MSRouteIterator next, MSRouteIterator end,
858 : LaneVisitedMap& visited,
859 : std::set<MSLink*>& flankSwitches) {
860 : bool seekForwardSignal = true;
861 : bool seekBidiSwitch = true;
862 : bool foundUnsafeSwitch = false;
863 5934 : MSLane* toLane = origin ? origin->getViaLaneOrLane() : (*next)->getLanes()[0];
864 11868 : const std::string warnID = origin ? "rail signal " + getClickableTLLinkID(origin) : "insertion lane '" + toLane->getID() + "'";
865 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
866 : gDebugFlag4 = DEBUG_COND_DW;
867 : if (gDebugFlag4) std::cout << "buildRoute origin=" << warnID << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
868 : << " visited=" << formatVisitedMap(visited) << "\n";
869 : #endif
870 38842 : while ((seekForwardSignal || seekBidiSwitch)) {
871 37020 : if (length > MAX_BLOCK_LENGTH) {
872 56 : if (myNumWarnings < MAX_SIGNAL_WARNINGS) {
873 224 : WRITE_WARNING("Block after " + warnID +
874 : " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
875 : }
876 56 : myNumWarnings++;
877 56 : myAbortedBuild = true;
878 : // length exceeded
879 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
880 : if (gDebugFlag4) {
881 : std::cout << " abort: length=" << length << "\n";
882 : }
883 : #endif
884 4112 : return;
885 : }
886 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
887 : if (gDebugFlag4) {
888 : std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
889 : }
890 : #endif
891 36964 : const MSEdge* current = &toLane->getEdge();
892 36964 : if (current->isNormal()) {
893 24205 : myRoute.push_back(current);
894 24205 : if (next != end) {
895 : next++;
896 : }
897 : }
898 36964 : appendMapIndex(visited, toLane);
899 36964 : length += toLane->getLength();
900 36964 : MSLane* bidi = toLane->getBidiLane();
901 36964 : if (seekForwardSignal) {
902 18180 : if (!foundUnsafeSwitch) {
903 18180 : myForward.push_back(toLane);
904 18180 : if (myForward.size() == 1) {
905 5934 : myLane = toLane;
906 5934 : if (MSGlobals::gUseMesoSim) {
907 1676 : MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(myLane->getEdge());
908 1676 : s->addDetector(this, myLane->getIndex());
909 : } else {
910 4258 : toLane->addMoveReminder(this);
911 : }
912 : }
913 : }
914 18784 : } else if (bidi == nullptr) {
915 729 : 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 36964 : if (bidi != nullptr) {
931 29394 : if (foundUnsafeSwitch) {
932 7873 : myBidiExtended.push_back(bidi);
933 : } else {
934 21521 : myBidi.push_back(bidi);
935 : }
936 29394 : if (!seekForwardSignal) {
937 : // look for switch that could protect from oncoming vehicles
938 37473 : for (const auto& ili : bidi->getIncomingLanes()) {
939 19418 : if (ili.viaLink->getDirection() == LinkDirection::TURN) {
940 1429 : continue;
941 : }
942 38957 : for (const MSLink* const link : ili.lane->getLinkCont()) {
943 20968 : if (link->getDirection() == LinkDirection::TURN) {
944 948 : continue;
945 : }
946 20020 : if (link->getViaLaneOrLane() != bidi) {
947 2031 : 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 4208 : for (const auto& ili2 : bidi->getIncomingLanes()) {
958 2177 : if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
959 2099 : flankSwitches.insert(ili.viaLink);
960 : }
961 : }
962 : }
963 : }
964 : }
965 : }
966 : }
967 : const std::vector<MSLink*>& links = toLane->getLinkCont();
968 36964 : toLane = nullptr;
969 40198 : for (const MSLink* const link : links) {
970 34761 : if ((next != end && &link->getLane()->getEdge() == *next)
971 69142 : && isRailway(link->getViaLaneOrLane()->getPermissions())) {
972 54314 : toLane = link->getViaLaneOrLane();
973 32908 : if (link->getTLLogic() != nullptr && link->getTLIndex() >= 0) {
974 6768 : if (link == origin) {
975 0 : 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 0 : myAbortedBuild = true;
978 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
979 : if (gDebugFlag4) {
980 : std::cout << " abort: found circle\n";
981 : }
982 : #endif
983 0 : return;
984 : }
985 : seekForwardSignal = false;
986 6768 : myFoundSignal = true;
987 6768 : 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 32908 : if (isSwitch(link)) {
996 : // switch on driveway
997 : //std::cout << "mySwitchDriveWays " << getID() << " link=" << link->getDescription() << "\n";
998 18836 : mySwitchDriveWays[link].push_back(this);
999 : }
1000 32908 : if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1001 : // reversal on driveway
1002 583 : myReversalDriveWays[current].push_back(this);
1003 583 : myReversals.push_back(current);
1004 : }
1005 : break;
1006 : }
1007 : }
1008 36964 : if (toLane == nullptr) {
1009 4056 : 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 128 : myFoundJump = true;
1018 128 : return;
1019 : } else {
1020 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1021 : if (gDebugFlag4) {
1022 : std::cout << " abort: no next lane available\n";
1023 : }
1024 : #endif
1025 3928 : myTerminateRoute = true;
1026 3928 : return;
1027 : }
1028 : }
1029 : }
1030 1822 : myBidiEnded = !seekBidiSwitch;
1031 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1032 : if (gDebugFlag4) {
1033 : std::cout << " normalEnd myBidiEnded=" << myBidiEnded << "\n";
1034 : }
1035 : #endif
1036 : }
1037 :
1038 :
1039 : bool
1040 39806 : MSDriveWay::isSwitch(const MSLink* link) {
1041 76839 : for (const MSLink* other : link->getLaneBefore()->getNormalPredecessorLane()->getLinkCont()) {
1042 44377 : if (other->getLane() != link->getLane() && !other->isTurnaround()) {
1043 : return true;
1044 : }
1045 : }
1046 53654 : for (auto ili : link->getLane()->getIncomingLanes()) {
1047 37986 : if (ili.viaLink != link && !ili.viaLink->isTurnaround()) {
1048 : return true;
1049 : }
1050 : }
1051 15668 : const MSLane* bidi = link->getLane()->getBidiLane();
1052 15668 : if (bidi != nullptr) {
1053 26511 : for (const MSLink* other : bidi->getLinkCont()) {
1054 14099 : if (other->getLane() != link->getLaneBefore()->getNormalPredecessorLane()->getBidiLane() && !other->isTurnaround()) {
1055 : return true;
1056 : }
1057 : }
1058 : }
1059 : return false;
1060 : }
1061 :
1062 :
1063 : void
1064 23736 : MSDriveWay::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 13372 : const MSLink* reverseOriginLink = originLink != nullptr && originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1069 32196 : ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1070 : : nullptr;
1071 : //std::cout << " originLink=" << originLink->getDescription() << "\n";
1072 8460 : if (reverseOriginLink != nullptr) {
1073 8460 : reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1074 : //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1075 : }
1076 73494 : for (int i = 0; i < (int)lanes.size(); i++) {
1077 49758 : const MSLane* lane = lanes[i];
1078 49758 : const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1079 49758 : const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1080 49758 : if (lane->isInternal()) {
1081 15864 : continue;
1082 : }
1083 71387 : for (auto ili : lane->getIncomingLanes()) {
1084 44901 : if (ili.viaLink == originLink
1085 35731 : || ili.viaLink == reverseOriginLink
1086 33606 : || ili.viaLink->getDirection() == LinkDirection::TURN
1087 67578 : || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND) {
1088 7408 : continue;
1089 : }
1090 30085 : 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 22616 : } else if (allFoes) {
1096 : // link is part of the driveway, find foes that cross the driveway without entering
1097 8037 : checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1098 : }
1099 : }
1100 : }
1101 23736 : }
1102 :
1103 :
1104 : void
1105 8037 : MSDriveWay::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 8037 : if (junction == nullptr) {
1111 : return; // unregulated junction;
1112 : }
1113 7963 : const MSJunctionLogic* logic = junction->getLogic();
1114 7963 : if (logic == nullptr) {
1115 : return; // unregulated junction;
1116 : }
1117 42827 : for (const MSEdge* in : junction->getIncoming()) {
1118 34924 : if (in->isInternal()) {
1119 17655 : continue;
1120 : }
1121 34592 : for (MSLane* inLane : in->getLanes()) {
1122 17323 : const MSLane* inBidi = inLane->getBidiLane();
1123 25124 : if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0 && (inBidi == nullptr || visited.count(inBidi) == 0)) {
1124 6300 : for (MSLink* link : inLane->getLinkCont()) {
1125 3279 : if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1126 8453 : && 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 432 : 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 :
1142 : void
1143 9866 : MSDriveWay::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 9866 : if (link->getCorrespondingEntryLink()->getTLLogic() != nullptr) {
1148 2193 : 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 2193 : myConflictLinks.push_back(entry);
1156 2193 : addFoes(entry);
1157 : } else {
1158 : const MSLane* lane = link->getLaneBefore();
1159 : std::vector<MSLink*> predLinks;
1160 15295 : for (auto ili : lane->getIncomingLanes()) {
1161 7622 : if (!ili.viaLink->isTurnaround()) {
1162 7368 : predLinks.push_back(ili.viaLink);
1163 : }
1164 : }
1165 7673 : 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 705 : for (MSLink* pred : predLinks) {
1171 470 : addSwitchFoes(pred);
1172 : }
1173 7438 : } else if (predLinks.size() == 1) {
1174 6898 : if (isSwitch(link)) {
1175 5907 : addSwitchFoes(link);
1176 : } else {
1177 : // continue upstream via single predecessor
1178 991 : findFlankProtection(predLinks.front(), origLink, flank);
1179 : }
1180 : }
1181 7673 : }
1182 9866 : }
1183 :
1184 :
1185 : void
1186 6377 : MSDriveWay::addSwitchFoes(MSLink* link) {
1187 : auto it = mySwitchDriveWays.find(link);
1188 6377 : if (it != mySwitchDriveWays.end()) {
1189 : #ifdef DEBUG_ADD_FOES
1190 : std::cout << " driveway " << myID << " addSwitchFoes for link " << link->getDescription() << "\n";
1191 : #endif
1192 7305 : for (MSDriveWay* foe : it->second) {
1193 5035 : 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 2695 : myFoes.push_back(foe);
1200 : } else {
1201 : #ifdef DEBUG_ADD_FOES
1202 : std::cout << " cand=" << foe->myID << "\n";
1203 : #endif
1204 : }
1205 : }
1206 : }
1207 6377 : }
1208 :
1209 :
1210 : MSDriveWay*
1211 5934 : MSDriveWay::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 5934 : MSDriveWay* dw = new MSDriveWay(link, id);
1235 : LaneVisitedMap visited;
1236 : std::vector<const MSLane*> before;
1237 5934 : MSLane* fromBidi = nullptr;
1238 5934 : if (link != nullptr) {
1239 3343 : appendMapIndex(visited, link->getLaneBefore());
1240 3343 : 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 5934 : if (fromBidi != nullptr) {
1245 2184 : before.push_back(fromBidi);
1246 : }
1247 5934 : dw->buildRoute(link, 0., first, end, visited, flankSwitches);
1248 5934 : dw->myCoreSize = (int)dw->myRoute.size();
1249 5934 : dw->checkFlanks(link, dw->myForward, visited, true, flankSwitches);
1250 5934 : dw->checkFlanks(link, dw->myBidi, visited, false, flankSwitches);
1251 5934 : dw->checkFlanks(link, before, visited, true, flankSwitches);
1252 13441 : 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 7507 : dw->findFlankProtection(fsLink, fsLink, dw->myFlank);
1259 : }
1260 : std::set<MSLink*> flankSwitchesBidiExtended;
1261 5934 : dw->checkFlanks(link, dw->myBidiExtended, visited, false, flankSwitchesBidiExtended);
1262 7302 : 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 1368 : dw->findFlankProtection(link, link, dw->myBidiExtended);
1269 : }
1270 5934 : MSRailSignal* rs = link ? const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(link->getTLLogic())) : nullptr;
1271 9277 : 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 5934 : if (!rs || !rs->isMovingBlock()) {
1286 5909 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myForward.begin(), dw->myForward.end());
1287 : }
1288 5934 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myBidi.begin(), dw->myBidi.end());
1289 5934 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myFlank.begin(), dw->myFlank.end());
1290 5934 : dw->addBidiFoes(rs, false);
1291 5934 : dw->addBidiFoes(rs, true);
1292 : // add driveways that start on the same signal / lane
1293 5934 : dw->addParallelFoes(link, *first);
1294 : // add driveways that reverse along this driveways route
1295 5934 : dw->addReversalFoes();
1296 : // make foes unique and symmetrical
1297 5934 : std::set<MSDriveWay*, ComparatorNumericalIdLess> uniqueFoes(dw->myFoes.begin(), dw->myFoes.end());
1298 5934 : std::set<MSLink*> uniqueCLink(dw->myConflictLinks.begin(), dw->myConflictLinks.end());
1299 : dw->myFoes.clear();
1300 5934 : const MSEdge* lastEdge = &dw->myForward.back()->getEdge();
1301 10032 : for (MSDriveWay* foe : uniqueFoes) {
1302 4098 : const MSEdge* foeLastEdge = &foe->myForward.back()->getEdge();
1303 4098 : const bool sameLast = foeLastEdge == lastEdge;
1304 4098 : if (sameLast && !movingBlock) {
1305 1049 : dw->myFoes.push_back(foe);
1306 1049 : if (foe != dw) {
1307 1049 : foe->myFoes.push_back(dw);
1308 : }
1309 : } else {
1310 3049 : 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 1646 : foe->myFoes.push_back(dw);
1317 1646 : foe->addSidings(dw);
1318 : } else {
1319 1403 : dw->buildSubFoe(foe, movingBlock);
1320 : }
1321 3049 : 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 1754 : dw->myFoes.push_back(foe);
1328 1754 : dw->addSidings(foe);
1329 : } else {
1330 1295 : foe->buildSubFoe(dw, movingBlock);
1331 : }
1332 : }
1333 4098 : if (link) {
1334 2887 : foe->addConflictLink(link);
1335 : }
1336 : // ignore links that have the same start junction
1337 4098 : if (foe->myRoute.front()->getFromJunction() != dw->myRoute.front()->getFromJunction()) {
1338 6282 : for (auto ili : foe->myForward.front()->getIncomingLanes()) {
1339 2875 : if (ili.viaLink->getTLLogic() != nullptr) {
1340 : // ignore links that originate on myBidi
1341 2546 : const MSLane* origin = ili.viaLink->getLaneBefore();
1342 2546 : 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 5934 : dw->myConflictLinks.insert(dw->myConflictLinks.begin(), uniqueCLink.begin(), uniqueCLink.end());
1351 5934 : myEndingDriveways[lastEdge].push_back(dw);
1352 5934 : if (!movingBlock) {
1353 : // every driveway is it's own foe (also all driveways that depart in the same block)
1354 12888 : for (MSDriveWay* sameEnd : myEndingDriveways[lastEdge]) {
1355 : if (uniqueFoes.count(sameEnd) == 0) {
1356 5972 : dw->myFoes.push_back(sameEnd);
1357 5972 : if (sameEnd != dw) {
1358 105 : 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 5934 : return dw;
1369 5934 : }
1370 :
1371 : std::string
1372 2917 : MSDriveWay::getTLLinkID(const MSLink* link) {
1373 5834 : return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
1374 : }
1375 :
1376 : std::string
1377 0 : MSDriveWay::getJunctionLinkID(const MSLink* link) {
1378 0 : return link->getJunction()->getID() + "_" + toString(link->getIndex());
1379 : }
1380 :
1381 : std::string
1382 3353 : MSDriveWay::getClickableTLLinkID(const MSLink* link) {
1383 10059 : return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
1384 : }
1385 :
1386 : std::string
1387 0 : MSDriveWay::formatVisitedMap(const LaneVisitedMap& visited) {
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 0 : return "dummy";
1404 : }
1405 :
1406 :
1407 : void
1408 40307 : MSDriveWay::appendMapIndex(LaneVisitedMap& map, const MSLane* lane) {
1409 : // avoid undefined behavior from evaluation order
1410 40307 : const int tmp = (int)map.size();
1411 40307 : map[lane] = tmp;
1412 40307 : }
1413 :
1414 : bool
1415 8311394 : MSDriveWay::match(MSRouteIterator firstIt, MSRouteIterator endIt) const {
1416 : // @todo optimize: it is sufficient to check for specific edges (after each switch)
1417 8311394 : auto itRoute = firstIt;
1418 : auto itDwRoute = myRoute.begin();
1419 : bool match = true;
1420 50007844 : while (itRoute != endIt && itDwRoute != myRoute.end()) {
1421 41717745 : 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 8290099 : if (match && itDwRoute == myRoute.end()
1434 16589377 : && (itRoute == endIt || myAbortedBuild || myBidiEnded || myFoundJump || myIsSubDriveway)) {
1435 : //std::cout << " using dw=" << "\n";
1436 8273645 : if (itRoute != endIt) {
1437 : // check whether the current route requires an extended driveway
1438 305908 : const MSEdge* next = *itRoute;
1439 305908 : const MSEdge* prev = myRoute.back();
1440 568 : if (myFoundJump && prev->getBidiEdge() != next && prev->getBidiEdge() != nullptr
1441 306116 : && 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 305898 : 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 8273620 : return true;
1457 : }
1458 : return false;
1459 : }
1460 :
1461 : void
1462 8851 : MSDriveWay::addFoes(const MSLink* link) {
1463 : #ifdef DEBUG_ADD_FOES
1464 : std::cout << "driveway " << myID << " addFoes for link " << link->getDescription() << "\n";
1465 : #endif
1466 8851 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
1467 8851 : if (rs != nullptr) {
1468 11081 : 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 2244 : 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 1911 : myFoes.push_back(foe);
1477 : }
1478 8837 : }
1479 : }
1480 8851 : }
1481 :
1482 :
1483 : void
1484 11868 : MSDriveWay::addBidiFoes(const MSRailSignal* ownSignal, bool extended) {
1485 : #ifdef DEBUG_ADD_FOES
1486 : std::cout << "driveway " << myID << " addBidiFoes extended=" << extended << "\n";
1487 : #endif
1488 11868 : const std::vector<const MSLane*>& bidiLanes = extended ? myBidiExtended : myBidi;
1489 41262 : for (const MSLane* bidi : bidiLanes) {
1490 61233 : for (auto ili : bidi->getIncomingLanes()) {
1491 31839 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(ili.viaLink->getTLLogic());
1492 31839 : if (rs != nullptr && rs != ownSignal &&
1493 31839 : std::find(bidiLanes.begin(), bidiLanes.end(), ili.lane) != bidiLanes.end()) {
1494 3315 : addFoes(ili.viaLink);
1495 : }
1496 : }
1497 29394 : const MSEdge* bidiEdge = &bidi->getEdge();
1498 : if (myDepartureDriveways.count(bidiEdge) != 0) {
1499 1942 : for (MSDriveWay* foe : myDepartureDriveways[bidiEdge]) {
1500 968 : if (flankConflict(*foe)) {
1501 : #ifdef DEBUG_ADD_FOES
1502 : std::cout << " foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << "\n";
1503 : #endif
1504 726 : 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 1744 : for (MSDriveWay* foe : myDepartureDrivewaysEnds[bidiEdge]) {
1514 913 : if (flankConflict(*foe)) {
1515 : #ifdef DEBUG_ADD_FOES
1516 : std::cout << " foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << "\n";
1517 : #endif
1518 706 : 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 11868 : }
1528 :
1529 :
1530 : void
1531 5934 : MSDriveWay::addParallelFoes(const MSLink* link, const MSEdge* first) {
1532 : #ifdef DEBUG_ADD_FOES
1533 : std::cout << "driveway " << myID << " addParallelFoes\n";
1534 : #endif
1535 5934 : if (link) {
1536 3343 : addFoes(link);
1537 : } else {
1538 : auto it = myDepartureDriveways.find(first);
1539 2591 : if (it != myDepartureDriveways.end()) {
1540 2700 : 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 109 : myFoes.push_back(foe);
1545 : }
1546 : }
1547 : }
1548 5934 : }
1549 :
1550 :
1551 : void
1552 5934 : MSDriveWay::addReversalFoes() {
1553 : #ifdef DEBUG_ADD_FOES
1554 : std::cout << "driveway " << myID << " addReversalFoes\n";
1555 : #endif
1556 : std::set<const MSEdge*> forward;
1557 24114 : for (const MSLane* lane : myForward) {
1558 18180 : if (lane->isNormal()) {
1559 12612 : forward.insert(&lane->getEdge());
1560 : }
1561 : }
1562 : int i = 0;
1563 30139 : for (const MSEdge* e : myRoute) {
1564 12622 : if (forward.count(e) != 0) {
1565 : // reversals in our own forward section must be ignored
1566 : continue;
1567 : }
1568 11583 : if (i == myCoreSize) {
1569 : break;
1570 : }
1571 11583 : i++;
1572 : auto it = myReversalDriveWays.find(e);
1573 11583 : if (it != myReversalDriveWays.end()) {
1574 1288 : 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 1722 : if (forwardRouteConflict(forward, *foe)) {
1581 : std::set<const MSEdge*> foeForward;
1582 999 : for (const MSLane* lane : foe->myForward) {
1583 848 : if (lane->isNormal()) {
1584 536 : foeForward.insert(&lane->getEdge());
1585 536 : if (lane->getBidiLane() != nullptr) {
1586 536 : 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 302 : 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 116 : myFoes.push_back(foe);
1598 : }
1599 : }
1600 : }
1601 : }
1602 : }
1603 5934 : }
1604 :
1605 :
1606 : bool
1607 2698 : MSDriveWay::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 2698 : if (myForward.size() < foe->myForward.size() &&
1619 2698 : 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 16 : foe->myFoes.push_back(this);
1624 16 : return true;
1625 : }
1626 2682 : 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 8563 : while (subLast >= 0) {
1634 8055 : const MSLane* lane = myForward[subLast];
1635 8055 : MSDriveWay tmp(myOrigin, "tmp", true);
1636 8055 : 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 8055 : const bool bidiConflict = std::find(foe->myBidi.begin(), foe->myBidi.end(), lane) != foe->myBidi.end();
1642 8055 : if (tmp.flankConflict(*foe) || tmp.crossingConflict(*foe) || bidiConflict) {
1643 : foundConflict = true;
1644 2188 : if (!movingBlock || bidiConflict) {
1645 : break;
1646 : }
1647 5867 : } else if (foundConflict) {
1648 : break;
1649 : }
1650 5881 : subLast--;
1651 8055 : }
1652 2682 : if (subLast < 0) {
1653 508 : if (foe->myTerminateRoute) {
1654 468 : if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
1655 62 : foe->myFoes.push_back(this);
1656 : // foe will get the sidings
1657 62 : addSidings(foe, true);
1658 : }
1659 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1660 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " terminates\n";
1661 : #endif
1662 40 : } else if (myTerminateRoute && myBidi.size() <= myForward.size()) {
1663 5 : 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 5 : 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 503 : return false;
1681 : }
1682 2174 : int subSize = subLast + 1;
1683 2776 : for (MSDriveWay* cand : mySubDriveWays) {
1684 1092 : if ((int)cand->myForward.size() == subSize) {
1685 : // can re-use existing sub-driveway
1686 490 : foe->myFoes.push_back(cand);
1687 490 : 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 490 : return true;
1692 : }
1693 : }
1694 1684 : std::vector<const MSLane*> forward(myForward.begin(), myForward.begin() + subSize);
1695 : std::vector<const MSEdge*> route;
1696 7922 : for (const MSLane* lane : forward) {
1697 6238 : if (lane->isNormal()) {
1698 3675 : route.push_back(&lane->getEdge());
1699 : }
1700 : }
1701 1684 : if (myRoute.size() > route.size()) {
1702 : // route continues. make sure the subDriveway does not end with a reversal
1703 1684 : const MSEdge* lastNormal = route.back();
1704 1684 : const MSEdge* nextNormal = myRoute[route.size()];
1705 1684 : 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 3344 : MSDriveWay* sub = new MSDriveWay(myOrigin, getID() + "." + toString(mySubDriveWays.size()));
1714 1672 : sub->myLane = myLane;
1715 1672 : sub->myIsSubDriveway = true;
1716 1672 : sub->myForward = forward;
1717 1672 : sub->myRoute = route;
1718 1672 : sub->myCoreSize = (int)sub->myRoute.size();
1719 1672 : myLane->addMoveReminder(sub);
1720 :
1721 : // copy trains that are currently on this driveway (and associated entry events)
1722 1737 : for (SUMOVehicle* veh : myTrains) {
1723 65 : if (std::find(sub->myRoute.begin(), sub->myRoute.end(), veh->getEdge()) != sub->myRoute.end()) {
1724 : sub->myTrains.insert(veh);
1725 53 : dynamic_cast<MSBaseVehicle*>(veh)->addReminder(sub);
1726 53 : for (const VehicleEvent& ve : myVehicleEvents) {
1727 0 : if (ve.id == veh->getID()) {
1728 0 : sub->myVehicleEvents.push_back(ve);
1729 : }
1730 : }
1731 : }
1732 : }
1733 :
1734 1672 : foe->myFoes.push_back(sub);
1735 1672 : sub->myFoes.push_back(foe);
1736 1672 : 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 1684 : }
1742 :
1743 : void
1744 3462 : MSDriveWay::addSidings(MSDriveWay* foe, bool addToFoe) {
1745 3462 : const MSEdge* foeEndBidi = foe->myForward.back()->getEdge().getBidiEdge();
1746 : int forwardNormals = 0;
1747 15840 : for (auto lane : foe->myForward) {
1748 12378 : if (lane->isNormal()) {
1749 8276 : forwardNormals++;
1750 : }
1751 : }
1752 3462 : 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 724 : return;
1757 : }
1758 : auto foeSearchBeg = foe->myRoute.begin() + forwardNormals;
1759 : auto foeSearchEnd = foe->myRoute.end();
1760 2738 : if (foeEndBidi == nullptr) {
1761 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " noBidi\n");
1762 : }
1763 : int i;
1764 : std::vector<int> start;
1765 : std::vector<double> length;
1766 16143 : for (i = 0; i < (int)myRoute.size(); i++) {
1767 16143 : if (myRoute[i] == foeEndBidi) {
1768 : break;
1769 : }
1770 : }
1771 2738 : if (i == (int)myRoute.size()) {
1772 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " foeEndBidi=" + foeEndBidi->getID() + " not on route\n");
1773 : }
1774 2738 : 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 2738 : i--;
1779 16143 : for (; i >= 0; i--) {
1780 13405 : const MSEdge* cur = myRoute[i];
1781 13405 : if (hasRS(cur, next)) {
1782 2685 : if (std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge()) == foeSearchEnd) {
1783 643 : start.push_back(i);
1784 643 : length.push_back(0);
1785 : }
1786 : }
1787 13405 : if (!start.empty()) {
1788 1807 : auto itFind = std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge());
1789 1807 : 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 401 : const int firstIndex = i + 1;
1794 401 : if (addToFoe) {
1795 34 : auto& foeSidings = foe->mySidings[this];
1796 : // indices must be mapped onto foe route;
1797 34 : const MSEdge* first = myRoute[firstIndex];
1798 34 : auto itFirst = std::find(foe->myRoute.begin(), foe->myRoute.end(), first);
1799 34 : if (itFirst != foe->myRoute.end()) {
1800 87 : for (int j = 0; j < (int)length.size(); j++) {
1801 53 : const MSEdge* last = myRoute[start[j]];
1802 53 : auto itLast = std::find(itFirst, foe->myRoute.end(), last);
1803 53 : if (itLast != foe->myRoute.end()) {
1804 53 : foeSidings.insert(foeSidings.begin(), Siding((int)(itFirst - foe->myRoute.begin()), (int)(itLast - foe->myRoute.begin()), length[j]));
1805 : }
1806 : }
1807 : }
1808 : } else {
1809 367 : auto& foeSidings = mySidings[foe];
1810 846 : for (int j = 0; j < (int)length.size(); j++) {
1811 479 : foeSidings.insert(foeSidings.begin(), Siding(firstIndex, start[j], length[j]));
1812 : }
1813 : }
1814 : start.clear();
1815 : length.clear();
1816 401 : foeSearchBeg = itFind;
1817 : } else {
1818 3156 : for (int j = 0; j < (int)length.size(); j++) {
1819 1750 : length[j] += cur->getLength();
1820 : }
1821 : }
1822 : }
1823 : next = cur;
1824 : }
1825 2738 : }
1826 :
1827 :
1828 : bool
1829 13405 : MSDriveWay::hasRS(const MSEdge* cur, const MSEdge* next) {
1830 13405 : if (cur->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1831 : // check if there is a controlled link between cur and next
1832 10579 : for (auto lane : cur->getLanes()) {
1833 10962 : for (const MSLink* link : lane->getLinkCont()) {
1834 7015 : if (&link->getLane()->getEdge() == next && link->getTLLogic() != nullptr) {
1835 : return true;
1836 : }
1837 : }
1838 : }
1839 : }
1840 : return false;
1841 : }
1842 :
1843 :
1844 : bool
1845 72 : MSDriveWay::forwardEndOnRoute(const MSDriveWay* foe) const {
1846 72 : const MSEdge* foeForwardEnd = &foe->myForward.back()->getNormalPredecessorLane()->getEdge();
1847 72 : return std::find(myRoute.begin(), myRoute.end(), foeForwardEnd) != myRoute.end();
1848 : }
1849 :
1850 : void
1851 2887 : MSDriveWay::addConflictLink(const MSLink* link) {
1852 2887 : if (link->getTLLogic() != nullptr) {
1853 : // ignore links that originate on myBidi
1854 : // and also links from the same junction as my own link
1855 2887 : const MSLane* origin = link->getLaneBefore();
1856 2887 : if (std::find(myBidi.begin(), myBidi.end(), origin) == myBidi.end()) {
1857 2029 : if (link->getJunction() != myRoute.front()->getFromJunction()) {
1858 1639 : if (std::find(myConflictLinks.begin(), myConflictLinks.end(), link) == myConflictLinks.end()) {
1859 1195 : myConflictLinks.push_back(const_cast<MSLink*>(link));
1860 : }
1861 : }
1862 : }
1863 : }
1864 2887 : }
1865 :
1866 : void
1867 274 : MSDriveWay::addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes) {
1868 : std::set<const MSDriveWay*> filtered;
1869 1425 : for (const MSDriveWay* foe : deadlockFoes) {
1870 1151 : if (std::find(myFoes.begin(), myFoes.end(), foe) == myFoes.end()) {
1871 : filtered.insert(foe);
1872 : }
1873 : }
1874 274 : if (std::find(myDeadlocks.begin(), myDeadlocks.end(), filtered) == myDeadlocks.end()) {
1875 81 : myDeadlocks.push_back(filtered);
1876 : //std::cout << getID() << " deadlockFoes=" << toString(deadlockFoes) << "\n";
1877 : }
1878 274 : }
1879 :
1880 : const MSDriveWay*
1881 52560 : MSDriveWay::getDepartureDriveway(const SUMOVehicle* veh) {
1882 52560 : const MSEdge* edge = veh->getEdge();
1883 52560 : if (edge->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1884 3643 : for (const MSLane* lane : edge->getLanes()) {
1885 3985 : for (auto ili : lane->getIncomingLanes()) {
1886 2441 : const MSLink* entry = ili.viaLink->getCorrespondingEntryLink();
1887 2441 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(entry->getTLLogic());
1888 1739 : if (rs != nullptr) {
1889 1739 : const MSDriveWay* dw = &const_cast<MSRailSignal*>(rs)->retrieveDriveWayForVeh(entry->getTLIndex(), veh);
1890 1739 : if (&dw->myForward.front()->getEdge() == edge) {
1891 : return dw;
1892 : }
1893 : }
1894 : }
1895 : }
1896 : }
1897 53571 : for (MSDriveWay* dw : myDepartureDriveways[edge]) {
1898 50980 : if (dw->match(veh->getCurrentRouteEdge(), veh->getRoute().end())) {
1899 : return dw;
1900 : }
1901 : }
1902 5182 : const std::string id = edge->getFromJunction()->getID() + ".d" + toString(myDepartDrivewayIndex[edge->getFromJunction()]++);
1903 2591 : MSDriveWay* dw = buildDriveWay(id, nullptr, veh->getCurrentRouteEdge(), veh->getRoute().end());
1904 2591 : myDepartureDriveways[edge].push_back(dw);
1905 2591 : myDepartureDrivewaysEnds[&dw->myForward.back()->getEdge()].push_back(dw);
1906 : dw->setVehicle(veh->getID());
1907 : return dw;
1908 : }
1909 :
1910 :
1911 : void
1912 1063 : MSDriveWay::writeDepatureBlocks(OutputDevice& od, bool writeVehicles) {
1913 2723 : for (auto item : myDepartureDriveways) {
1914 1660 : const MSEdge* edge = item.first;
1915 1660 : if (item.second.size() > 0) {
1916 3320 : od.openTag("departJunction");
1917 : od.writeAttr(SUMO_ATTR_ID, edge->getFromJunction()->getID());
1918 3421 : for (const MSDriveWay* dw : item.second) {
1919 1761 : if (writeVehicles) {
1920 137 : dw->writeBlockVehicles(od);
1921 : } else {
1922 1624 : dw->writeBlocks(od);
1923 : }
1924 : }
1925 3320 : od.closeTag(); // departJunction
1926 : }
1927 : }
1928 1063 : }
1929 :
1930 : void
1931 425 : MSDriveWay::saveState(OutputDevice& out) {
1932 : // all driveways are in myEndingDriveways which makes it convenient
1933 463 : for (auto item : myEndingDriveways) {
1934 80 : for (MSDriveWay* dw : item.second) {
1935 42 : dw->_saveState(out);
1936 51 : for (MSDriveWay* sub : dw->mySubDriveWays) {
1937 9 : sub->_saveState(out);
1938 : }
1939 : }
1940 : }
1941 425 : }
1942 :
1943 : void
1944 51 : MSDriveWay::_saveState(OutputDevice& out) const {
1945 51 : if (!myTrains.empty() || haveSubTrains()) {
1946 37 : out.openTag(myIsSubDriveway ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
1947 : out.writeAttr(SUMO_ATTR_ID, getID());
1948 40 : out.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
1949 20 : if (!myTrains.empty()) {
1950 40 : out.writeAttr(SUMO_ATTR_VEHICLES, toString(myTrains));
1951 : }
1952 40 : out.closeTag();
1953 : }
1954 51 : }
1955 :
1956 :
1957 : bool
1958 31 : MSDriveWay::haveSubTrains() const {
1959 36 : for (MSDriveWay* sub : mySubDriveWays) {
1960 5 : if (!sub->myTrains.empty()) {
1961 : return true;
1962 : }
1963 : }
1964 : return false;
1965 : }
1966 :
1967 : void
1968 29 : MSDriveWay::loadState(const SUMOSAXAttributes& attrs, int tag) {
1969 29 : if ((int)myDriveWayRouteLookup.size() < myGlobalDriveWayIndex) {
1970 69 : for (auto item : myEndingDriveways) {
1971 110 : for (MSDriveWay* dw : item.second) {
1972 56 : myDriveWayRouteLookup[dw->myRoute] = dw;
1973 : }
1974 : }
1975 : }
1976 29 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
1977 : bool ok;
1978 29 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1979 29 : const std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), ok);
1980 : ConstMSEdgeVector route;
1981 29 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
1982 29 : MSEdge::parseEdgesList(edges, route, id);
1983 : }
1984 : MSDriveWay* dw = nullptr;
1985 29 : if (tag == SUMO_TAG_DRIVEWAY) {
1986 : auto it = myDriveWayRouteLookup.find(route);
1987 26 : if (it == myDriveWayRouteLookup.end()) {
1988 : //WRITE_WARNING(TLF("Unknown driveWay '%' with route '%'", id, edges));
1989 : //return;
1990 0 : throw ProcessError(TLF("Unknown driveWay '%' with route '%'", id, edges));
1991 : }
1992 26 : dw = it->second;
1993 26 : myDriveWayLookup[id] = dw;
1994 : } else {
1995 3 : std::string parentID = id.substr(0, id.rfind('.'));
1996 : auto it = myDriveWayLookup.find(parentID);
1997 3 : if (it == myDriveWayLookup.end()) {
1998 : //WRITE_WARNING(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
1999 : //return;
2000 0 : throw ProcessError(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2001 : }
2002 3 : MSDriveWay* parent = it->second;
2003 3 : for (MSDriveWay* sub : parent->mySubDriveWays) {
2004 1 : if (sub->myRoute == route) {
2005 : dw = sub;
2006 : break;
2007 : }
2008 : }
2009 3 : 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 54 : const std::string vehicles = attrs.getOpt<std::string>(SUMO_ATTR_VEHICLES, id.c_str(), ok, "");
2016 81 : for (const std::string& vehID : StringTokenizer(vehicles).getVector()) {
2017 27 : MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(c.getVehicle(vehID));
2018 27 : if (veh == nullptr) {
2019 0 : throw ProcessError(TLF("Unknown vehicle '%' in driveway '%'", vehID, id));
2020 : }
2021 27 : dw->myTrains.insert(veh);
2022 27 : veh->addReminder(dw);
2023 27 : }
2024 29 : }
2025 :
2026 :
2027 : /****************************************************************************/
|