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