Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
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_MOVEREMINDER
50 : //#define DEBUG_MATCH
51 :
52 : #define DEBUG_HELPER(obj) ((obj) != nullptr && (obj)->isSelected())
53 : //#define DEBUG_HELPER(obj) ((obj)->getID() == "")
54 : //#define DEBUG_HELPER(obj) (true)
55 :
56 : #define DEBUG_DW_ID ""
57 : #define DEBUG_COND_DW(obj) (obj->getID() == DEBUG_DW_ID || DEBUG_DW_ID == std::string("ALL"))
58 : #define DEBUG_COND_DW2 (getID() == DEBUG_DW_ID || DEBUG_DW_ID == std::string("ALL"))
59 :
60 : // ===========================================================================
61 : // static value definitions
62 : // ===========================================================================
63 : int MSDriveWay::myGlobalDriveWayIndex(0);
64 : std::set<const MSEdge*> MSDriveWay::myBlockLengthWarnings;
65 : bool MSDriveWay::myWriteVehicles(false);
66 : double MSDriveWay::myMovingBlockMaxDist(1e10);
67 : std::map<const MSLink*, std::vector<MSDriveWay*> > MSDriveWay::mySwitchDriveWays;
68 : std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myReversalDriveWays;
69 : std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myDepartureDriveways;
70 : std::map<const MSJunction*, int> MSDriveWay::myDepartDrivewayIndex;
71 : std::map<const MSEdge*, std::vector<MSDriveWay*> > MSDriveWay::myDepartureDrivewaysEnds;
72 : std::map<const MSEdge*, std::vector<MSDriveWay*>, ComparatorNumericalIdLess> MSDriveWay::myEndingDriveways;
73 : std::map<ConstMSEdgeVector, MSDriveWay*> MSDriveWay::myDriveWayRouteLookup;
74 : std::map<std::string, MSDriveWay*> MSDriveWay::myDriveWayLookup;
75 :
76 : // ---------------------------------------------------------------------------
77 : // static initialisation methods
78 : // ---------------------------------------------------------------------------
79 : void
80 42726 : MSDriveWay::init() {
81 42726 : myWriteVehicles = OptionsCont::getOptions().isSet("railsignal-vehicle-output");
82 42726 : myMovingBlockMaxDist = OptionsCont::getOptions().getFloat("railsignal.moving-block.max-dist");
83 42726 : }
84 :
85 : // ===========================================================================
86 : // MSDriveWay method definitions
87 : // ===========================================================================
88 :
89 :
90 26816 : MSDriveWay::MSDriveWay(const MSLink* origin, const std::string& id, bool temporary) :
91 53632 : MSMoveReminder("DriveWay_" + (temporary ? "tmp" : id)),
92 : Named(id),
93 11856 : myNumericalID(temporary ? -1 : myGlobalDriveWayIndex++),
94 26816 : myOrigin(origin),
95 26816 : myActive(nullptr),
96 26816 : myCoreSize(0),
97 26816 : myForwardEdgeCount(0),
98 26816 : myFoundSignal(false),
99 26816 : myFoundJump(false),
100 26816 : myTerminateRoute(false),
101 26816 : myAbortedBuild(false),
102 26816 : myBidiEnded(false),
103 92304 : myParent(nullptr)
104 26816 : {}
105 :
106 :
107 38672 : MSDriveWay::~MSDriveWay() {
108 29389 : for (const MSDriveWay* sub : mySubDriveWays) {
109 2573 : delete sub;
110 : }
111 : mySubDriveWays.clear();
112 119120 : }
113 :
114 : void
115 42395 : MSDriveWay::cleanup() {
116 42395 : myGlobalDriveWayIndex = 0;
117 : myBlockLengthWarnings.clear();
118 42395 : myWriteVehicles = false;
119 :
120 45881 : for (auto item : myDepartureDriveways) {
121 7283 : for (MSDriveWay* dw : item.second) {
122 3797 : delete dw;
123 : }
124 : }
125 : MSDriveWay::mySwitchDriveWays.clear();
126 : MSDriveWay::myReversalDriveWays.clear();
127 : MSDriveWay::myDepartureDriveways.clear();
128 : MSDriveWay::myDepartDrivewayIndex.clear();
129 : MSDriveWay::myDepartureDrivewaysEnds.clear();
130 : MSDriveWay::myEndingDriveways.clear();
131 42395 : }
132 :
133 : void
134 167 : MSDriveWay::clearState() {
135 192 : for (auto item : myEndingDriveways) {
136 50 : for (MSDriveWay* dw : item.second) {
137 : dw->myTrains.clear();
138 : }
139 : }
140 167 : }
141 :
142 :
143 : bool
144 40290 : MSDriveWay::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
145 : #ifdef DEBUG_MOVEREMINDER
146 : std::cout << SIMTIME << " notifyEnter " << getDescription() << " veh=" << veh.getID() << " lane=" << (MSGlobals::gUseMesoSim ? veh.getCurrentEdge()->getID() : Named::getIDSecure(enteredLane)) << " reason=" << reason << "\n";
147 : #endif
148 :
149 40290 : if (veh.isVehicle() && MSRailSignalControl::isUsingDriveWays(veh.getVClass())) {
150 13658 : if ((enteredLane == myLane || (MSGlobals::gUseMesoSim && veh.getCurrentEdge() == &myLane->getEdge()))
151 52459 : && (reason == NOTIFICATION_DEPARTED || reason == NOTIFICATION_JUNCTION || reason == NOTIFICATION_PARKING)) {
152 38696 : SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
153 38696 : MSRouteIterator firstIt = std::find(sveh.getCurrentRouteEdge(), sveh.getRoute().end(), myLane->getNextNormal());
154 38696 : if (match(firstIt, sveh.getRoute().end())) {
155 22952 : if (myTrains.count(&sveh) == 0) {
156 22880 : enterDriveWay(sveh, reason);
157 : }
158 22916 : return true;
159 : }
160 1536 : } else if (reason == NOTIFICATION_REROUTE) {
161 1473 : SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
162 : assert(myTrains.count(&sveh) == 0);
163 1473 : int movedPast = matchesPastRoute(sveh);
164 : // vehicle must still be one the drivway
165 1473 : if (movedPast >= 0 && movedPast < myForwardEdgeCount) {
166 770 : enterDriveWay(sveh, reason);
167 770 : return true;
168 : }
169 : }
170 : }
171 : return false;
172 : }
173 :
174 :
175 : bool
176 151361 : MSDriveWay::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, Notification reason, const MSLane* enteredLane) {
177 : UNUSED_PARAMETER(enteredLane);
178 : #ifdef DEBUG_MOVEREMINDER
179 : std::cout << SIMTIME << " notifyLeave " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(enteredLane) << " reason=" << toString(reason) << "\n";
180 : #endif
181 151361 : if (veh.isVehicle() && MSRailSignalControl::isUsingDriveWays(veh.getVClass())) {
182 : // leaving network with departure, teleport etc
183 151361 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
184 7409 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
185 7409 : if (myWriteVehicles) {
186 804 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
187 : }
188 7409 : return false;
189 143952 : } else if (MSGlobals::gUseMesoSim && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
190 : // notifyLeave is called before moving the route iterator
191 21500 : const MSLane* leftLane = (*(dynamic_cast<SUMOVehicle&>(veh).getCurrentRouteEdge()))->getLanes().front();
192 21500 : return notifyLeaveBack(veh, reason, leftLane);
193 : } else {
194 : return true;
195 : }
196 : } else {
197 0 : return false;
198 : }
199 : }
200 :
201 :
202 : bool
203 94168 : MSDriveWay::notifyLeaveBack(SUMOTrafficObject& veh, Notification reason, const MSLane* 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 94168 : if (veh.isVehicle() && MSRailSignalControl::isUsingDriveWays(veh.getVClass())) {
208 94168 : if (leftLane == myForward.back() && (veh.getBackLane() != leftLane->getBidiLane() || MSGlobals::gUseMesoSim)) {
209 15505 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
210 15505 : if (myWriteVehicles) {
211 1308 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
212 : }
213 15505 : return false;
214 : } else {
215 78663 : return true;
216 : }
217 : } else {
218 0 : return false;
219 : }
220 : }
221 :
222 :
223 : bool
224 1557 : MSDriveWay::notifyReroute(SUMOTrafficObject& veh) {
225 : #ifdef DEBUG_MOVEREMINDER
226 : std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << "\n";
227 : #endif
228 : assert(veh.isVehicle());
229 1557 : if (MSRailSignalControl::isUsingDriveWays(veh.getVClass())) {
230 1555 : SUMOVehicle* sveh = dynamic_cast<SUMOVehicle*>(&veh);
231 : assert(myTrains.count(sveh) != 0);
232 1555 : if (matchesPastRoute(*sveh) >= 0) {
233 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
234 774 : return true;
235 : }
236 : // no match found, remove
237 : myTrains.erase(sveh);
238 781 : if (myWriteVehicles) {
239 142 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), NOTIFICATION_REROUTE));
240 : }
241 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " invalid\n";
242 : }
243 : return false;
244 : }
245 :
246 :
247 : int
248 3028 : MSDriveWay::matchesPastRoute(SUMOVehicle& sveh) const {
249 : // look backwards along the route to find the driveway lane
250 3028 : const ConstMSEdgeVector& routeEdges = sveh.getRoute().getEdges();
251 18908 : for (int i = sveh.getRoutePosition(); i >= 0; i--) {
252 18490 : if (routeEdges[i] == myLane->getNextNormal()) {
253 : MSRouteIterator firstIt = routeEdges.begin() + i;
254 2610 : if (match(firstIt, sveh.getRoute().end())) {
255 : // driveway is still valid after rerouting
256 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
257 1634 : return sveh.getRoutePosition() - i;
258 : }
259 976 : break;
260 : }
261 : }
262 : return -1;
263 : }
264 :
265 :
266 : void
267 23650 : MSDriveWay::enterDriveWay(SUMOVehicle& sveh, Notification reason) {
268 23650 : myTrains.insert(&sveh);
269 23650 : if (myOrigin != nullptr) {
270 15799 : MSRailSignalControl::getInstance().notifyApproach(myOrigin);
271 : }
272 78251 : for (const MSDriveWay* foe : myFoes) {
273 54601 : if (foe->myOrigin != nullptr) {
274 42476 : MSRailSignalControl::getInstance().notifyApproach(foe->myOrigin);
275 : }
276 : }
277 23650 : if (myWriteVehicles) {
278 2234 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, true, sveh.getID(), reason));
279 : }
280 23650 : }
281 :
282 : bool
283 722102 : MSDriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
284 722102 : if (foeDriveWayOccupied(true, closest.first, occupied)) {
285 : return false;
286 : }
287 619775 : for (MSLink* foeLink : myConflictLinks) {
288 150532 : if (hasLinkConflict(closest, foeLink)) {
289 : #ifdef DEBUG_SIGNALSTATE
290 : if (gDebugFlag4 || DEBUG_HELPER(closest.first)) {
291 : std::cout << getID() << " linkConflict with " << getTLLinkID(foeLink) << "\n";
292 : }
293 : #endif
294 : return false;
295 : }
296 : }
297 469243 : myActive = closest.first;
298 469243 : return true;
299 : }
300 :
301 :
302 : bool
303 150532 : MSDriveWay::hasLinkConflict(const Approaching& veh, const MSLink* foeLink) const {
304 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
305 : if (gDebugFlag4) {
306 : std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << " ego=" << Named::getIDSecure(veh.first) << "\n";
307 : }
308 : #endif
309 150532 : if (foeLink->getApproaching().size() > 0) {
310 51598 : Approaching foe = foeLink->getClosest();
311 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
312 : if (gDebugFlag4) {
313 : std::cout << " approaching foe=" << foe.first->getID() << "\n";
314 : }
315 : #endif
316 51598 : if (foe.first == veh.first) {
317 51598 : return false;
318 : }
319 : const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
320 : assert(foeTLL != nullptr);
321 46526 : const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
322 : MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
323 46526 : if (foeRS != nullptr) {
324 46526 : const MSDriveWay& foeDriveWay = foeRS->retrieveDriveWayForVeh(foeLink->getTLIndex(), foe.first);
325 : MSEdgeVector occupied;
326 71405 : if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied) ||
327 41402 : !foeRS->constraintsAllow(foe.first) ||
328 32765 : !overlap(foeDriveWay) ||
329 62768 : getFoeOrSubFoe(&foeDriveWay) == nullptr ||
330 13443 : canUseSiding(veh.first, getFoeOrSubFoe(&foeDriveWay)).first) {
331 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
332 : if (gDebugFlag4 || veh.first->isSelected()) {
333 : if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied)) {
334 : std::cout << " foe blocked\n";
335 : } else if (!foeRS->constraintsAllow(foe.first)) {
336 : std::cout << " foe constrained\n";
337 : } else if (!overlap(foeDriveWay)) {
338 : std::cout << " no overlap with foeDW=" << foeDriveWay.getID() << "\n";
339 : } else if (getFoeOrSubFoe(&foeDriveWay) == nullptr) {
340 : std::cout << " foeDW=" << foeDriveWay.getID() << " is not a foe to " << getID() << "\n";
341 : } else if (canUseSiding(veh.first, &foeDriveWay).first) {
342 : std::cout << " use siding\n";
343 : }
344 : }
345 : #endif
346 34533 : return false;
347 : }
348 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
349 : if (gDebugFlag4) {
350 : std::cout
351 : << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
352 : << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
353 : << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
354 : << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
355 : << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
356 : << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
357 : << "\n";
358 : }
359 : #endif
360 11993 : const bool yield = mustYield(veh, foe);
361 11993 : if (MSRailSignal::storeVehicles()) {
362 540 : MSRailSignal::rivalVehicles().push_back(foe.first);
363 540 : if (yield) {
364 315 : MSRailSignal::priorityVehicles().push_back(foe.first);
365 : }
366 : }
367 11993 : return yield;
368 46526 : }
369 : }
370 : return false;
371 : }
372 :
373 :
374 : const MSDriveWay*
375 75573 : MSDriveWay::getFoeOrSubFoe(const MSDriveWay* dw) const {
376 75573 : if (std::find(myFoes.begin(), myFoes.end(), dw) != myFoes.end()) {
377 44954 : return dw;
378 : }
379 35409 : for (const MSDriveWay* sub : dw->mySubDriveWays) {
380 27820 : const MSDriveWay* foe = getFoeOrSubFoe(sub);
381 27820 : if (foe != nullptr) {
382 : return foe;
383 : }
384 : }
385 : return nullptr;
386 : }
387 :
388 :
389 : bool
390 11993 : MSDriveWay::mustYield(const Approaching& veh, const Approaching& foe) {
391 11993 : if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
392 8222 : if (foe.second.arrivalTime == veh.second.arrivalTime) {
393 562 : if (foe.first->getSpeed() == veh.first->getSpeed()) {
394 538 : if (foe.second.dist == veh.second.dist) {
395 502 : if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
396 484 : return foe.first->getNumericalID() < veh.first->getNumericalID();
397 : } else {
398 18 : return foe.first->getWaitingTime() > veh.first->getWaitingTime();
399 : }
400 : } else {
401 36 : return foe.second.dist < veh.second.dist;
402 : }
403 : } else {
404 24 : return foe.first->getSpeed() > veh.first->getSpeed();
405 : }
406 : } else {
407 7660 : return foe.second.arrivalTime < veh.second.arrivalTime;
408 : }
409 : } else {
410 3771 : return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
411 : }
412 : }
413 :
414 :
415 : bool
416 16035 : MSDriveWay::conflictLaneOccupied(bool store, const SUMOVehicle* ego) const {
417 210513 : for (const MSLane* lane : myConflictLanes) {
418 : if (!lane->isEmpty()) {
419 4410 : std::string joinVehicle = "";
420 4410 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
421 0 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
422 0 : if (stop != nullptr) {
423 0 : joinVehicle = stop->join;
424 : }
425 : }
426 : #ifdef DEBUG_SIGNALSTATE
427 : if (gDebugFlag4) {
428 : std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
429 : if (joinVehicle != "") {
430 : std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
431 : lane->releaseVehicles();
432 : }
433 : }
434 : #endif
435 4410 : if (lane->getVehicleNumberWithPartials() == 1) {
436 4410 : MSVehicle* foe = lane->getLastAnyVehicle();
437 4410 : if (joinVehicle != "") {
438 0 : if (foe->getID() == joinVehicle && foe->isStopped()) {
439 : #ifdef DEBUG_SIGNALSTATE
440 : if (gDebugFlag4) {
441 : std::cout << " ignore join-target '" << joinVehicle << "\n";
442 : }
443 : #endif
444 0 : continue;
445 : }
446 : }
447 4410 : if (ego != nullptr) {
448 0 : if (foe == ego && std::find(myForward.begin(), myForward.end(), lane) == myForward.end()) {
449 : #ifdef DEBUG_SIGNALSTATE
450 : if (gDebugFlag4) {
451 : std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
452 : }
453 : #endif
454 0 : continue;
455 : }
456 0 : if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
457 : #ifdef DEBUG_SIGNALSTATE
458 : if (gDebugFlag4) {
459 : std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
460 : }
461 : #endif
462 0 : continue;
463 : }
464 : }
465 : }
466 4410 : if (MSRailSignal::storeVehicles() && store) {
467 4410 : MSRailSignal::blockingVehicles().push_back(lane->getLastAnyVehicle());
468 : }
469 : return true;
470 : }
471 : }
472 11625 : return false;
473 : }
474 :
475 :
476 : bool
477 8089119 : MSDriveWay::foeDriveWayApproached() const {
478 16321601 : for (const MSDriveWay* foeDW : myFoes) {
479 16244395 : if (foeDW->myOrigin != nullptr && foeDW->myOrigin->getApproaching().size() > 0) {
480 : #ifdef DEBUG_SIGNALSTATE
481 : if (gDebugFlag4) {
482 : std::cout << SIMTIME << " foeLink=" << foeDW->myOrigin->getDescription() << " approachedBy=" << foeDW->myOrigin->getApproaching().begin()->first->getID() << "\n";
483 : }
484 : #endif
485 : return true;
486 : }
487 : }
488 : return false;
489 : }
490 :
491 :
492 : bool
493 17591252 : MSDriveWay::foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const {
494 36203794 : for (const MSDriveWay* foeDW : myFoes) {
495 27616952 : if (!foeDW->myTrains.empty()) {
496 : #ifdef DEBUG_SIGNALSTATE
497 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
498 : std::cout << SIMTIME << " " << getID() << " foeDriveWay " << foeDW->getID() << " occupied ego=" << Named::getIDSecure(ego) << " foeVeh=" << toString(foeDW->myTrains) << "\n";
499 : }
500 : #endif
501 9054238 : if (foeDW->myTrains.size() == 1) {
502 9052012 : SUMOVehicle* foe = *foeDW->myTrains.begin();
503 9052012 : if (foe == ego) {
504 : #ifdef DEBUG_SIGNALSTATE
505 : if (gDebugFlag4 || DEBUG_HELPER(ego)) {
506 : std::cout << " ignore ego as foe '" << Named::getIDSecure(ego) << "\n";
507 : }
508 : #endif
509 49916 : continue;
510 : }
511 9028192 : if (hasJoin(ego, foe)) {
512 36 : continue;
513 : }
514 : }
515 9030382 : std::pair<bool, const MSDriveWay*> useSiding = canUseSiding(ego, foeDW);
516 : #ifdef DEBUG_SIGNALSTATE
517 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
518 : auto it = mySidings.find(foeDW);
519 : int numSidings = 0;
520 : if (it != mySidings.end()) {
521 : numSidings = it->second.size();
522 : }
523 : std::cout << " ego=" << Named::getIDSecure(ego) << " useSiding=" << useSiding.first << " sidingFoe=" << Named::getIDSecure(useSiding.second) << " numSidings=" << numSidings << "\n";
524 : }
525 : #endif
526 9030382 : if (useSiding.first) {
527 26060 : continue;
528 : } else {
529 9004322 : if (MSRailSignal::storeVehicles() && store) {
530 740 : for (SUMOVehicle* foe : foeDW->myTrains) {
531 370 : MSRailSignal::blockingVehicles().push_back(foe);
532 : }
533 370 : MSRailSignal::blockingDriveWays().push_back(foeDW);
534 : }
535 18011341 : for (const SUMOVehicle* foe : foeDW->myTrains) {
536 9007019 : occupied.push_back(const_cast<MSEdge*>(foe->getEdge()));
537 9007019 : MSEdge* bidi = const_cast<MSEdge*>(foe->getEdge()->getBidiEdge());
538 9007019 : if (bidi != nullptr) {
539 8491649 : occupied.push_back(bidi);
540 : }
541 : /// @todo: if foe occupies more than one edge we should add all of them to the occupied vector
542 : }
543 8292785 : if (ego != nullptr && MSGlobals::gTimeToTeleportRSDeadlock > 0
544 9282589 : && (ego->getWaitingTime() > ego->getVehicleType().getCarFollowModel().getStartupDelay() || !ego->isOnRoad())) {
545 : // if there is an occupied siding, it becomes part of the waitRelation
546 147820 : SUMOVehicle* foe = *(useSiding.second == nullptr ? foeDW : useSiding.second)->myTrains.begin();
547 147820 : const MSRailSignal* rs = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
548 147820 : MSRailSignalControl::getInstance().addWaitRelation(ego, rs, foe);
549 : }
550 9004322 : return true;
551 : }
552 18562714 : } else if (foeDW != this && isDepartDriveway() && !foeDW->isDepartDriveway()) {
553 16336 : if (foeDW->myOrigin->getApproaching().size() > 0) {
554 3359 : Approaching foeA = foeDW->myOrigin->getClosest();
555 3359 : const SUMOVehicle* foe = foeA.first;
556 3359 : if (foeA.second.dist < foe->getBrakeGap(true)) {
557 254 : MSRouteIterator firstIt = std::find(foe->getCurrentRouteEdge(), foe->getRoute().end(), foeDW->myRoute.front());
558 254 : if (firstIt != foe->getRoute().end()) {
559 254 : if (foeDW->match(firstIt, foe->getRoute().end())) {
560 203 : bool useSiding = canUseSiding(ego, foeDW).first;
561 : #ifdef DEBUG_SIGNALSTATE
562 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
563 : std::cout << SIMTIME << " " << getID() << " blocked by " << foeDW->getID() << " (approached by " << foe->getID() << ") useSiding=" << useSiding << "\n";
564 : }
565 : #endif
566 203 : if (useSiding) {
567 : //std::cout << SIMTIME << " " << getID() << " ego=" << ego->getID() << " foeDW=" << foeDW->getID() << " myFoes=" << toString(myFoes) << "\n";
568 115 : continue;
569 : } else {
570 88 : return true;
571 : }
572 : }
573 : }
574 : }
575 : }
576 : }
577 : }
578 8587938 : for (const std::set<const MSDriveWay*>& dlFoes : myDeadlocks) {
579 : bool allOccupied = true;
580 10551 : for (const MSDriveWay* dlFoe : dlFoes) {
581 7836 : if (dlFoe->myTrains.empty()) {
582 : allOccupied = false;
583 : //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck clear " << dlFoe->getID() << "\n";
584 : break;
585 : }
586 : }
587 3811 : if (allOccupied) {
588 : #ifdef DEBUG_SIGNALSTATE
589 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
590 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck " << joinNamedToString(dlFoes, " ") << "\n";
591 : }
592 : #endif
593 8974 : for (const MSDriveWay* dlFoe : dlFoes) {
594 6259 : MSRailSignal::blockingDriveWays().push_back(dlFoe);
595 : }
596 : return true;
597 : }
598 : }
599 : return false;
600 : }
601 :
602 :
603 : bool
604 9028192 : MSDriveWay::hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe) {
605 9028192 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
606 277635 : std::string joinVehicle = "";
607 277635 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
608 277635 : if (stop != nullptr) {
609 119114 : joinVehicle = stop->join;
610 : }
611 277635 : if (joinVehicle == "" && !ego->hasDeparted() && ego->getStops().size() > 1) {
612 : // check one more stop
613 5019 : auto it = ego->getStops().begin();
614 : std::advance(it, 1);
615 5019 : joinVehicle = it->pars.join;
616 : }
617 277635 : if (joinVehicle != "") {
618 : #ifdef DEBUG_SIGNALSTATE
619 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
620 : std::cout << " joinVehicle=" << joinVehicle << "\n";
621 : }
622 : #endif
623 345 : if (foe->getID() == joinVehicle && foe->isStopped()) {
624 : #ifdef DEBUG_SIGNALSTATE
625 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
626 : std::cout << " ignore join-target '" << joinVehicle << "\n";
627 : }
628 : #endif
629 : return true;
630 : }
631 : }
632 :
633 277611 : if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
634 : #ifdef DEBUG_SIGNALSTATE
635 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
636 : std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
637 : }
638 : #endif
639 : return true;
640 : }
641 : }
642 : return false;
643 : }
644 :
645 :
646 : std::pair<bool, const MSDriveWay*>
647 9062096 : MSDriveWay::canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, const MSEdge* recurseSidingEnd) const {
648 : auto it = mySidings.find(foe);
649 9062096 : if (it != mySidings.end()) {
650 69329 : for (auto siding : it->second) {
651 : // assume siding is usuable when computing state for unapproached signal (ego == nullptr)
652 69129 : if (ego == nullptr || siding.length >= ego->getLength()) {
653 : // if the siding is already "reserved" by another vehicle we cannot use it here
654 59204 : const MSEdge* sidingEnd = myRoute[siding.end];
655 : bool checkNext = false;
656 138368 : for (MSDriveWay* sidingApproach : myEndingDriveways[sidingEnd]) {
657 97861 : if (!sidingApproach->myTrains.empty() && *sidingApproach->myTrains.begin() == ego && sidingEnd == recurseSidingEnd) {
658 : // check next siding if if exists
659 : checkNext = true;
660 : #ifdef DEBUG_SIGNALSTATE
661 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
662 : std::cout << " checkNext\n";
663 : }
664 : #endif
665 3606 : continue;
666 : }
667 94255 : if (!sidingApproach->myTrains.empty() && *sidingApproach->myTrains.begin() != ego) {
668 : // possibly the foe vehicle can use the other part of the siding
669 24739 : if (recurseSidingEnd == nullptr) {
670 : const SUMOVehicle* foeVeh = nullptr;
671 17217 : if (!foe->myTrains.empty()) {
672 17088 : foeVeh = *foe->myTrains.begin();
673 129 : } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
674 129 : foeVeh = foe->myOrigin->getClosest().first;
675 : }
676 17217 : if (foeVeh == nullptr) {
677 0 : WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
678 0 : continue;
679 : }
680 17217 : const MSDriveWay* foe2 = foe->isSubDriveWay() ? foe->myParent : foe;
681 17217 : const MSDriveWay* this2 = foe2->getFoeOrSubFoe(this);
682 : #ifdef DEBUG_SIGNALSTATE
683 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
684 : std::cout << " foe2=" << foe2->getID() << " this2=" << this2->getID() << "\n";
685 : }
686 : #endif
687 17217 : if (this2 != nullptr && foe2->canUseSiding(foeVeh, this2, sidingEnd).first) {
688 6042 : continue;
689 : }
690 : }
691 : // possibly the foe vehicle
692 : // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation
693 : #ifdef DEBUG_SIGNALSTATE
694 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
695 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
696 : << " foeVeh=" << toString(foe->myTrains)
697 : << " sidingEnd=" << sidingEnd->getID() << " sidingApproach=" << sidingApproach->getID() << " approaching=" << toString(sidingApproach->myTrains) << "\n";
698 : }
699 : #endif
700 18697 : return std::make_pair(false, sidingApproach);
701 : }
702 : }
703 : // vehicles approaching intermediate driveways could also make the siding unusable but would not show up as sidingApproaches
704 45756 : for (int i : siding.intermediateEnds) {
705 8283 : const MSEdge* intermediateEnd = myRoute[i];
706 15528 : for (MSDriveWay* intermediateApproach : myEndingDriveways[intermediateEnd]) {
707 : if (!intermediateApproach->myTrains.empty()
708 10279 : && (*intermediateApproach->myTrains.begin() != ego || intermediateEnd == recurseSidingEnd)) {
709 : SUMOVehicle* onApproach = *intermediateApproach->myTrains.begin();
710 3335 : if (std::find(onApproach->getCurrentRouteEdge(), onApproach->getRoute().end(), sidingEnd) == onApproach->getRoute().end()) {
711 : // intermediate vehicle does not make use of the siding
712 101 : continue;
713 : }
714 : // possibly the foe vehicle can use the other part of the siding
715 3234 : if (recurseSidingEnd == nullptr) {
716 : const SUMOVehicle* foeVeh = nullptr;
717 851 : if (!foe->myTrains.empty()) {
718 822 : foeVeh = *foe->myTrains.begin();
719 29 : } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
720 29 : foeVeh = foe->myOrigin->getClosest().first;
721 : }
722 851 : if (foeVeh == nullptr) {
723 0 : WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
724 0 : continue;
725 : }
726 851 : const MSDriveWay* foe2 = foe->isSubDriveWay() ? foe->myParent : foe;
727 851 : const MSDriveWay* this2 = foe2->getFoeOrSubFoe(this);
728 851 : if (this2 != nullptr && foe2->canUseSiding(foeVeh, this2, intermediateEnd).first) {
729 200 : continue;
730 : }
731 : }
732 : // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation
733 : #ifdef DEBUG_SIGNALSTATE
734 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
735 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
736 : << " foeVeh=" << toString(foe->myTrains)
737 : << " sidingEnd=" << sidingEnd->getID() << " intermediateApproach=" << intermediateApproach->getID() << " approaching=" << toString(intermediateApproach->myTrains) << "\n";
738 : }
739 : #endif
740 3034 : return std::make_pair(false, intermediateApproach);
741 : }
742 : }
743 : }
744 37473 : if (checkNext) {
745 3606 : continue;
746 : }
747 : #ifdef DEBUG_SIGNALSTATE
748 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
749 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
750 : << " foeVeh=" << toString(foe->myTrains)
751 : << " sidingEnd=" << sidingEnd->getID() << " usable\n";
752 : }
753 : #endif
754 33867 : return std::make_pair(true, nullptr);
755 : }
756 : }
757 : }
758 : #ifdef DEBUG_SIGNALSTATE
759 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
760 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID() << " noSidings\n";
761 : }
762 : #endif
763 9006498 : return std::make_pair(false, nullptr);
764 : }
765 :
766 : bool
767 23783 : MSDriveWay::overlap(const MSDriveWay& other) const {
768 43418 : for (int i = 0; i < myCoreSize; i++) {
769 415345 : for (int j = 0; j < other.myCoreSize; j++) {
770 395710 : const MSEdge* edge = myRoute[i];
771 395710 : const MSEdge* edge2 = other.myRoute[j];
772 : if (edge->getToJunction() == edge2->getToJunction()
773 374507 : || edge->getToJunction() == edge2->getFromJunction()
774 768201 : || edge->getFromJunction() == edge2->getFromJunction()) {
775 : // XXX might be rail_crossing with parallel tracks
776 : return true;
777 : }
778 : }
779 : }
780 : return false;
781 : }
782 :
783 :
784 : bool
785 80184 : MSDriveWay::flankConflict(const MSDriveWay& other) const {
786 276830 : for (const MSLane* lane : myForward) {
787 1139952 : for (const MSLane* lane2 : other.myForward) {
788 933280 : if (lane == lane2) {
789 : return true;
790 : }
791 : }
792 3014719 : for (const MSLane* lane2 : other.myBidi) {
793 2813396 : if (lane == lane2) {
794 6066 : if (bidiBlockedBy(other)) {
795 : // it's only a deadlock if both trains block symmetrically
796 : return true;
797 : }
798 : }
799 : }
800 7215761 : for (const MSLane* lane2 : other.myBidiExtended) {
801 7019115 : if (lane == lane2) {
802 23264 : if (bidiBlockedBy(other)) {
803 : // it's only a deadlock if both trains block symmetrically
804 : return true;
805 : }
806 : }
807 : }
808 : }
809 : return false;
810 : }
811 :
812 :
813 : bool
814 68289 : MSDriveWay::crossingConflict(const MSDriveWay& other) const {
815 251582 : for (const MSLane* lane : myForward) {
816 860197 : for (const MSLane* lane2 : other.myForward) {
817 676904 : if (lane->isNormal() && lane2->isNormal() && lane->getEdge().getToJunction() == lane2->getEdge().getToJunction()) {
818 : return true;
819 : }
820 : }
821 : }
822 60086 : if (myOrigin != nullptr && other.myOrigin != nullptr
823 52238 : && myOrigin->getJunction() == other.myOrigin->getJunction()
824 : //&& myForward.front()->isInternal() && other.myForward.front()->isInternal()
825 1862 : && myOrigin->getJunction()->getLogic() != nullptr
826 67946 : && myOrigin->getJunction()->getLogic()->getFoesFor(myOrigin->getIndex()).test(other.myOrigin->getIndex())) {
827 : // switch/crossing is also a rail_signal (direct control)
828 133 : if (!(myForward.front()->isInternal() && other.myForward.front()->isInternal())) {
829 34 : return false;
830 : }
831 : return true;
832 : }
833 65951 : if (other.myOrigin != nullptr && other.myForward.front()->isInternal()) {
834 154897 : for (int i = 0; i < (int)myForward.size() - 1; i++) {
835 99182 : const MSLane* lane = myForward[i];
836 99182 : if (lane->getToJunction() == other.myOrigin->getJunction()) {
837 58 : const MSLane* next = myForward[i + 1];
838 58 : const MSLink* link = lane->getLinkTo(next);
839 58 : if (link && link->getTLLogic() == nullptr) {
840 : // switch/crossing is also a rail_signal (direct control) but own link is uncontrolled
841 58 : if (lane->getToJunction()->getLogic() != nullptr
842 58 : && lane->getToJunction()->getLogic()->getFoesFor(link->getIndex()).test(other.myOrigin->getIndex())) {
843 : // and links are in conflict
844 : return true;
845 : }
846 : }
847 : }
848 : }
849 : }
850 : return false;
851 : }
852 :
853 :
854 : bool
855 30493 : MSDriveWay::bidiBlockedBy(const MSDriveWay& other) const {
856 537446 : for (const MSLane* lane : myBidi) {
857 1962778 : for (const MSLane* lane2 : other.myForward) {
858 1455825 : if (lane == lane2) {
859 : return true;
860 : }
861 : }
862 : }
863 542821 : for (const MSLane* lane : myBidiExtended) {
864 1851871 : for (const MSLane* lane2 : other.myForward) {
865 1333496 : if (lane == lane2) {
866 4330 : if (overlap(other)) {
867 : return true;
868 : }
869 : }
870 : }
871 : }
872 : return false;
873 : }
874 :
875 :
876 : bool
877 17551 : MSDriveWay::bidiBlockedByEnd(const MSDriveWay& other) const {
878 17551 : const MSLane* end = other.myForward.back();
879 152095 : for (const MSLane* lane : myBidi) {
880 140503 : if (lane == end) {
881 : return true;
882 : }
883 : }
884 98963 : for (const MSLane* lane : myBidiExtended) {
885 90301 : if (lane == end) {
886 2930 : if (overlap(other)) {
887 : return true;
888 : }
889 : }
890 : }
891 : return false;
892 : }
893 :
894 : bool
895 6114 : MSDriveWay::forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck) {
896 : int i = 0;
897 64809 : for (const MSEdge* edge2 : other.myRoute) {
898 63989 : if (i == other.myCoreSize) {
899 : return false;
900 : }
901 63989 : i++;
902 63989 : if (edge2 == myForward.front()->getNextNormal() && !secondCheck) {
903 : // foe should not pass from behind through our own forward section
904 : return false;
905 : }
906 : if (forward.count(edge2->getBidiEdge()) != 0) {
907 : return true;
908 : }
909 : }
910 : return false;
911 : }
912 :
913 : void
914 9380 : MSDriveWay::writeBlocks(OutputDevice& od) const {
915 16463 : od.openTag(isSubDriveWay() ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
916 9380 : od.writeAttr(SUMO_ATTR_ID, myID);
917 9380 : od.writeAttr(SUMO_ATTR_VEHICLE, myFirstVehicle);
918 9380 : od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
919 9380 : if (myCoreSize != (int)myRoute.size()) {
920 0 : od.writeAttr("core", myCoreSize);
921 : }
922 9380 : od.openTag("forward");
923 9380 : od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
924 18760 : od.closeTag();
925 9380 : if (!isSubDriveWay()) {
926 7083 : od.openTag("bidi");
927 7083 : od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
928 7083 : if (myBidiExtended.size() > 0) {
929 2182 : od.lf();
930 2182 : od << " ";
931 4364 : od.writeAttr("deadlockCheck", toString(myBidiExtended));
932 : }
933 7083 : od.closeTag();
934 7083 : od.openTag("flank");
935 7083 : od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
936 7083 : od.closeTag();
937 :
938 14166 : od.openTag("conflictLinks");
939 :
940 : std::vector<std::string> signals;
941 11582 : for (MSLink* link : myConflictLinks) {
942 8998 : signals.push_back(getTLLinkID(link));
943 : }
944 7083 : od.writeAttr("signals", joinToStringSorting(signals, " "));
945 14166 : od.closeTag();
946 :
947 : std::vector<std::string> foes;
948 27147 : for (MSDriveWay* dw : myFoes) {
949 20064 : foes.push_back(dw->myID);
950 : }
951 7083 : if (foes.size() > 0) {
952 6916 : od.openTag("foes");
953 6916 : od.writeAttr("driveWays", joinToStringSorting(foes, " "));
954 13832 : od.closeTag();
955 : }
956 8751 : for (auto item : mySidings) {
957 1668 : od.openTag("sidings");
958 1668 : od.writeAttr("foe", item.first->getID());
959 4056 : for (auto siding : item.second) {
960 2388 : od.openTag("siding");
961 2388 : od.writeAttr("start", myRoute[siding.start]->getID());
962 2388 : od.writeAttr("end", myRoute[siding.end]->getID());
963 2388 : od.writeAttr("length", siding.length);
964 2388 : if (siding.intermediateEnds.size() > 0) {
965 : std::vector<std::string> endEdges;
966 1770 : for (int i : siding.intermediateEnds) {
967 983 : endEdges.push_back(myRoute[i]->getID());
968 : }
969 787 : od.writeAttr("intermediateEnds", endEdges);
970 787 : }
971 4776 : od.closeTag();
972 : }
973 3336 : od.closeTag();
974 : }
975 7176 : for (auto item : myDeadlocks) {
976 93 : od.openTag("deadlock");
977 93 : od.writeAttr("foes", joinNamedToStringSorting(item, " "));
978 186 : od.closeTag();
979 : }
980 7083 : }
981 18760 : od.closeTag(); // driveWay
982 :
983 11677 : for (const MSDriveWay* sub : mySubDriveWays) {
984 2297 : sub->writeBlocks(od);
985 : }
986 : #ifdef DRIVEWAY_SANITY_CHECK
987 9380 : std::set<MSDriveWay*> uFoes(myFoes.begin(), myFoes.end());
988 9380 : if (uFoes.size() != myFoes.size()) {
989 0 : WRITE_WARNINGF("Duplicate foes in driveway '%'", getID());
990 :
991 : }
992 : #endif
993 9380 : }
994 :
995 :
996 : void
997 1122 : MSDriveWay::writeBlockVehicles(OutputDevice& od) const {
998 2006 : od.openTag(isSubDriveWay() ? "subDriveWay" : "driveWay");
999 1122 : od.writeAttr(SUMO_ATTR_ID, myID);
1000 3387 : for (const VehicleEvent& ve : myVehicleEvents) {
1001 3392 : od.openTag(ve.isEntry ? "entry" : "exit");
1002 2265 : od.writeAttr(SUMO_ATTR_ID, ve.id);
1003 2265 : od.writeAttr(SUMO_ATTR_TIME, time2string(ve.time));
1004 2265 : od.writeAttr("reason", Notifications.getString(ve.reason));
1005 4530 : od.closeTag(); // event
1006 : }
1007 2244 : od.closeTag(); // driveWay
1008 :
1009 1360 : for (const MSDriveWay* sub : mySubDriveWays) {
1010 238 : sub->writeBlockVehicles(od);
1011 : }
1012 1122 : }
1013 :
1014 :
1015 : void
1016 9283 : MSDriveWay::buildRoute(const MSLink* origin,
1017 : MSRouteIterator next, MSRouteIterator end,
1018 : LaneVisitedMap& visited,
1019 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) {
1020 9283 : double length = 0;
1021 : bool seekForwardSignal = true;
1022 : bool seekBidiSwitch = true;
1023 : bool foundUnsafeSwitch = false;
1024 9283 : MSLane* toLane = origin ? origin->getViaLaneOrLane() : (*next)->getLanes()[0];
1025 24052 : const std::string warnID = origin ? "rail signal " + getClickableTLLinkID(origin) : "insertion lane '" + toLane->getID() + "'";
1026 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1027 : if (gDebugFlag4) std::cout << "buildRoute origin=" << warnID << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1028 : << " visited=" << formatVisitedMap(visited) << "\n";
1029 : #endif
1030 : while (true) {
1031 130246 : if (length > MSGlobals::gMaxRailSignalBlockLength) {
1032 : // typical block length in germany on main lines is 3-5km on branch lines up to 7km
1033 : // special branches that are used by one train exclusively could also be up to 20km in length
1034 : // minimum block size in germany is 37.5m (LZB)
1035 : // larger countries (USA, Russia) might see blocks beyond 20km)
1036 242 : if (seekForwardSignal && myBlockLengthWarnings.count(myRoute.front()) == 0) {
1037 282 : WRITE_WARNINGF("Block after % exceeds maximum length (stopped searching after edge '%' (length=%m).",
1038 : warnID, toLane->getEdge().getID(), length);
1039 : myBlockLengthWarnings.insert(myRoute.front());
1040 : }
1041 242 : myAbortedBuild = true;
1042 : // length exceeded
1043 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1044 : if (gDebugFlag4) {
1045 : std::cout << " abort: length=" << length << "\n";
1046 : }
1047 : #endif
1048 9283 : return;
1049 : }
1050 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1051 : if (gDebugFlag4) {
1052 : std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1053 : }
1054 : #endif
1055 130004 : const MSEdge* current = &toLane->getEdge();
1056 130004 : if (current->isNormal()) {
1057 69894 : myRoute.push_back(current);
1058 69894 : if (next != end) {
1059 : next++;
1060 : }
1061 : }
1062 130004 : appendMapIndex(visited, toLane);
1063 130004 : length += toLane->getLength();
1064 130004 : MSLane* bidi = toLane->getBidiLane();
1065 130004 : if (seekForwardSignal) {
1066 37417 : if (!foundUnsafeSwitch) {
1067 37417 : myForward.push_back(toLane);
1068 37417 : if (toLane->isNormal()) {
1069 21916 : myForwardEdgeCount++;
1070 : }
1071 37417 : if (myForward.size() == 1) {
1072 9283 : myLane = toLane;
1073 9283 : if (MSGlobals::gUseMesoSim) {
1074 3030 : MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(myLane->getEdge());
1075 3030 : s->addDetector(this, myLane->getIndex());
1076 : } else {
1077 6253 : toLane->addMoveReminder(this, false);
1078 : }
1079 : }
1080 : }
1081 92587 : } else if (bidi == nullptr) {
1082 29774 : if (toLane->isInternal() && toLane->getIncomingLanes().front().viaLink->isTurnaround()) {
1083 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1084 : if (gDebugFlag4) {
1085 : std::cout << " continue bidiSearch beyond turnaround\n";
1086 : }
1087 : #endif
1088 : } else {
1089 : seekBidiSwitch = false;
1090 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1091 : if (gDebugFlag4) {
1092 : std::cout << " noBidi, abort search for bidiSwitch\n";
1093 : }
1094 : #endif
1095 : }
1096 : }
1097 130004 : if (bidi != nullptr) {
1098 83953 : if (!seekForwardSignal && !foundUnsafeSwitch && bidi->isNormal()) {
1099 : // look for switch that could protect from oncoming vehicles
1100 24546 : for (const MSLink* const link : bidi->getLinkCont()) {
1101 13803 : if (link->getDirection() == LinkDirection::TURN) {
1102 531 : continue;
1103 : }
1104 26386 : if (!myBidi.empty() && link->getViaLaneOrLane() != myBidi.back()) {
1105 2426 : myCoreSize = (int)myRoute.size() - 1;
1106 2426 : MSLink* used = const_cast<MSLink*>(bidi->getLinkTo(myBidi.back()));
1107 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1108 : if (gDebugFlag4) {
1109 : std::cout << " found unsafe switch " << link->getDescription() << " (used=" << (used == nullptr ? "NULL" : used->getDescription()) << ")\n";
1110 : }
1111 : #endif
1112 : // trains along our route beyond this switch might create deadlock
1113 : foundUnsafeSwitch = true;
1114 : // the switch itself must still be guarded to ensure safety
1115 2426 : if (used != nullptr) {
1116 : // possibly nullptr if there was an intermediate section of unidirectional edges
1117 : flankSwitches.insert(used);
1118 : }
1119 : break;
1120 : }
1121 : }
1122 : }
1123 81527 : if (foundUnsafeSwitch) {
1124 40582 : myBidiExtended.push_back(bidi);
1125 : } else {
1126 43371 : myBidi.push_back(bidi);
1127 : }
1128 : }
1129 130004 : const std::vector<MSLink*>& links = toLane->getLinkCont();
1130 130004 : toLane = nullptr;
1131 137072 : for (const MSLink* const link : links) {
1132 128419 : if ((next != end && &link->getLane()->getEdge() == *next)) {
1133 121351 : toLane = link->getViaLaneOrLane();
1134 121351 : if (link->getTLLogic() != nullptr && link->getTLIndex() >= 0 && link->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
1135 28477 : if (link == origin) {
1136 388 : if (seekForwardSignal) {
1137 0 : WRITE_WARNINGF(TL("Found circular block after % (% edges, length %)"), warnID, toString(myRoute.size()), toString(length));
1138 : }
1139 : //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1140 388 : myAbortedBuild = true;
1141 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1142 : if (gDebugFlag4) {
1143 : std::cout << " abort: found circle\n";
1144 : }
1145 : #endif
1146 388 : return;
1147 : }
1148 : seekForwardSignal = false;
1149 28089 : myFoundSignal = true;
1150 : seekBidiSwitch = bidi != nullptr;
1151 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1152 : if (gDebugFlag4) {
1153 : std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1154 : }
1155 : #endif
1156 : }
1157 : //if (links.size() > 1 && !foundUnsafeSwitch) {
1158 120963 : if (isSwitch(link)) {
1159 : // switch on driveway
1160 : //std::cout << "mySwitchDriveWays " << getID() << " link=" << link->getDescription() << "\n";
1161 74863 : mySwitchDriveWays[link].push_back(this);
1162 : }
1163 120963 : if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1164 : // reversal on driveway
1165 1777 : myReversalDriveWays[current].push_back(this);
1166 1777 : myReversals.push_back(current);
1167 : }
1168 : break;
1169 : }
1170 : }
1171 129616 : if (toLane == nullptr) {
1172 8653 : if (next != end) {
1173 : // no connection found, jump to next route edge
1174 : toLane = (*next)->getLanes()[0];
1175 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1176 : if (gDebugFlag4) {
1177 : std::cout << " abort: turn-around or jump\n";
1178 : }
1179 : #endif
1180 90 : myFoundJump = true;
1181 90 : return;
1182 : } else {
1183 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1184 : if (gDebugFlag4) {
1185 : std::cout << " abort: no next lane available\n";
1186 : }
1187 : #endif
1188 8563 : myTerminateRoute = true;
1189 8563 : return;
1190 : }
1191 : }
1192 120963 : }
1193 : myBidiEnded = !seekBidiSwitch;
1194 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1195 : if (gDebugFlag4) {
1196 : std::cout << " normalEnd myBidiEnded=" << myBidiEnded << "\n";
1197 : }
1198 : #endif
1199 : }
1200 :
1201 :
1202 : bool
1203 133884 : MSDriveWay::isSwitch(const MSLink* link) {
1204 260137 : for (const MSLink* other : link->getLaneBefore()->getNormalPredecessorLane()->getLinkCont()) {
1205 146779 : if (other->getLane() != link->getLane() && !other->isTurnaround()) {
1206 : return true;
1207 : }
1208 : }
1209 176353 : for (auto ili : link->getLane()->getIncomingLanes()) {
1210 127595 : if (ili.viaLink != link && !ili.viaLink->isTurnaround()) {
1211 : return true;
1212 : }
1213 : }
1214 48758 : const MSLane* bidi = link->getLane()->getBidiLane();
1215 48758 : if (bidi != nullptr) {
1216 71762 : for (const MSLink* other : bidi->getLinkCont()) {
1217 37083 : if (other->getLane() != link->getLaneBefore()->getNormalPredecessorLane()->getBidiLane() && !other->isTurnaround()) {
1218 : return true;
1219 : }
1220 : }
1221 : }
1222 : return false;
1223 : }
1224 :
1225 :
1226 : void
1227 37132 : MSDriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited,
1228 : bool allFoes, bool movingBlock, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1229 : #ifdef DEBUG_CHECK_FLANKS
1230 : if (gDebugFlag4) {
1231 : std::cout << " checkFlanks lanes=" << toString(lanes) << " allFoes=" << allFoes << "\n";
1232 : }
1233 : #endif
1234 21944 : const MSLink* reverseOriginLink = originLink != nullptr && originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1235 49000 : ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1236 : : nullptr;
1237 : //std::cout << " originLink=" << originLink->getDescription() << "\n";
1238 11868 : if (reverseOriginLink != nullptr) {
1239 11868 : reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1240 : //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1241 : }
1242 161551 : for (int i = 0; i < (int)lanes.size(); i++) {
1243 124419 : const MSLane* lane = lanes[i];
1244 124419 : const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1245 124419 : const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1246 124419 : if (lane->isInternal()) {
1247 53369 : continue;
1248 : }
1249 147455 : for (auto ili : lane->getIncomingLanes()) {
1250 86942 : if (ili.viaLink == originLink
1251 75457 : || ili.viaLink == reverseOriginLink
1252 72153 : || ili.viaLink->getDirection() == LinkDirection::TURN
1253 65987 : || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND
1254 142392 : || (originLink == nullptr && i == 0 && movingBlock)) {
1255 10537 : continue;
1256 : }
1257 65868 : if (ili.lane != prev && ili.lane != next) {
1258 : #ifdef DEBUG_CHECK_FLANKS
1259 : if (gDebugFlag4) {
1260 : 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";
1261 : }
1262 : #endif
1263 : flankSwitches.insert(ili.viaLink);
1264 52984 : } else if (allFoes) {
1265 : // link is part of the driveway, find foes that cross the driveway without entering
1266 16078 : checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1267 : }
1268 : }
1269 : }
1270 37132 : }
1271 :
1272 :
1273 : void
1274 16078 : MSDriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1275 : #ifdef DEBUG_CHECK_FLANKS
1276 : if (gDebugFlag4) {
1277 : std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1278 : }
1279 : #endif
1280 : const MSJunction* junction = dwLink->getJunction();
1281 16078 : if (junction == nullptr) {
1282 : return; // unregulated junction;
1283 : }
1284 15998 : const MSJunctionLogic* logic = junction->getLogic();
1285 15998 : if (logic == nullptr) {
1286 : return; // unregulated junction;
1287 : }
1288 84713 : for (const MSEdge* in : junction->getIncoming()) {
1289 68783 : if (in->isInternal()) {
1290 34855 : continue;
1291 : }
1292 68274 : for (MSLane* inLane : in->getLanes()) {
1293 34346 : const MSLane* inBidi = inLane->getBidiLane();
1294 46784 : if (isRailwayOrShared(inLane->getPermissions()) && visited.count(inLane) == 0 && (inBidi == nullptr || visited.count(inBidi) == 0)) {
1295 9495 : for (MSLink* link : inLane->getLinkCont()) {
1296 4943 : if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1297 12764 : && visited.count(link->getLane()) == 0) {
1298 : #ifdef DEBUG_CHECK_FLANKS
1299 : if (gDebugFlag4) {
1300 : std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1301 : }
1302 : #endif
1303 672 : if (link->getViaLane() == nullptr) {
1304 : flankSwitches.insert(link);
1305 : } else {
1306 : flankSwitches.insert(link->getViaLane()->getLinkCont().front());
1307 : }
1308 : }
1309 : }
1310 : }
1311 : }
1312 : }
1313 : }
1314 :
1315 : void
1316 16042 : MSDriveWay::findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank) {
1317 : #ifdef DEBUG_CHECK_FLANKS
1318 : if (gDebugFlag4) {
1319 : std::cout << " findFlankProtection link=" << link->getDescription() << " origLink=" << origLink->getDescription() << "\n";
1320 : }
1321 : #endif
1322 16042 : if (link->getCorrespondingEntryLink()->getTLLogic() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1323 2286 : MSLink* entry = const_cast<MSLink*>(link->getCorrespondingEntryLink());
1324 : // guarded by signal
1325 : #ifdef DEBUG_CHECK_FLANKS
1326 : if (gDebugFlag4) {
1327 : std::cout << " flank guarded by " << entry->getTLLogic()->getID() << "\n";
1328 : }
1329 : #endif
1330 : // @note, technically it's enough to collect links from foe driveways
1331 : // but this also adds "unused" conflict links which may aid comprehension
1332 2286 : myConflictLinks.push_back(entry);
1333 2286 : addFoes(entry);
1334 : } else {
1335 : const MSLane* lane = link->getLaneBefore();
1336 : std::vector<MSLink*> predLinks;
1337 27522 : for (auto ili : lane->getIncomingLanes()) {
1338 13766 : if (!ili.viaLink->isTurnaround()) {
1339 13363 : predLinks.push_back(ili.viaLink);
1340 : }
1341 : }
1342 13756 : if (predLinks.size() > 1) {
1343 : // this is a switch
1344 : #ifdef DEBUG_ADD_FOES
1345 : if (gDebugFlag4) {
1346 : std::cout << " predecessors of " << link->getDescription() << " isSwitch\n";
1347 : }
1348 : #endif
1349 663 : for (MSLink* pred : predLinks) {
1350 442 : addSwitchFoes(pred);
1351 : }
1352 13535 : } else if (predLinks.size() == 1) {
1353 12921 : if (isSwitch(link)) {
1354 11419 : addSwitchFoes(link);
1355 : } else {
1356 : // continue upstream via single predecessor
1357 1502 : findFlankProtection(predLinks.front(), origLink, flank);
1358 : }
1359 : }
1360 : // check for insertions
1361 13756 : if (myDepartureDriveways.count(&lane->getEdge()) != 0) {
1362 354 : for (MSDriveWay* foe : myDepartureDriveways[&lane->getEdge()]) {
1363 183 : if (flankConflict(*foe) || crossingConflict(*foe)) {
1364 : #ifdef DEBUG_ADD_FOES
1365 : if (gDebugFlag4) {
1366 : std::cout << " foe " << foe->getID() << " departs on flank=" << lane->getID() << "\n";
1367 : }
1368 : #endif
1369 129 : myFoes.push_back(foe);
1370 : } else {
1371 : #ifdef DEBUG_ADD_FOES
1372 : if (gDebugFlag4) {
1373 : std::cout << " cand foe " << foe->getID() << " departs on flank=" << lane->getID() << " rejected\n";
1374 : }
1375 : #endif
1376 : }
1377 : }
1378 : }
1379 13756 : }
1380 16042 : }
1381 :
1382 :
1383 : void
1384 11861 : MSDriveWay::addSwitchFoes(MSLink* link) {
1385 : auto it = mySwitchDriveWays.find(link);
1386 11861 : if (it != mySwitchDriveWays.end()) {
1387 : #ifdef DEBUG_ADD_FOES
1388 : if (gDebugFlag4) {
1389 : std::cout << " driveway " << myID << " addSwitchFoes for link " << link->getDescription() << "\n";
1390 : }
1391 : #endif
1392 36511 : for (MSDriveWay* foe : it->second) {
1393 32101 : if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1394 : #ifdef DEBUG_ADD_FOES
1395 : if (gDebugFlag4) std::cout << " foe=" << foe->myID
1396 : << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this)
1397 : << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1398 : #endif
1399 4757 : myFoes.push_back(foe);
1400 : } else {
1401 : #ifdef DEBUG_ADD_FOES
1402 : if (gDebugFlag4) {
1403 : std::cout << " cand=" << foe->myID << "\n";
1404 : }
1405 : #endif
1406 : }
1407 : }
1408 : }
1409 11861 : }
1410 :
1411 :
1412 : MSDriveWay*
1413 9283 : MSDriveWay::buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end) {
1414 : // collect lanes and links that are relevant for setting this signal for the current driveWay
1415 : // For each driveway we collect
1416 : // - conflictLanes (signal must be red if any conflict lane is occupied)
1417 : // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
1418 : // - that cannot break in time (arrivalSpeedBraking > 0)
1419 : // - approached by a vehicle with higher switching priority (see #3941)
1420 : // These objects are construct in steps:
1421 : //
1422 : // forwardBlock
1423 : // - search forward recursive from outgoing lane until controlled railSignal link found
1424 : // -> add all found lanes to conflictLanes
1425 : //
1426 : // bidiBlock (if any forwardBlock edge has bidi edge)
1427 : // - search bidi backward recursive until first switch
1428 : // - from switch search backward recursive all other incoming until controlled rail signal link
1429 : // -> add final links to conflictLinks
1430 : //
1431 : // flanks
1432 : // - search backward recursive from flanking switches
1433 : // until controlled railSignal link or protecting switch is found
1434 : // -> add all found lanes to conflictLanes
1435 : // -> add final links to conflictLinks
1436 9283 : MSDriveWay* dw = new MSDriveWay(link, id);
1437 : LaneVisitedMap visited;
1438 : std::vector<const MSLane*> before;
1439 9283 : MSLane* fromBidi = nullptr;
1440 9283 : if (link != nullptr) {
1441 5486 : appendMapIndex(visited, link->getLaneBefore());
1442 5486 : fromBidi = link->getLaneBefore()->getBidiLane();
1443 : }
1444 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitches; // list of switches that threaten the driveway and for which protection must be found
1445 :
1446 9283 : if (fromBidi != nullptr) {
1447 3049 : before.push_back(fromBidi);
1448 : }
1449 : #ifdef DEBUG_BUILD_DRIVEWAY
1450 : gDebugFlag4 = DEBUG_COND_DW(dw);
1451 : #endif
1452 9283 : dw->buildRoute(link, first, end, visited, flankSwitches);
1453 9283 : dw->myCoreSize = (int)dw->myRoute.size();
1454 :
1455 9283 : MSRailSignal* rs = link ? const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(link->getTLLogic())) : nullptr;
1456 9283 : const bool movingBlock = (rs && rs->isMovingBlock()) || (!rs &&
1457 13080 : (OptionsCont::getOptions().getBool("railsignal-moving-block")
1458 3668 : || MSRailSignalControl::isMovingBlock((*first)->getPermissions())));
1459 :
1460 9283 : dw->checkFlanks(link, dw->myForward, visited, true, movingBlock, flankSwitches);
1461 9283 : dw->checkFlanks(link, dw->myBidi, visited, false, movingBlock, flankSwitches);
1462 9283 : dw->checkFlanks(link, before, visited, true, movingBlock, flankSwitches);
1463 19494 : for (MSLink* fsLink : flankSwitches) {
1464 : #ifdef DEBUG_ADD_FOES
1465 : if (DEBUG_COND_DW(dw)) {
1466 : std::cout << " fsLink=" << fsLink->getDescription() << "\n";
1467 : }
1468 : #endif
1469 10211 : dw->findFlankProtection(fsLink, fsLink, dw->myFlank);
1470 : }
1471 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitchesBidiExtended;
1472 9283 : dw->checkFlanks(link, dw->myBidiExtended, visited, false, movingBlock, flankSwitchesBidiExtended);
1473 13612 : for (MSLink* const flink : flankSwitchesBidiExtended) {
1474 : #ifdef DEBUG_ADD_FOES
1475 : if (DEBUG_COND_DW(dw)) {
1476 : std::cout << " fsLinkExtended=" << flink->getDescription() << "\n";
1477 : }
1478 : #endif
1479 4329 : dw->findFlankProtection(flink, flink, dw->myBidiExtended);
1480 : }
1481 : #ifdef DEBUG_BUILD_DRIVEWAY
1482 : if (DEBUG_COND_DW(dw)) {
1483 : std::cout << SIMTIME << " buildDriveWay " << dw->myID << " link=" << (link == nullptr ? "NULL" : link->getDescription())
1484 : << "\n route=" << toString(dw->myRoute)
1485 : << "\n forward=" << toString(dw->myForward)
1486 : << "\n bidi=" << toString(dw->myBidi)
1487 : << "\n bidiEx=" << toString(dw->myBidiExtended)
1488 : << "\n flank=" << toString(dw->myFlank)
1489 : << "\n flankSwitch=" << MSRailSignal::describeLinks(std::vector<MSLink*>(flankSwitches.begin(), flankSwitches.end()))
1490 : << "\n coreSize=" << dw->myCoreSize
1491 : << "\n";
1492 : }
1493 : #endif
1494 9283 : if (!rs || !rs->isMovingBlock()) {
1495 9172 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myForward.begin(), dw->myForward.end());
1496 : }
1497 9283 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myBidi.begin(), dw->myBidi.end());
1498 9283 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myFlank.begin(), dw->myFlank.end());
1499 9283 : dw->addBidiFoes(rs, false);
1500 9283 : dw->addBidiFoes(rs, true);
1501 9283 : if (!movingBlock) {
1502 : // add driveways that start on the same signal / lane
1503 8959 : dw->addParallelFoes(link, *first);
1504 : }
1505 : // add driveways that reverse along this driveways route
1506 9283 : dw->addReversalFoes(movingBlock);
1507 : // make foes unique and symmetrical
1508 9283 : std::set<MSDriveWay*, ComparatorNumericalIdLess> uniqueFoes(dw->myFoes.begin(), dw->myFoes.end());
1509 : dw->myFoes.clear();
1510 : // check for self-intersecting forward-section in movingBlock mode
1511 9283 : if (movingBlock && uniqueFoes.count(dw) == 0) {
1512 : std::map<const MSJunction*, std::vector<const MSLink*> > forwardJunctions;
1513 299 : int iLast = (int)dw->myForward.size() - 1;
1514 : bool selfIntersect = false;
1515 2971 : for (int i = 0; i < iLast && !selfIntersect; i++) {
1516 2672 : const MSLane* fw = dw->myForward[i];
1517 2672 : if (fw->isNormal()) {
1518 1290 : const MSJunction* fwTo = fw->getEdge().getToJunction();
1519 1290 : const MSLink* fwLink = fw->getLinkTo(dw->myForward[i + 1]);
1520 1290 : if (fwLink != nullptr) {
1521 1301 : for (const MSLink* link2 : forwardJunctions[fwTo]) {
1522 : const std::vector<MSLink*>& foeLinks = fwLink->getFoeLinks();
1523 : const std::vector<MSLink*>& foeLinks2 = link2->getFoeLinks();
1524 26 : if (std::find(foeLinks.begin(), foeLinks.end(), link2) != foeLinks.end()
1525 32 : || std::find(foeLinks2.begin(), foeLinks2.end(), fwLink) != foeLinks2.end()
1526 16 : || fwLink->getLane()->getBidiLane() == link2->getLaneBefore()
1527 37 : || link2->getLane()->getBidiLane() == fwLink->getLaneBefore()) {
1528 15 : dw->myFoes.push_back(dw);
1529 : selfIntersect = true;
1530 : #ifdef DEBUG_ADD_FOES
1531 : if (DEBUG_COND_DW(dw)) {
1532 : std::cout << " self-intersecting movingBlock for dw=" << dw->getID() << " at junction " << fwTo->getID() << " fwLink=" << fwLink->getDescription() << " link2=" << link2->getDescription() << "\n";
1533 : }
1534 : #endif
1535 : break;
1536 : }
1537 : }
1538 1290 : forwardJunctions[fwTo].push_back(fwLink);
1539 : }
1540 : }
1541 : }
1542 : }
1543 9283 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> uniqueCLink(dw->myConflictLinks.begin(), dw->myConflictLinks.end());
1544 9283 : const MSEdge* lastEdge = &dw->myForward.back()->getEdge();
1545 16536 : for (MSDriveWay* foe : uniqueFoes) {
1546 7253 : const MSEdge* foeLastEdge = &foe->myForward.back()->getEdge();
1547 7253 : const bool sameLast = foeLastEdge == lastEdge;
1548 7253 : if (sameLast && !movingBlock) {
1549 2718 : dw->myFoes.push_back(foe);
1550 2718 : if (foe != dw) {
1551 2718 : foe->myFoes.push_back(dw);
1552 : }
1553 : } else {
1554 4535 : if (foe->bidiBlockedByEnd(*dw)) {
1555 : #ifdef DEBUG_ADD_FOES
1556 : if (DEBUG_COND_DW(dw)) {
1557 : std::cout << " setting " << dw->getID() << " as foe of " << foe->getID() << "\n";
1558 : }
1559 : #endif
1560 2193 : foe->myFoes.push_back(dw);
1561 2193 : foe->addSidings(dw);
1562 : } else {
1563 2342 : dw->buildSubFoe(foe, movingBlock);
1564 : }
1565 4535 : if (foe != dw) { // check for movingBlock
1566 4510 : if (dw->bidiBlockedByEnd(*foe)) {
1567 : #ifdef DEBUG_ADD_FOES
1568 : if (DEBUG_COND_DW(dw)) {
1569 : std::cout << " addFoeCheckSiding " << foe->getID() << "\n";
1570 : }
1571 : #endif
1572 2425 : dw->myFoes.push_back(foe);
1573 2425 : dw->addSidings(foe);
1574 : } else {
1575 2085 : foe->buildSubFoe(dw, movingBlock);
1576 : }
1577 : }
1578 : }
1579 7253 : if (link) {
1580 5186 : foe->addConflictLink(link);
1581 : }
1582 : // ignore links that have the same start junction
1583 7253 : if (foe->myRoute.front()->getFromJunction() != dw->myRoute.front()->getFromJunction()) {
1584 8955 : for (auto ili : foe->myForward.front()->getIncomingLanes()) {
1585 4026 : if (ili.viaLink->getTLLogic() != nullptr) {
1586 : // ignore links that originate on myBidi
1587 3563 : const MSLane* origin = ili.viaLink->getLaneBefore();
1588 3563 : if (std::find(dw->myBidi.begin(), dw->myBidi.end(), origin) == dw->myBidi.end()) {
1589 : uniqueCLink.insert(ili.viaLink);
1590 : }
1591 : }
1592 : }
1593 : }
1594 : }
1595 : dw->myConflictLinks.clear();
1596 9283 : dw->myConflictLinks.insert(dw->myConflictLinks.begin(), uniqueCLink.begin(), uniqueCLink.end());
1597 9283 : myEndingDriveways[lastEdge].push_back(dw);
1598 9283 : if (!movingBlock) {
1599 : // every driveway is it's own foe (also all driveways that depart in the same block)
1600 20929 : for (MSDriveWay* sameEnd : myEndingDriveways[lastEdge]) {
1601 : if (uniqueFoes.count(sameEnd) == 0) {
1602 9252 : dw->myFoes.push_back(sameEnd);
1603 9252 : if (sameEnd != dw) {
1604 293 : sameEnd->myFoes.push_back(dw);
1605 : }
1606 : }
1607 : }
1608 : }
1609 : #ifdef DEBUG_BUILD_DRIVEWAY
1610 : if (DEBUG_COND_DW(dw)) {
1611 : std::cout << dw->myID << " mb=" << movingBlock << " finalFoes " << toString(dw->myFoes) << "\n";
1612 : }
1613 : gDebugFlag4 = false;
1614 : #endif
1615 9283 : return dw;
1616 9283 : }
1617 :
1618 : std::string
1619 4499 : MSDriveWay::getTLLinkID(const MSLink* link) {
1620 8998 : return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
1621 : }
1622 :
1623 : std::string
1624 0 : MSDriveWay::getJunctionLinkID(const MSLink* link) {
1625 0 : return link->getJunction()->getID() + "_" + toString(link->getIndex());
1626 : }
1627 :
1628 : std::string
1629 5486 : MSDriveWay::getClickableTLLinkID(const MSLink* link) {
1630 16458 : return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
1631 : }
1632 :
1633 : std::string
1634 0 : MSDriveWay::formatVisitedMap(const LaneVisitedMap& visited) {
1635 : UNUSED_PARAMETER(visited);
1636 : /*
1637 : std::vector<const MSLane*> lanes(visited.size(), nullptr);
1638 : for (auto item : visited) {
1639 : lanes[item.second] = item.first;
1640 : }
1641 : for (auto it = lanes.begin(); it != lanes.end();) {
1642 : if (*it == nullptr) {
1643 : it = lanes.erase(it);
1644 : } else {
1645 : it++;
1646 : }
1647 : }
1648 : return toString(lanes);
1649 : */
1650 0 : return "dummy";
1651 : }
1652 :
1653 :
1654 : void
1655 135490 : MSDriveWay::appendMapIndex(LaneVisitedMap& map, const MSLane* lane) {
1656 : // avoid undefined behavior from evaluation order
1657 135490 : const int tmp = (int)map.size();
1658 135490 : map[lane] = tmp;
1659 135490 : }
1660 :
1661 : bool
1662 17097585 : MSDriveWay::match(MSRouteIterator firstIt, MSRouteIterator endIt) const {
1663 : // @todo optimize: it is sufficient to check for specific edges (after each switch)
1664 17097585 : auto itRoute = firstIt;
1665 : auto itDwRoute = myRoute.begin();
1666 : bool match = true;
1667 120502968 : while (itRoute != endIt && itDwRoute != myRoute.end()) {
1668 103603410 : if (*itRoute != *itDwRoute) {
1669 : match = false;
1670 : #ifdef DEBUG_MATCH
1671 : std::cout << " check dw=" << getID() << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
1672 : #endif
1673 : break;
1674 : }
1675 : itRoute++;
1676 : itDwRoute++;
1677 : }
1678 : // if the vehicle arrives before the end of this driveway,
1679 : // we'd rather build a new driveway to avoid superfluous restrictions
1680 16899558 : if (match && itDwRoute == myRoute.end()
1681 33968511 : && (itRoute == endIt || myAbortedBuild || myBidiEnded || myFoundJump || isSubDriveWay())) {
1682 : //std::cout << " using dw=" << "\n";
1683 16856474 : if (itRoute != endIt) {
1684 : // check whether the current route requires an extended driveway
1685 244365 : const MSEdge* next = *itRoute;
1686 244365 : const MSEdge* prev = myRoute.back();
1687 425 : if (myFoundJump && prev->getBidiEdge() != next && prev->getBidiEdge() != nullptr
1688 244630 : && prev->isConnectedTo(*next, (SUMOVehicleClass)(SVC_RAIL_CLASSES & prev->getPermissions()))) {
1689 : #ifdef DEBUG_MATCH
1690 : std::cout << " check dw=" << getID() << " prev=" << prev->getID() << " next=" << next->getID() << "\n";
1691 : #endif
1692 : return false;
1693 : }
1694 244340 : if (!myFoundJump && prev->getBidiEdge() == next && prev == &myForward.back()->getEdge()) {
1695 : assert(isSubDriveWay() || myBidiEnded);
1696 : // must not leave driveway via reversal
1697 : #ifdef DEBUG_MATCH
1698 : std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, endIt)) << "\n";
1699 : #endif
1700 : return false;
1701 : }
1702 244334 : if (myForward.back()->isInternal() && myForward.back()->getNextNormal() != (*itRoute)) {
1703 : // driveway is part of a direct-control conflict and continues elsewhere
1704 : #ifdef DEBUG_MATCH
1705 : std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, itRoute)) << " (direct control)\n";
1706 : #endif
1707 : return false;
1708 : }
1709 : }
1710 16856441 : return !isSubDriveWay() || myParent->match(firstIt, endIt);
1711 : }
1712 : return false;
1713 : }
1714 :
1715 : void
1716 12573 : MSDriveWay::addFoes(const MSLink* link) {
1717 : #ifdef DEBUG_ADD_FOES
1718 : if (gDebugFlag4) {
1719 : std::cout << "driveway " << myID << " addFoes for link " << link->getDescription() << "\n";
1720 : }
1721 : #endif
1722 12573 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
1723 12573 : if (rs != nullptr) {
1724 17426 : for (MSDriveWay* foe : rs->retrieveDriveWays(link->getTLIndex())) {
1725 : #ifdef DEBUG_ADD_FOES
1726 : if (gDebugFlag4) {
1727 : std::cout << " cand foe=" << foe->myID << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this) << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1728 : }
1729 : #endif
1730 4853 : if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1731 : #ifdef DEBUG_ADD_FOES
1732 : if (gDebugFlag4) {
1733 : std::cout << " foe=" << foe->myID << "\n";
1734 : }
1735 : #endif
1736 3778 : myFoes.push_back(foe);
1737 : }
1738 12573 : }
1739 : }
1740 12573 : }
1741 :
1742 :
1743 : void
1744 18566 : MSDriveWay::addBidiFoes(const MSRailSignal* ownSignal, bool extended) {
1745 : #ifdef DEBUG_ADD_FOES
1746 : if (gDebugFlag4) {
1747 : std::cout << "driveway " << myID << " addBidiFoes extended=" << extended << "\n";
1748 : }
1749 : #endif
1750 18566 : const std::vector<const MSLane*>& bidiLanes = extended ? myBidiExtended : myBidi;
1751 102519 : for (const MSLane* bidi : bidiLanes) {
1752 171348 : for (auto ili : bidi->getIncomingLanes()) {
1753 87395 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(ili.viaLink->getTLLogic());
1754 87395 : if (rs != nullptr && rs != ownSignal &&
1755 87395 : std::find(bidiLanes.begin(), bidiLanes.end(), ili.lane) != bidiLanes.end()) {
1756 4912 : addFoes(ili.viaLink);
1757 : }
1758 : }
1759 83953 : const MSEdge* bidiEdge = &bidi->getEdge();
1760 : if (myDepartureDriveways.count(bidiEdge) != 0) {
1761 3734 : for (MSDriveWay* foe : myDepartureDriveways[bidiEdge]) {
1762 1678 : if (flankConflict(*foe)) {
1763 : #ifdef DEBUG_ADD_FOES
1764 : if (gDebugFlag4) {
1765 : std::cout << " foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << "\n";
1766 : }
1767 : #endif
1768 1069 : myFoes.push_back(foe);
1769 : } else {
1770 : #ifdef DEBUG_ADD_FOES
1771 : if (gDebugFlag4) {
1772 : std::cout << " cand foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << " rejected\n";
1773 : }
1774 : #endif
1775 : }
1776 : }
1777 : }
1778 : if (myDepartureDrivewaysEnds.count(bidiEdge) != 0) {
1779 3086 : for (MSDriveWay* foe : myDepartureDrivewaysEnds[bidiEdge]) {
1780 1589 : if (flankConflict(*foe)) {
1781 : #ifdef DEBUG_ADD_FOES
1782 : if (gDebugFlag4) {
1783 : std::cout << " foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << "\n";
1784 : }
1785 : #endif
1786 1044 : myFoes.push_back(foe);
1787 : } else {
1788 : #ifdef DEBUG_ADD_FOES
1789 : if (gDebugFlag4) {
1790 : std::cout << " cand foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << " rejected\n";
1791 : }
1792 : #endif
1793 : }
1794 : }
1795 : }
1796 : }
1797 18566 : }
1798 :
1799 :
1800 : void
1801 8959 : MSDriveWay::addParallelFoes(const MSLink* link, const MSEdge* first) {
1802 : #ifdef DEBUG_ADD_FOES
1803 : if (gDebugFlag4) {
1804 : std::cout << "driveway " << myID << " addParallelFoes\n";
1805 : }
1806 : #endif
1807 8959 : if (link) {
1808 5375 : addFoes(link);
1809 : } else {
1810 : auto it = myDepartureDriveways.find(first);
1811 3584 : if (it != myDepartureDriveways.end()) {
1812 3808 : for (MSDriveWay* foe : it->second) {
1813 : #ifdef DEBUG_ADD_FOES
1814 : if (gDebugFlag4) {
1815 : std::cout << " foe " << foe->getID() << " departs on first=" << first->getID() << "\n";
1816 : }
1817 : #endif
1818 263 : myFoes.push_back(foe);
1819 : }
1820 : }
1821 : }
1822 8959 : }
1823 :
1824 :
1825 : void
1826 9283 : MSDriveWay::addReversalFoes(bool movingBlock) {
1827 : #ifdef DEBUG_ADD_FOES
1828 : if (gDebugFlag4) {
1829 : std::cout << "driveway " << myID << " addReversalFoes\n";
1830 : }
1831 : #endif
1832 : std::set<const MSEdge*> forward;
1833 46700 : for (const MSLane* lane : myForward) {
1834 37417 : if (lane->isNormal()) {
1835 21916 : forward.insert(&lane->getEdge());
1836 : }
1837 : }
1838 : int i = 0;
1839 79177 : for (const MSEdge* e : myRoute) {
1840 21932 : if (forward.count(e) != 0 && !movingBlock) {
1841 : // reversals in our own forward can be ignored because each driveway
1842 : // is automatically a foe of itself by default
1843 : continue;
1844 : }
1845 49666 : if (i == myCoreSize) {
1846 : break;
1847 : }
1848 49666 : i++;
1849 : auto it = myReversalDriveWays.find(e);
1850 49666 : if (it != myReversalDriveWays.end()) {
1851 6717 : for (MSDriveWay* foe : it->second) {
1852 : // check whether the foe reverses into our own forward section
1853 : // (it might reverse again or disappear via arrival)
1854 : #ifdef DEBUG_ADD_FOES
1855 : //std::cout << " candidate foe " << foe->getID() << " reverses on edge=" << e->getID() << " forward=" << joinNamedToString(forward, " ") << " foeRoute=" << toString(foe->myRoute) << "\n";
1856 : #endif
1857 11752 : if (forwardRouteConflict(forward, *foe)) {
1858 : std::set<const MSEdge*> foeForward;
1859 1795 : for (const MSLane* lane : foe->myForward) {
1860 1557 : if (lane->isNormal()) {
1861 801 : foeForward.insert(&lane->getEdge());
1862 801 : if (lane->getBidiLane() != nullptr) {
1863 790 : foeForward.insert(lane->getEdge().getBidiEdge());
1864 : }
1865 : }
1866 : }
1867 : #ifdef DEBUG_ADD_FOES
1868 : if (gDebugFlag4) {
1869 : std::cout << " reversal cand=" << foe->getID() << " foeForward " << toString(foeForward) << "\n";
1870 : }
1871 : #endif
1872 476 : if (foe->forwardRouteConflict(foeForward, *this, true)) {
1873 : #ifdef DEBUG_ADD_FOES
1874 : if (gDebugFlag4) {
1875 : std::cout << " foe " << foe->getID() << " reverses on edge=" << e->getID() << "\n";
1876 : }
1877 : #endif
1878 192 : myFoes.push_back(foe);
1879 : }
1880 5638 : } else if (movingBlock && foe == this) {
1881 : #ifdef DEBUG_ADD_FOES
1882 : if (gDebugFlag4) {
1883 : std::cout << " dw " << getID() << " reverses on forward edge=" << e->getID() << " (movingBlock)\n";
1884 : }
1885 : #endif
1886 25 : myFoes.push_back(foe);
1887 : }
1888 : }
1889 : }
1890 : }
1891 9283 : }
1892 :
1893 :
1894 : bool
1895 4427 : MSDriveWay::buildSubFoe(MSDriveWay* foe, bool movingBlock) {
1896 : // Subdriveways (Teilfahrstraße) model the resolution of a driving conflict
1897 : // before a vehicle has left the driveway. This is possible when the driveway diverges from the foe
1898 : // driveway at an earlier point (switch or crossing).
1899 : //
1900 : // We already know that the last edge of this driveway doesn't impact the foe (unless the driveway ends within the block).
1901 : // Remove further edges from the end of the driveway (myForward) until the point of conflict is found.
1902 : //
1903 : // For movingBlock the logic is changed:
1904 : // We remove the conflict-free part as before but then keep removing the conflict part until another non-conconflit part is found
1905 4427 : if (myForward.size() < foe->myForward.size() &&
1906 4427 : myForward == std::vector<const MSLane*>(foe->myForward.begin(), foe->myForward.begin() + myForward.size())) {
1907 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1908 : if (gDebugFlag4) {
1909 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " is subpart of foe=" << foe->getID() << "\n";
1910 : }
1911 : #endif
1912 83 : foe->myFoes.push_back(this);
1913 83 : return true;
1914 : }
1915 4344 : int subLast = (int)myForward.size() - 2;
1916 4344 : if (movingBlock && myForward.back() == foe->myForward.back()) {
1917 71 : subLast++;
1918 : }
1919 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1920 : if (subLast < 0) {
1921 : if (gDebugFlag4) {
1922 : std::cout << " " << getID() << " cannot build subDriveWay for foe " << foe->getID() << " because myForward has only a single lane\n";
1923 : }
1924 : }
1925 : #endif
1926 : bool foundConflict = false;
1927 : bool flankC = false;
1928 : bool zipperC = false;
1929 : bool crossC = false;
1930 15126 : while (subLast >= 0) {
1931 14960 : const MSLane* lane = myForward[subLast];
1932 14960 : const MSLink* tmpOrigin = subLast > 0 ? myForward[subLast - 1]->getLinkTo(lane) : myOrigin;
1933 14960 : MSDriveWay tmp(tmpOrigin, "tmp", true);
1934 14960 : tmp.myForward.push_back(lane);
1935 14960 : tmp.myBidi = myBidi;
1936 14960 : tmp.myBidiExtended = myBidiExtended;
1937 14960 : tmp.myRoute.push_back(lane->getNextNormal());
1938 14960 : tmp.myCoreSize = 1;
1939 14960 : flankC = tmp.flankConflict(*foe);
1940 14960 : const bool bidiConflict = std::find(foe->myBidi.begin(), foe->myBidi.end(), lane) != foe->myBidi.end();
1941 14960 : crossC = tmp.crossingConflict(*foe);
1942 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1943 : if (gDebugFlag4) {
1944 : std::cout << " subLast=" << subLast << " lane=" << lane->getID() << " fc=" << flankC << " cc=" << crossC << " bc=" << bidiConflict << "\n";
1945 : }
1946 : #endif
1947 14960 : if (flankC || crossC || bidiConflict) {
1948 : foundConflict = true;
1949 4486 : if (!movingBlock || bidiConflict) {
1950 : break;
1951 : }
1952 358 : if (((flankC && lane->getFromJunction()->getType() == SumoXMLNodeType::ZIPPER)
1953 46 : || (!flankC && lane->getToJunction()->getType() == SumoXMLNodeType::ZIPPER))
1954 431 : && (isDepartDriveway()
1955 15 : || getForwardDistance(flankC ? subLast - 1 : subLast) > myMovingBlockMaxDist)) {
1956 : zipperC = true;
1957 : foundConflict = false;
1958 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1959 : if (gDebugFlag4) {
1960 : std::cout << " ignored movingBlock zipperConflict\n";
1961 : }
1962 : #endif
1963 18 : if (!flankC && crossC) {
1964 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1965 : if (gDebugFlag4) {
1966 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
1967 : }
1968 : #endif
1969 : return false;
1970 : }
1971 : }
1972 395 : if (!flankC && crossC) {
1973 : break;
1974 : }
1975 10474 : } else if (foundConflict) {
1976 : break;
1977 : }
1978 10782 : subLast--;
1979 14960 : }
1980 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1981 : if (gDebugFlag4) {
1982 : std::cout << " subLastFinal=" << subLast << " movingBlock=" << movingBlock << " zipperC=" << zipperC << "\n";
1983 : }
1984 : #endif
1985 4335 : if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
1986 : //std::set<const MSEdge*> firstEdge;
1987 : //firstEdge.insert(foe->myRoute.front());
1988 :
1989 248 : ConstMSEdgeVector forward(myRoute.begin(), myRoute.begin() + myForwardEdgeCount);
1990 : ConstMSEdgeVector foeAfterForward(foe->myRoute.begin() + foe->myForwardEdgeCount,
1991 248 : foe->myRoute.begin() + MIN2(foe->myRoute.size(), foe->myForwardEdgeCount + forward.size()));
1992 : // @todo the check for forwardRouteConflict correctly reduces waiting in
1993 : // test rail/reversal/consecutive_before_reversal but creates deadlock in
1994 : // test rail/reversal/reversal_onRoute_beyond_core3b
1995 248 : if (forward == foeAfterForward /*&& forwardRouteConflict(firstEdge, *this, true)*/) {
1996 126 : foe->myFoes.push_back(this);
1997 : // foe will get the sidings
1998 126 : addSidings(foe, true);
1999 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2000 : if (gDebugFlag4) {
2001 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " special case 1\n";
2002 : }
2003 : #endif
2004 : return true;
2005 : }
2006 248 : }
2007 4209 : if (subLast < 0) {
2008 136 : if (movingBlock && zipperC) {
2009 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2010 : if (gDebugFlag4) {
2011 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
2012 : }
2013 : #endif
2014 : return false;
2015 136 : } else if (&myForward.back()->getEdge() == myRoute.back() && foe->forwardEndOnRoute(this)) {
2016 : // driveway ends in the middle of the block and only the final edge overlaps with the foe driveWay
2017 15 : foe->myFoes.push_back(this);
2018 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2019 : if (gDebugFlag4) {
2020 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " foe endsOnForward\n";
2021 : }
2022 : #endif
2023 121 : } else if (foe->myTerminateRoute) {
2024 121 : if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
2025 5 : foe->myFoes.push_back(this);
2026 : // foe will get the sidings
2027 5 : addSidings(foe, true);
2028 : }
2029 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2030 : if (gDebugFlag4) {
2031 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " terminates\n";
2032 : }
2033 : #endif
2034 0 : } else if (myTerminateRoute && myBidi.size() <= myForward.size()) {
2035 0 : foe->myFoes.push_back(this);
2036 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2037 : if (gDebugFlag4) {
2038 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " terminates, foe=" << foe->getID() << "\n";
2039 : }
2040 : #endif
2041 0 : return true;
2042 : } else if (foe->myReversals.size() % 2 == 1) {
2043 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2044 : if (gDebugFlag4) {
2045 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " has " << foe->myReversals.size() << " reversals\n";
2046 : }
2047 : #endif
2048 : } else {
2049 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2050 : if (gDebugFlag4) {
2051 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " failed\n";
2052 : }
2053 : #endif
2054 : #ifdef SUBDRIVEWAY_WARN_NOCONFLICT
2055 : WRITE_WARNINGF("No point of conflict found between driveway '%' and driveway '%' when creating sub-driveway", getID(), foe->getID());
2056 : #endif
2057 : }
2058 136 : return false;
2059 : }
2060 4073 : int subSize = subLast + 1;
2061 5003 : for (MSDriveWay* cand : mySubDriveWays) {
2062 2407 : if ((int)cand->myForward.size() == subSize) {
2063 : // can re-use existing sub-driveway
2064 1477 : foe->myFoes.push_back(cand);
2065 1477 : if (foe->bidiBlockedByEnd(*cand)) {
2066 1343 : foe->addSidings(cand);
2067 : }
2068 1477 : cand->myFoes.push_back(foe);
2069 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2070 : if (gDebugFlag4) {
2071 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " useExisting=" << cand->getID() << "\n";
2072 : }
2073 : #endif
2074 1477 : return true;
2075 : }
2076 : }
2077 2596 : std::vector<const MSLane*> forward(myForward.begin(), myForward.begin() + subSize);
2078 : std::vector<const MSEdge*> route;
2079 14857 : for (const MSLane* lane : forward) {
2080 12261 : if (lane->isNormal()) {
2081 6095 : route.push_back(&lane->getEdge());
2082 : }
2083 : }
2084 2596 : if (route.empty()) {
2085 59 : if (subSize == 1 && crossC
2086 56 : && forward.front()->getFromJunction() == foe->myForward.front()->getFromJunction()
2087 115 : && forward.front()->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2088 : assert(myForward.front()->isInternal());
2089 : // sub-driveway ends after a single internal lane but since the route cannot be empty we add the next edge
2090 56 : route.push_back(foe->myForward.front()->getEdge().getNormalSuccessor());
2091 : } else {
2092 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2093 : if (gDebugFlag4) {
2094 : std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID() << " empty subRoute\n";
2095 : }
2096 : #endif
2097 3 : return false;
2098 : }
2099 : }
2100 2593 : if (myRoute.size() > route.size()) {
2101 : // route continues. make sure the subDriveway does not end with a reversal
2102 2581 : const MSEdge* lastNormal = route.back();
2103 2581 : const MSEdge* nextNormal = myRoute[route.size()];
2104 2581 : if (lastNormal->getBidiEdge() == nextNormal) {
2105 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2106 : if (gDebugFlag4) std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID()
2107 : << " lastNormal=" << lastNormal->getID() << " nextNormal=" << nextNormal->getID() << " endWithReversal\n";
2108 : #endif
2109 : return false;
2110 : }
2111 : }
2112 5146 : MSDriveWay* sub = new MSDriveWay(myOrigin, getID() + "." + toString(mySubDriveWays.size()));
2113 2573 : sub->myLane = myLane;
2114 2573 : sub->myParent = this;
2115 2573 : sub->myForward = forward;
2116 2573 : sub->myRoute = route;
2117 2573 : sub->myCoreSize = (int)sub->myRoute.size();
2118 2573 : myLane->addMoveReminder(sub, false);
2119 :
2120 : // copy trains that are currently on this driveway (and associated entry events)
2121 2745 : for (SUMOVehicle* veh : myTrains) {
2122 172 : auto itOnSub = std::find(sub->myRoute.begin(), sub->myRoute.end(), veh->getEdge());
2123 172 : if (itOnSub != sub->myRoute.end()) {
2124 : sub->myTrains.insert(veh);
2125 : // non-zero is enough to avoid superfluous activation via activateReminders (and removal)
2126 148 : const double pos = sub->myRoute.front()->getLength();
2127 148 : dynamic_cast<MSBaseVehicle*>(veh)->addReminder(sub, pos);
2128 169 : for (const VehicleEvent& ve : myVehicleEvents) {
2129 21 : if (ve.id == veh->getID()) {
2130 21 : sub->myVehicleEvents.push_back(ve);
2131 : }
2132 : }
2133 : }
2134 : }
2135 :
2136 2573 : foe->myFoes.push_back(sub);
2137 2573 : if (foe->bidiBlockedByEnd(*sub)) {
2138 1765 : foe->addSidings(sub);
2139 : }
2140 2573 : sub->myFoes.push_back(foe);
2141 2573 : mySubDriveWays.push_back(sub);
2142 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
2143 : if (gDebugFlag4) {
2144 : std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " sub=" << sub->getID() << " route=" << toString(sub->myRoute) << "\n";
2145 : }
2146 : #endif
2147 : return true;
2148 2596 : }
2149 :
2150 :
2151 : double
2152 15 : MSDriveWay::getForwardDistance(int lastIndex) const {
2153 : assert(lastIndex < (int)myForward.size());
2154 : double result = 0;
2155 57 : for (int i = 0; i <= lastIndex; i++) {
2156 42 : result += myForward[i]->getLength();
2157 : }
2158 15 : return result;
2159 : }
2160 :
2161 :
2162 : void
2163 7857 : MSDriveWay::addSidings(MSDriveWay* foe, bool addToFoe) {
2164 7857 : const ConstMSEdgeVector& foeRoute = foe->isSubDriveWay() ? foe->myParent->myRoute : foe->myRoute;
2165 7857 : const MSEdge* foeEndBidi = foe->myForward.back()->getEdge().getBidiEdge();
2166 : int foeForwardNormals = 0;
2167 41469 : for (auto lane : foe->myForward) {
2168 33612 : if (lane->isNormal()) {
2169 17978 : foeForwardNormals++;
2170 : }
2171 : }
2172 7857 : if (foeForwardNormals == (int)foeRoute.size()) {
2173 : #ifdef DEBUG_BUILD_SIDINGS
2174 : if (gDebugFlag4) {
2175 : std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " foeForwardNormals=" << foeForwardNormals << " frSize=" << foeRoute.size() << " aborted\n";
2176 : }
2177 : #endif
2178 1027 : return;
2179 : }
2180 : auto foeSearchBeg = foeRoute.begin() + foeForwardNormals;
2181 : auto foeSearchEnd = foeRoute.end();
2182 6980 : if (foeEndBidi == nullptr) {
2183 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " noBidi\n");
2184 : }
2185 : // if foe is a subDriveway, the forward section may end on an internal edge which would not be found on myRoute
2186 6980 : foeEndBidi = foeEndBidi->getNormalSuccessor();
2187 6980 : std::set<const MSEdge*> foeForwardEdges(foeRoute.begin(), foeRoute.begin() + foeForwardNormals);
2188 : int forwardNormals = 0;
2189 48024 : for (auto lane : myForward) {
2190 41194 : if (lane->isNormal()) {
2191 22087 : forwardNormals++;
2192 : if (foeForwardEdges.count(&lane->getEdge()) != 0) {
2193 : #ifdef DEBUG_BUILD_SIDINGS
2194 : if (gDebugFlag4) {
2195 : std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " forwardEdge=" << lane->getEdge().getID() << " on foeForward (sidings unsafe)\n";
2196 : }
2197 : #endif
2198 : return;
2199 : }
2200 : }
2201 : }
2202 : int i;
2203 : std::vector<int> start;
2204 : std::vector<double> length;
2205 : std::vector<std::vector<int> > intermediateRS;
2206 40488 : for (i = 0; i < (int)myRoute.size(); i++) {
2207 40488 : if (myRoute[i] == foeEndBidi) {
2208 : break;
2209 : }
2210 : }
2211 6830 : if (i == (int)myRoute.size()) {
2212 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " foeEndBidi=" + foeEndBidi->getID() + " not on route\n");
2213 : }
2214 6830 : const MSEdge* next = myRoute[i];
2215 : #ifdef DEBUG_BUILD_SIDINGS
2216 : if (gDebugFlag4) {
2217 : std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " next=" << next->getID() << " foeForwardNormals=" << foeForwardNormals << " frSize=" << foeRoute.size() << " foeSearchBeg=" << (*foeSearchBeg)->getID() << "\n";
2218 : }
2219 : #endif
2220 6830 : i--;
2221 : // look backward along our route starting at the final edge of the foe dw
2222 40488 : for (; i >= 0; i--) {
2223 33658 : const MSEdge* cur = myRoute[i];
2224 33658 : const bool curHasRS = hasRS(cur, next);
2225 33658 : if (curHasRS) {
2226 11495 : if (std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge()) == foeSearchEnd) {
2227 : // we found a rail signal in a safe spot (not on the foe route)
2228 7923 : start.push_back(i);
2229 7923 : length.push_back(0);
2230 7923 : intermediateRS.push_back({});
2231 : }
2232 : }
2233 33658 : if (!start.empty()) {
2234 : // move further backwards along the route to find the spot where it merges again with the foe route
2235 12718 : auto itFind = std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge());
2236 12718 : if (itFind != foeSearchEnd) {
2237 : #ifdef DEBUG_BUILD_SIDINGS
2238 : if (gDebugFlag4) {
2239 : std::cout << "endSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " curBidi=" << Named::getIDSecure(cur->getBidiEdge()) << " length=" << toString(length) << "\n";
2240 : }
2241 : #endif
2242 2144 : const int firstIndex = i + 1;
2243 2144 : if (addToFoe) {
2244 131 : auto& foeSidings = foe->mySidings[this];
2245 : // indices must be mapped onto foe route;
2246 131 : const MSEdge* first = myRoute[firstIndex];
2247 131 : auto itFirst = std::find(foeRoute.begin(), foeRoute.end(), first);
2248 131 : if (itFirst != foeRoute.end()) {
2249 473 : for (int j = 0; j < (int)length.size(); j++) {
2250 342 : const MSEdge* last = myRoute[start[j]];
2251 342 : auto itLast = std::find(itFirst, foeRoute.end(), last);
2252 342 : if (itLast != foeRoute.end()) {
2253 : // @todo are intermediateRS relevant here?
2254 684 : foeSidings.insert(foeSidings.begin(), Siding((int)(itFirst - foeRoute.begin()), (int)(itLast - foeRoute.begin()), length[j], {}));
2255 342 : if (foeSidings.size() > 2) {
2256 : foeSidings.pop_back(); // only need the first 2 sidings
2257 : }
2258 : }
2259 : }
2260 : }
2261 : } else {
2262 : // pick up further rail signals between the start of the siding and the start of the current driveway
2263 : std::vector<int> furtherRS;
2264 2013 : if (curHasRS) {
2265 128 : furtherRS.push_back(i);
2266 : }
2267 : const MSEdge* next2 = cur;
2268 5670 : for (int i2 = i - 1; i2 >= forwardNormals; i2--) {
2269 3657 : const MSEdge* cur2 = myRoute[i2];
2270 3657 : if (hasRS(cur2, next2)) {
2271 1711 : furtherRS.push_back(i2);
2272 : }
2273 : next2 = cur2;
2274 : }
2275 2013 : auto& foeSidings = mySidings[foe];
2276 8896 : for (int j = 0; j < (int)length.size(); j++) {
2277 6883 : intermediateRS[j].insert(intermediateRS[j].end(), furtherRS.begin(), furtherRS.end());
2278 13766 : foeSidings.insert(foeSidings.begin(), Siding(firstIndex, start[j], length[j], intermediateRS[j]));
2279 6883 : if (foeSidings.size() > 2) {
2280 : foeSidings.pop_back(); // only need the first 2 sidings
2281 : }
2282 : }
2283 2013 : }
2284 : start.clear();
2285 : length.clear();
2286 : intermediateRS.clear();
2287 2144 : foeSearchBeg = itFind;
2288 : } else {
2289 75447 : for (int j = 0; j < (int)length.size(); j++) {
2290 64873 : length[j] += cur->getLength();
2291 64873 : if (curHasRS && i != start[j]) {
2292 45431 : intermediateRS[j].push_back(i);
2293 : }
2294 : }
2295 : }
2296 : }
2297 : next = cur;
2298 : }
2299 6830 : }
2300 :
2301 :
2302 : bool
2303 37315 : MSDriveWay::hasRS(const MSEdge* cur, const MSEdge* next) {
2304 37315 : if (cur->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2305 : // check if there is a controlled link between cur and next
2306 25288 : for (auto lane : cur->getLanes()) {
2307 25699 : for (const MSLink* link : lane->getLinkCont()) {
2308 19658 : if (&link->getLane()->getEdge() == next && link->getTLLogic() != nullptr) {
2309 : return true;
2310 : }
2311 : }
2312 : }
2313 : }
2314 : return false;
2315 : }
2316 :
2317 :
2318 : bool
2319 372 : MSDriveWay::forwardEndOnRoute(const MSDriveWay* foe) const {
2320 372 : const MSEdge* foeForwardEnd = &foe->myForward.back()->getNormalPredecessorLane()->getEdge();
2321 372 : return std::find(myRoute.begin(), myRoute.end(), foeForwardEnd) != myRoute.end();
2322 : }
2323 :
2324 : void
2325 5186 : MSDriveWay::addConflictLink(const MSLink* link) {
2326 5186 : if (link->getTLLogic() != nullptr) {
2327 : // ignore links that originate on myBidi
2328 : // and also links from the same junction as my own link
2329 5186 : const MSLane* origin = link->getLaneBefore();
2330 5186 : if (std::find(myBidi.begin(), myBidi.end(), origin) == myBidi.end()) {
2331 4158 : if (link->getJunction() != myRoute.front()->getFromJunction()) {
2332 2628 : if (std::find(myConflictLinks.begin(), myConflictLinks.end(), link) == myConflictLinks.end()) {
2333 1869 : myConflictLinks.push_back(const_cast<MSLink*>(link));
2334 : }
2335 : }
2336 : }
2337 : }
2338 5186 : }
2339 :
2340 : void
2341 348 : MSDriveWay::addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes) {
2342 : std::set<const MSDriveWay*> filtered;
2343 1737 : for (const MSDriveWay* foe : deadlockFoes) {
2344 1389 : if (std::find(myFoes.begin(), myFoes.end(), foe) == myFoes.end()) {
2345 : filtered.insert(foe);
2346 : }
2347 : }
2348 348 : if (std::find(myDeadlocks.begin(), myDeadlocks.end(), filtered) == myDeadlocks.end()) {
2349 93 : myDeadlocks.push_back(filtered);
2350 : //std::cout << getID() << " deadlockFoes=" << toString(deadlockFoes) << "\n";
2351 : }
2352 348 : }
2353 :
2354 : const MSDriveWay*
2355 8041317 : MSDriveWay::getDepartureDriveway(const SUMOVehicle* veh, bool init) {
2356 8041317 : const MSEdge* edge = init ? veh->getRoute().getEdges()[veh->getDepartEdge()] : veh->getEdge();
2357 : assert(isRailwayOrShared(edge->getPermissions()));
2358 8041317 : if (edge->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2359 4467 : for (const MSLane* lane : edge->getLanes()) {
2360 4816 : for (auto ili : lane->getIncomingLanes()) {
2361 2818 : const MSLink* entry = ili.viaLink->getCorrespondingEntryLink();
2362 2818 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(entry->getTLLogic());
2363 1887 : if (rs != nullptr) {
2364 1887 : const MSDriveWay* dw = &const_cast<MSRailSignal*>(rs)->retrieveDriveWayForVeh(entry->getTLIndex(), veh);
2365 1887 : if (&dw->myForward.front()->getEdge() == edge) {
2366 : return dw;
2367 : }
2368 : }
2369 : }
2370 : }
2371 : }
2372 8045198 : for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2373 8041401 : auto matchStart = init ? veh->getRoute().begin() + veh->getDepartEdge() : veh->getCurrentRouteEdge();
2374 8041401 : if (dw->match(matchStart, veh->getRoute().end())) {
2375 8037049 : return dw;
2376 : }
2377 : }
2378 7594 : const std::string id = edge->getFromJunction()->getID() + ".d" + toString(myDepartDrivewayIndex[edge->getFromJunction()]++);
2379 3797 : MSDriveWay* dw = buildDriveWay(id, nullptr, veh->getCurrentRouteEdge(), veh->getRoute().end());
2380 3797 : myDepartureDriveways[edge].push_back(dw);
2381 3797 : myDepartureDrivewaysEnds[&dw->myForward.back()->getEdge()].push_back(dw);
2382 : dw->setVehicle(veh->getID());
2383 : return dw;
2384 : }
2385 :
2386 :
2387 : void
2388 1547 : MSDriveWay::writeDepatureBlocks(OutputDevice& od, bool writeVehicles) {
2389 4169 : for (auto item : myDepartureDriveways) {
2390 2622 : const MSEdge* edge = item.first;
2391 2622 : if (item.second.size() > 0) {
2392 5244 : od.openTag("departJunction");
2393 2622 : od.writeAttr(SUMO_ATTR_ID, edge->getFromJunction()->getID());
2394 5549 : for (const MSDriveWay* dw : item.second) {
2395 2927 : if (writeVehicles) {
2396 421 : dw->writeBlockVehicles(od);
2397 : } else {
2398 2506 : dw->writeBlocks(od);
2399 : }
2400 : }
2401 5244 : od.closeTag(); // departJunction
2402 : }
2403 : }
2404 1547 : }
2405 :
2406 : void
2407 538 : MSDriveWay::saveState(OutputDevice& out) {
2408 : // all driveways are in myEndingDriveways which makes it convenient
2409 616 : for (auto item : myEndingDriveways) {
2410 172 : for (MSDriveWay* dw : item.second) {
2411 94 : dw->_saveState(out);
2412 112 : for (MSDriveWay* sub : dw->mySubDriveWays) {
2413 18 : sub->_saveState(out);
2414 : }
2415 : }
2416 : }
2417 538 : }
2418 :
2419 : void
2420 112 : MSDriveWay::_saveState(OutputDevice& out) const {
2421 112 : if (!myTrains.empty() || haveSubTrains()) {
2422 83 : out.openTag(isSubDriveWay() ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
2423 43 : out.writeAttr(SUMO_ATTR_ID, getID());
2424 43 : out.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
2425 43 : if (!myTrains.empty()) {
2426 : std::vector<std::string> trainIDs;
2427 86 : for (SUMOVehicle* veh : myTrains) {
2428 43 : trainIDs.push_back(veh->getID());
2429 : }
2430 43 : out.writeAttr(SUMO_ATTR_VEHICLES, toString(trainIDs));
2431 43 : }
2432 86 : out.closeTag();
2433 : }
2434 112 : }
2435 :
2436 :
2437 : bool
2438 69 : MSDriveWay::haveSubTrains() const {
2439 76 : for (MSDriveWay* sub : mySubDriveWays) {
2440 7 : if (!sub->myTrains.empty()) {
2441 : return true;
2442 : }
2443 : }
2444 : return false;
2445 : }
2446 :
2447 : void
2448 43 : MSDriveWay::loadState(const SUMOSAXAttributes& attrs, int tag) {
2449 43 : if ((int)myDriveWayRouteLookup.size() < myGlobalDriveWayIndex) {
2450 106 : for (auto item : myEndingDriveways) {
2451 164 : for (MSDriveWay* dw : item.second) {
2452 84 : myDriveWayRouteLookup[dw->myRoute] = dw;
2453 : }
2454 : }
2455 : }
2456 43 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
2457 : bool ok;
2458 43 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
2459 43 : const std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), ok);
2460 : ConstMSEdgeVector route;
2461 43 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
2462 43 : MSEdge::parseEdgesList(edges, route, id);
2463 : }
2464 : // missing driveways and subdriveways can be ignored. They may have been created
2465 : // for vehicles that are not relevant at state loading time
2466 : MSDriveWay* dw = nullptr;
2467 43 : if (tag == SUMO_TAG_DRIVEWAY) {
2468 : auto it = myDriveWayRouteLookup.find(route);
2469 40 : if (it == myDriveWayRouteLookup.end()) {
2470 : //WRITE_WARNING(TLF("Unknown driveWay '%' with route '%'", id, edges));
2471 : return;
2472 : }
2473 38 : dw = it->second;
2474 38 : myDriveWayLookup[id] = dw;
2475 : } else {
2476 3 : std::string parentID = id.substr(0, id.rfind('.'));
2477 : auto it = myDriveWayLookup.find(parentID);
2478 3 : if (it == myDriveWayLookup.end()) {
2479 : //WRITE_WARNING(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2480 : return;
2481 : }
2482 3 : MSDriveWay* parent = it->second;
2483 3 : for (MSDriveWay* sub : parent->mySubDriveWays) {
2484 1 : if (sub->myRoute == route) {
2485 : dw = sub;
2486 : break;
2487 : }
2488 : }
2489 3 : if (dw == nullptr) {
2490 : // missing subdriveways can be ignored. They may have been created
2491 : // as foes for driveways that are not relevant at state loading time
2492 : return;
2493 : }
2494 : }
2495 78 : const std::string vehicles = attrs.getOpt<std::string>(SUMO_ATTR_VEHICLES, id.c_str(), ok, "");
2496 117 : for (const std::string& vehID : StringTokenizer(vehicles).getVector()) {
2497 39 : MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(c.getVehicle(vehID));
2498 39 : if (veh == nullptr) {
2499 0 : throw ProcessError(TLF("Unknown vehicle '%' in driveway '%'", vehID, id));
2500 : }
2501 39 : if (!dw->hasTrain(veh)) {
2502 4 : dw->myTrains.insert(veh);
2503 4 : veh->addReminder(dw);
2504 : }
2505 39 : }
2506 43 : }
2507 :
2508 : const MSDriveWay*
2509 0 : MSDriveWay::retrieveDepartDriveWay(const MSEdge* edge, const std::string& id) {
2510 0 : for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2511 0 : if (dw->getID() == id) {
2512 : return dw;
2513 : }
2514 : }
2515 : return nullptr;
2516 : }
2517 :
2518 :
2519 : bool
2520 1563 : MSDriveWay::hasTrain(SUMOVehicle* veh) const {
2521 1563 : return myTrains.count(veh) != 0;
2522 : }
2523 :
2524 : /****************************************************************************/
|