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 41523 : MSDriveWay::init() {
81 41523 : myWriteVehicles = OptionsCont::getOptions().isSet("railsignal-vehicle-output");
82 41523 : myMovingBlockMaxDist = OptionsCont::getOptions().getFloat("railsignal.moving-block.max-dist");
83 41523 : }
84 :
85 : // ===========================================================================
86 : // MSDriveWay method definitions
87 : // ===========================================================================
88 :
89 :
90 22502 : MSDriveWay::MSDriveWay(const MSLink* origin, const std::string& id, bool temporary) :
91 45004 : MSMoveReminder("DriveWay_" + (temporary ? "tmp" : id)),
92 : Named(id),
93 10390 : myNumericalID(temporary ? -1 : myGlobalDriveWayIndex++),
94 22502 : myOrigin(origin),
95 22502 : myActive(nullptr),
96 22502 : myCoreSize(0),
97 22502 : myForwardEdgeCount(0),
98 22502 : myFoundSignal(false),
99 22502 : myFoundJump(false),
100 22502 : myTerminateRoute(false),
101 22502 : myAbortedBuild(false),
102 22502 : myBidiEnded(false),
103 77896 : myIsSubDriveway(false)
104 22502 : {}
105 :
106 :
107 32892 : MSDriveWay::~MSDriveWay() {
108 24681 : for (const MSDriveWay* sub : mySubDriveWays) {
109 2179 : delete sub;
110 : }
111 : mySubDriveWays.clear();
112 100398 : }
113 :
114 : void
115 41182 : MSDriveWay::cleanup() {
116 41182 : myGlobalDriveWayIndex = 0;
117 : myBlockLengthWarnings.clear();
118 41182 : myWriteVehicles = false;
119 :
120 44078 : for (auto item : myDepartureDriveways) {
121 6025 : for (MSDriveWay* dw : item.second) {
122 3129 : 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 41182 : }
132 :
133 : void
134 168 : MSDriveWay::clearState() {
135 193 : for (auto item : myEndingDriveways) {
136 50 : for (MSDriveWay* dw : item.second) {
137 : dw->myTrains.clear();
138 : }
139 : }
140 168 : }
141 :
142 :
143 : bool
144 33232 : 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.getEdge()->getID() : Named::getIDSecure(enteredLane)) << " reason=" << reason << "\n";
147 : #endif
148 66464 : if (veh.isVehicle() && (enteredLane == myLane || (MSGlobals::gUseMesoSim && veh.getEdge() == &myLane->getEdge()))
149 65067 : && (reason == NOTIFICATION_DEPARTED || reason == NOTIFICATION_JUNCTION || reason == NOTIFICATION_PARKING)) {
150 31750 : SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
151 31750 : MSRouteIterator firstIt = std::find(sveh.getCurrentRouteEdge(), sveh.getRoute().end(), myLane->getNextNormal());
152 31750 : if (match(firstIt, sveh.getRoute().end())) {
153 19602 : if (myTrains.count(&sveh) == 0) {
154 19558 : enterDriveWay(sveh, reason);
155 : }
156 19580 : return true;
157 : }
158 1482 : } else if (reason == NOTIFICATION_REROUTE) {
159 : assert(veh.isVehicle());
160 1427 : SUMOVehicle& sveh = dynamic_cast<SUMOVehicle&>(veh);
161 : assert(myTrains.count(&sveh) == 0);
162 1427 : int movedPast = matchesPastRoute(sveh);
163 : // vehicle must still be one the drivway
164 1427 : if (movedPast >= 0 && movedPast < myForwardEdgeCount) {
165 717 : enterDriveWay(sveh, reason);
166 717 : return true;
167 : }
168 : }
169 : return false;
170 : }
171 :
172 :
173 : bool
174 111650 : MSDriveWay::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, Notification reason, const MSLane* enteredLane) {
175 : UNUSED_PARAMETER(enteredLane);
176 : #ifdef DEBUG_MOVEREMINDER
177 : std::cout << SIMTIME << " notifyLeave " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(enteredLane) << " reason=" << toString(reason) << "\n";
178 : #endif
179 111650 : if (veh.isVehicle()) {
180 : // leaving network with departure, teleport etc
181 111650 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
182 6137 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
183 6137 : if (myWriteVehicles) {
184 626 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
185 : }
186 6137 : return false;
187 105513 : } else if (MSGlobals::gUseMesoSim && reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
188 : // notifyLeave is called before moving the route iterator
189 7242 : const MSLane* leftLane = (*(dynamic_cast<SUMOVehicle&>(veh).getCurrentRouteEdge()))->getLanes().front();
190 7242 : return notifyLeaveBack(veh, reason, leftLane);
191 : } else {
192 : return true;
193 : }
194 : } else {
195 : return false;
196 : }
197 : }
198 :
199 :
200 : bool
201 77130 : MSDriveWay::notifyLeaveBack(SUMOTrafficObject& veh, Notification reason, const MSLane* leftLane) {
202 : #ifdef DEBUG_MOVEREMINDER
203 : std::cout << SIMTIME << " notifyLeaveBack " << getDescription() << " veh=" << veh.getID() << " lane=" << Named::getIDSecure(leftLane) << " reason=" << toString(reason) << "\n";
204 : #endif
205 77130 : if (veh.isVehicle()) {
206 77130 : if (leftLane == myForward.back() && (veh.getBackLane() != leftLane->getBidiLane() || MSGlobals::gUseMesoSim)) {
207 13484 : myTrains.erase(&dynamic_cast<SUMOVehicle&>(veh));
208 13484 : if (myWriteVehicles) {
209 1286 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), reason));
210 : }
211 13484 : return false;
212 : } else {
213 63646 : return true;
214 : }
215 : } else {
216 : return false;
217 : }
218 : }
219 :
220 :
221 : bool
222 1437 : MSDriveWay::notifyReroute(SUMOTrafficObject& veh) {
223 : #ifdef DEBUG_MOVEREMINDER
224 : std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << "\n";
225 : #endif
226 : assert(veh.isVehicle());
227 1437 : SUMOVehicle* sveh = dynamic_cast<SUMOVehicle*>(&veh);
228 : assert(myTrains.count(sveh) != 0);
229 1437 : if (matchesPastRoute(*sveh) >= 0) {
230 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
231 : return true;
232 : }
233 : // no match found, remove
234 : myTrains.erase(sveh);
235 701 : if (myWriteVehicles) {
236 30 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, false, veh.getID(), NOTIFICATION_REROUTE));
237 : }
238 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " invalid\n";
239 : return false;
240 : }
241 :
242 :
243 : int
244 2864 : MSDriveWay::matchesPastRoute(SUMOVehicle& sveh) const {
245 : // look backwards along the route to find the driveway lane
246 2864 : const ConstMSEdgeVector& routeEdges = sveh.getRoute().getEdges();
247 18751 : for (int i = sveh.getRoutePosition(); i >= 0; i--) {
248 18335 : if (routeEdges[i] == myLane->getNextNormal()) {
249 : MSRouteIterator firstIt = routeEdges.begin() + i;
250 2448 : if (match(firstIt, sveh.getRoute().end())) {
251 : // driveway is still valid after rerouting
252 : //std::cout << SIMTIME << " notifyReroute " << getDescription() << " veh=" << veh.getID() << " valid\n";
253 1552 : return sveh.getRoutePosition() - i;
254 : }
255 896 : break;
256 : }
257 : }
258 : return -1;
259 : }
260 :
261 :
262 : void
263 20275 : MSDriveWay::enterDriveWay(SUMOVehicle& sveh, Notification reason) {
264 20275 : myTrains.insert(&sveh);
265 20275 : if (myOrigin != nullptr) {
266 13995 : MSRailSignalControl::getInstance().notifyApproach(myOrigin);
267 : }
268 65924 : for (const MSDriveWay* foe : myFoes) {
269 45649 : if (foe->myOrigin != nullptr) {
270 36427 : MSRailSignalControl::getInstance().notifyApproach(foe->myOrigin);
271 : }
272 : }
273 20275 : if (myWriteVehicles) {
274 1930 : myVehicleEvents.push_back(VehicleEvent(SIMSTEP, true, sveh.getID(), reason));
275 : }
276 20275 : }
277 :
278 : bool
279 600648 : MSDriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
280 600648 : if (foeDriveWayOccupied(true, closest.first, occupied)) {
281 : return false;
282 : }
283 496124 : for (MSLink* foeLink : myConflictLinks) {
284 136501 : if (hasLinkConflict(closest, foeLink)) {
285 : #ifdef DEBUG_SIGNALSTATE
286 : if (gDebugFlag4 || DEBUG_HELPER(closest.first)) {
287 : std::cout << getID() << " linkConflict with " << getTLLinkID(foeLink) << "\n";
288 : }
289 : #endif
290 : return false;
291 : }
292 : }
293 359623 : myActive = closest.first;
294 359623 : return true;
295 : }
296 :
297 :
298 : bool
299 136501 : MSDriveWay::hasLinkConflict(const Approaching& veh, const MSLink* foeLink) const {
300 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
301 : if (gDebugFlag4) {
302 : std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << " ego=" << Named::getIDSecure(veh.first) << "\n";
303 : }
304 : #endif
305 136501 : if (foeLink->getApproaching().size() > 0) {
306 45416 : Approaching foe = foeLink->getClosest();
307 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
308 : if (gDebugFlag4) {
309 : std::cout << " approaching foe=" << foe.first->getID() << "\n";
310 : }
311 : #endif
312 45416 : if (foe.first == veh.first) {
313 45416 : return false;
314 : }
315 : const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
316 : assert(foeTLL != nullptr);
317 40605 : const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
318 : MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
319 40605 : if (foeRS != nullptr) {
320 40605 : const MSDriveWay& foeDriveWay = foeRS->retrieveDriveWayForVeh(foeLink->getTLIndex(), foe.first);
321 : MSEdgeVector occupied;
322 65558 : if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied) ||
323 41312 : !foeRS->constraintsAllow(foe.first) ||
324 32437 : !overlap(foeDriveWay) ||
325 56683 : !isFoeOrSubFoe(&foeDriveWay) ||
326 12658 : canUseSiding(veh.first, &foeDriveWay).first) {
327 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
328 : if (gDebugFlag4) {
329 : if (foeDriveWay.foeDriveWayOccupied(false, foe.first, occupied)) {
330 : std::cout << " foe blocked\n";
331 : } else if (!foeRS->constraintsAllow(foe.first)) {
332 : std::cout << " foe constrained\n";
333 : } else if (!overlap(foeDriveWay)) {
334 : std::cout << " no overlap with foeDW=" << foeDriveWay.getID() << "\n";
335 : } else if (!isFoeOrSubFoe(&foeDriveWay)) {
336 : std::cout << " foeDW=" << foeDriveWay.getID() << " is not a foe to " << getID() << "\n";
337 : } else if (canUseSiding(veh.first, &foeDriveWay).first) {
338 : std::cout << " use siding\n";
339 : }
340 : }
341 : #endif
342 28085 : return false;
343 : }
344 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
345 : if (gDebugFlag4) {
346 : std::cout
347 : << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
348 : << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
349 : << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
350 : << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
351 : << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
352 : << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
353 : << "\n";
354 : }
355 : #endif
356 12520 : const bool yield = mustYield(veh, foe);
357 12520 : if (MSRailSignal::storeVehicles()) {
358 540 : MSRailSignal::rivalVehicles().push_back(foe.first);
359 540 : if (yield) {
360 315 : MSRailSignal::priorityVehicles().push_back(foe.first);
361 : }
362 : }
363 12520 : return yield;
364 40605 : }
365 : }
366 : return false;
367 : }
368 :
369 :
370 : bool
371 26191 : MSDriveWay::isFoeOrSubFoe(const MSDriveWay* foe) const {
372 26191 : if (std::find(myFoes.begin(), myFoes.end(), foe) != myFoes.end()) {
373 : return true;
374 : }
375 18035 : for (const MSDriveWay* sub : foe->mySubDriveWays) {
376 10113 : if (isFoeOrSubFoe(sub)) {
377 : return true;
378 : }
379 : }
380 : return false;
381 : }
382 :
383 :
384 : bool
385 12520 : MSDriveWay::mustYield(const Approaching& veh, const Approaching& foe) {
386 12520 : if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
387 8070 : if (foe.second.arrivalTime == veh.second.arrivalTime) {
388 616 : if (foe.first->getSpeed() == veh.first->getSpeed()) {
389 592 : if (foe.second.dist == veh.second.dist) {
390 556 : if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
391 538 : return foe.first->getNumericalID() < veh.first->getNumericalID();
392 : } else {
393 18 : return foe.first->getWaitingTime() > veh.first->getWaitingTime();
394 : }
395 : } else {
396 36 : return foe.second.dist < veh.second.dist;
397 : }
398 : } else {
399 24 : return foe.first->getSpeed() > veh.first->getSpeed();
400 : }
401 : } else {
402 7454 : return foe.second.arrivalTime < veh.second.arrivalTime;
403 : }
404 : } else {
405 4450 : return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
406 : }
407 : }
408 :
409 :
410 : bool
411 16035 : MSDriveWay::conflictLaneOccupied(bool store, const SUMOVehicle* ego) const {
412 210513 : for (const MSLane* lane : myConflictLanes) {
413 : if (!lane->isEmpty()) {
414 4410 : std::string joinVehicle = "";
415 4410 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
416 0 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
417 0 : if (stop != nullptr) {
418 0 : joinVehicle = stop->join;
419 : }
420 : }
421 : #ifdef DEBUG_SIGNALSTATE
422 : if (gDebugFlag4) {
423 : std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
424 : if (joinVehicle != "") {
425 : std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
426 : lane->releaseVehicles();
427 : }
428 : }
429 : #endif
430 4410 : if (lane->getVehicleNumberWithPartials() == 1) {
431 4410 : MSVehicle* foe = lane->getLastAnyVehicle();
432 4410 : if (joinVehicle != "") {
433 0 : if (foe->getID() == joinVehicle && foe->isStopped()) {
434 : #ifdef DEBUG_SIGNALSTATE
435 : if (gDebugFlag4) {
436 : std::cout << " ignore join-target '" << joinVehicle << "\n";
437 : }
438 : #endif
439 0 : continue;
440 : }
441 : }
442 4410 : if (ego != nullptr) {
443 0 : if (foe == ego && std::find(myForward.begin(), myForward.end(), lane) == myForward.end()) {
444 : #ifdef DEBUG_SIGNALSTATE
445 : if (gDebugFlag4) {
446 : std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
447 : }
448 : #endif
449 0 : continue;
450 : }
451 0 : if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
452 : #ifdef DEBUG_SIGNALSTATE
453 : if (gDebugFlag4) {
454 : std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
455 : }
456 : #endif
457 0 : continue;
458 : }
459 : }
460 : }
461 4410 : if (MSRailSignal::storeVehicles() && store) {
462 4410 : MSRailSignal::blockingVehicles().push_back(lane->getLastAnyVehicle());
463 : }
464 : return true;
465 : }
466 : }
467 11625 : return false;
468 : }
469 :
470 :
471 : bool
472 8076336 : MSDriveWay::foeDriveWayApproached() const {
473 16260700 : for (const MSDriveWay* foeDW : myFoes) {
474 16199099 : if (foeDW->myOrigin != nullptr && foeDW->myOrigin->getApproaching().size() > 0) {
475 : #ifdef DEBUG_SIGNALSTATE
476 : if (gDebugFlag4) {
477 : std::cout << SIMTIME << " foeLink=" << foeDW->myOrigin->getDescription() << " approachedBy=" << foeDW->myOrigin->getApproaching().begin()->first->getID() << "\n";
478 : }
479 : #endif
480 : return true;
481 : }
482 : }
483 : return false;
484 : }
485 :
486 :
487 : bool
488 9354605 : MSDriveWay::foeDriveWayOccupied(bool store, const SUMOVehicle* ego, MSEdgeVector& occupied) const {
489 27390544 : for (const MSDriveWay* foeDW : myFoes) {
490 18928174 : if (!foeDW->myTrains.empty()) {
491 : #ifdef DEBUG_SIGNALSTATE
492 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
493 : std::cout << SIMTIME << " " << getID() << " foeDriveWay " << foeDW->getID() << " occupied ego=" << Named::getIDSecure(ego) << " foeVeh=" << toString(foeDW->myTrains) << "\n";
494 : }
495 : #endif
496 918619 : if (foeDW->myTrains.size() == 1) {
497 916769 : SUMOVehicle* foe = *foeDW->myTrains.begin();
498 916769 : if (foe == ego) {
499 : #ifdef DEBUG_SIGNALSTATE
500 : if (gDebugFlag4 || DEBUG_HELPER(ego)) {
501 : std::cout << " ignore ego as foe '" << Named::getIDSecure(ego) << "\n";
502 : }
503 : #endif
504 26472 : continue;
505 : }
506 895548 : if (hasJoin(ego, foe)) {
507 36 : continue;
508 : }
509 : }
510 897362 : std::pair<bool, const MSDriveWay*> useSiding = canUseSiding(ego, foeDW);
511 : #ifdef DEBUG_SIGNALSTATE
512 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
513 : auto it = mySidings.find(foeDW);
514 : int numSidings = 0;
515 : if (it != mySidings.end()) {
516 : numSidings = it->second.size();
517 : }
518 : std::cout << " useSiding=" << useSiding.first << " sidingFoe=" << Named::getIDSecure(useSiding.second) << " numSidings=" << numSidings << "\n";
519 : }
520 : #endif
521 897362 : if (useSiding.first) {
522 5215 : continue;
523 : } else {
524 892147 : if (MSRailSignal::storeVehicles() && store) {
525 740 : for (SUMOVehicle* foe : foeDW->myTrains) {
526 370 : MSRailSignal::blockingVehicles().push_back(foe);
527 : }
528 370 : MSRailSignal::blockingDriveWays().push_back(foeDW);
529 : }
530 1787159 : for (const SUMOVehicle* foe : foeDW->myTrains) {
531 895012 : occupied.push_back(const_cast<MSEdge*>(foe->getEdge()));
532 895012 : MSEdge* bidi = const_cast<MSEdge*>(foe->getEdge()->getBidiEdge());
533 895012 : if (bidi != nullptr) {
534 481302 : occupied.push_back(bidi);
535 : }
536 : /// @todo: if foe occupies more than one edge we should add all of them to the occupied vector
537 : }
538 298223 : if (ego != nullptr && MSGlobals::gTimeToTeleportRSDeadlock > 0
539 1135785 : && (ego->getWaitingTime() > ego->getVehicleType().getCarFollowModel().getStartupDelay() || !ego->isOnRoad())) {
540 : // if there is an occupied siding, it becomes part of the waitRelation
541 137140 : SUMOVehicle* foe = *(useSiding.second == nullptr ? foeDW : useSiding.second)->myTrains.begin();
542 137140 : const MSRailSignal* rs = myOrigin != nullptr ? dynamic_cast<const MSRailSignal*>(myOrigin->getTLLogic()) : nullptr;
543 137140 : MSRailSignalControl::getInstance().addWaitRelation(ego, rs, foe);
544 : }
545 892147 : return true;
546 : }
547 18009555 : } else if (foeDW != this && isDepartDriveway() && !foeDW->isDepartDriveway()) {
548 9280 : if (foeDW->myOrigin->getApproaching().size() > 0) {
549 1643 : Approaching foeA = foeDW->myOrigin->getClosest();
550 1643 : const SUMOVehicle* foe = foeA.first;
551 1643 : if (foeA.second.dist < foe->getBrakeGap(true)) {
552 131 : MSRouteIterator firstIt = std::find(foe->getCurrentRouteEdge(), foe->getRoute().end(), foeDW->myRoute.front());
553 131 : if (firstIt != foe->getRoute().end()) {
554 131 : if (foeDW->match(firstIt, foe->getRoute().end())) {
555 88 : bool useSiding = canUseSiding(ego, foeDW).first;
556 : #ifdef DEBUG_SIGNALSTATE
557 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
558 : std::cout << SIMTIME << " " << getID() << " blocked by " << foeDW->getID() << " (approached by " << foe->getID() << ") useSiding=" << useSiding << "\n";
559 : }
560 : #endif
561 88 : if (useSiding) {
562 : //std::cout << SIMTIME << " " << getID() << " ego=" << ego->getID() << " foeDW=" << foeDW->getID() << " myFoes=" << toString(myFoes) << "\n";
563 0 : continue;
564 : } else {
565 88 : return true;
566 : }
567 : }
568 : }
569 : }
570 : }
571 : }
572 : }
573 8463385 : for (const std::set<const MSDriveWay*>& dlFoes : myDeadlocks) {
574 : bool allOccupied = true;
575 10108 : for (const MSDriveWay* dlFoe : dlFoes) {
576 7452 : if (dlFoe->myTrains.empty()) {
577 : allOccupied = false;
578 : //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck clear " << dlFoe->getID() << "\n";
579 : break;
580 : }
581 : }
582 3671 : if (allOccupied) {
583 : #ifdef DEBUG_SIGNALSTATE
584 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
585 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " deadlockCheck " << joinNamedToString(dlFoes, " ") << "\n";
586 : }
587 : #endif
588 8645 : for (const MSDriveWay* dlFoe : dlFoes) {
589 5989 : MSRailSignal::blockingDriveWays().push_back(dlFoe);
590 : }
591 : return true;
592 : }
593 : }
594 : return false;
595 : }
596 :
597 :
598 : bool
599 895548 : MSDriveWay::hasJoin(const SUMOVehicle* ego, const SUMOVehicle* foe) {
600 895548 : if (ego != nullptr && !MSGlobals::gUseMesoSim) {
601 234698 : std::string joinVehicle = "";
602 234698 : const SUMOVehicleParameter::Stop* stop = ego->getNextStopParameter();
603 234698 : if (stop != nullptr) {
604 92612 : joinVehicle = stop->join;
605 : }
606 234698 : if (joinVehicle == "" && !ego->hasDeparted() && ego->getStops().size() > 1) {
607 : // check one more stop
608 7441 : auto it = ego->getStops().begin();
609 : std::advance(it, 1);
610 7441 : joinVehicle = it->pars.join;
611 : }
612 234698 : if (joinVehicle != "") {
613 : #ifdef DEBUG_SIGNALSTATE
614 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
615 : std::cout << " joinVehicle=" << joinVehicle << "\n";
616 : }
617 : #endif
618 345 : if (foe->getID() == joinVehicle && foe->isStopped()) {
619 : #ifdef DEBUG_SIGNALSTATE
620 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
621 : std::cout << " ignore join-target '" << joinVehicle << "\n";
622 : }
623 : #endif
624 : return true;
625 : }
626 : }
627 :
628 234674 : if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
629 : #ifdef DEBUG_SIGNALSTATE
630 : if (gDebugFlag4 || DEBUG_COND_DW(ego) || DEBUG_COND_DW(foe)) {
631 : std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
632 : }
633 : #endif
634 : return true;
635 : }
636 : }
637 : return false;
638 : }
639 :
640 :
641 : std::pair<bool, const MSDriveWay*>
642 913852 : MSDriveWay::canUseSiding(const SUMOVehicle* ego, const MSDriveWay* foe, bool recurse) const {
643 : auto it = mySidings.find(foe);
644 913852 : if (it != mySidings.end()) {
645 14568 : for (auto siding : it->second) {
646 : // assume siding is usuable when computing state for unapproached signal (ego == nullptr)
647 13776 : if (ego == nullptr || siding.length >= ego->getLength()) {
648 : // if the siding is already "reserved" by another vehicle we cannot use it here
649 10425 : const MSEdge* sidingEnd = myRoute[siding.end];
650 24336 : for (MSDriveWay* sidingApproach : myEndingDriveways[sidingEnd]) {
651 18677 : if (!sidingApproach->myTrains.empty()) {
652 : // possibly the foe vehicle can use the other part of the siding
653 5072 : if (recurse) {
654 : const SUMOVehicle* foeVeh = nullptr;
655 3744 : if (!foe->myTrains.empty()) {
656 3730 : foeVeh = *foe->myTrains.begin();
657 14 : } else if (foe->myOrigin != nullptr && foe->myOrigin->getApproaching().size() > 0) {
658 14 : foeVeh = foe->myOrigin->getClosest().first;
659 : }
660 3744 : if (foeVeh == nullptr) {
661 0 : WRITE_WARNINGF("Invalid call to canUseSiding dw=% foe=% ego=% time=%", getID(), foe->getID(), Named::getIDSecure(ego), time2string(SIMSTEP));
662 0 : continue;
663 : }
664 3744 : if (foe->canUseSiding(foeVeh, this, false).first) {
665 306 : continue;
666 : }
667 : }
668 : // possibly the foe vehicle
669 : // @todo: in principle it might still be possible to continue if vehicle that approaches the siding can safely leave the situation
670 : #ifdef DEBUG_SIGNALSTATE
671 : if (gDebugFlag4 || DEBUG_COND_DW2 || DEBUG_HELPER(ego)) {
672 : std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
673 : << " foeVeh=" << toString(foe->myTrains)
674 : << " sidingEnd=" << sidingEnd->getID() << " sidingApproach=" << sidingApproach->getID() << " approaching=" << toString(sidingApproach->myTrains) << "\n";
675 : }
676 : #endif
677 4766 : return std::make_pair(false, sidingApproach);
678 : }
679 : }
680 : //std::cout << SIMTIME << " " << getID() << " ego=" << Named::getIDSecure(ego) << " foe=" << foe->getID()
681 : // << " foeVeh=" << toString(foe->myTrains)
682 : // << " sidingEnd=" << sidingEnd->getID() << "usable\n";
683 5659 : return std::make_pair(true, nullptr);
684 : }
685 : }
686 : }
687 903427 : return std::make_pair(false, nullptr);
688 : }
689 :
690 : bool
691 20097 : MSDriveWay::overlap(const MSDriveWay& other) const {
692 32552 : for (int i = 0; i < myCoreSize; i++) {
693 372946 : for (int j = 0; j < other.myCoreSize; j++) {
694 360491 : const MSEdge* edge = myRoute[i];
695 360491 : const MSEdge* edge2 = other.myRoute[j];
696 : if (edge->getToJunction() == edge2->getToJunction()
697 342867 : || edge->getToJunction() == edge2->getFromJunction()
698 701500 : || edge->getFromJunction() == edge2->getFromJunction()) {
699 : // XXX might be rail_crossing with parallel tracks
700 : return true;
701 : }
702 : }
703 : }
704 : return false;
705 : }
706 :
707 :
708 : bool
709 74562 : MSDriveWay::flankConflict(const MSDriveWay& other) const {
710 247331 : for (const MSLane* lane : myForward) {
711 969712 : for (const MSLane* lane2 : other.myForward) {
712 791550 : if (lane == lane2) {
713 : return true;
714 : }
715 : }
716 2530792 : for (const MSLane* lane2 : other.myBidi) {
717 2355330 : if (lane == lane2) {
718 5282 : if (bidiBlockedBy(other)) {
719 : // it's only a deadlock if both trains block symmetrically
720 : return true;
721 : }
722 : }
723 : }
724 6064405 : for (const MSLane* lane2 : other.myBidiExtended) {
725 5891636 : if (lane == lane2) {
726 20261 : if (bidiBlockedBy(other)) {
727 : // it's only a deadlock if both trains block symmetrically
728 : return true;
729 : }
730 : }
731 : }
732 : }
733 : return false;
734 : }
735 :
736 :
737 : bool
738 64574 : MSDriveWay::crossingConflict(const MSDriveWay& other) const {
739 224636 : for (const MSLane* lane : myForward) {
740 728221 : for (const MSLane* lane2 : other.myForward) {
741 568159 : if (lane->isNormal() && lane2->isNormal() && lane->getEdge().getToJunction() == lane2->getEdge().getToJunction()) {
742 : return true;
743 : }
744 : }
745 : }
746 57049 : if (myOrigin != nullptr && other.myOrigin != nullptr
747 49861 : && myOrigin->getJunction() == other.myOrigin->getJunction()
748 : //&& myForward.front()->isInternal() && other.myForward.front()->isInternal()
749 1241 : && myOrigin->getJunction()->getLogic() != nullptr
750 63846 : && myOrigin->getJunction()->getLogic()->getFoesFor(myOrigin->getIndex()).test(other.myOrigin->getIndex())) {
751 : // switch/crossing is also a rail_signal (direct control)
752 90 : if (!(myForward.front()->isInternal() && other.myForward.front()->isInternal())) {
753 27 : return false;
754 : }
755 : return true;
756 : }
757 62515 : if (other.myOrigin != nullptr && other.myForward.front()->isInternal()) {
758 119255 : for (int i = 0; i < (int)myForward.size() - 1; i++) {
759 77384 : const MSLane* lane = myForward[i];
760 77384 : if (lane->getToJunction() == other.myOrigin->getJunction()) {
761 42 : const MSLane* next = myForward[i + 1];
762 42 : const MSLink* link = lane->getLinkTo(next);
763 42 : if (link && link->getTLLogic() == nullptr) {
764 : // switch/crossing is also a rail_signal (direct control) but own link is uncontrolled
765 42 : if (lane->getToJunction()->getLogic() != nullptr
766 42 : && lane->getToJunction()->getLogic()->getFoesFor(link->getIndex()).test(other.myOrigin->getIndex())) {
767 : // and links are in conflict
768 : return true;
769 : }
770 : }
771 : }
772 : }
773 : }
774 : return false;
775 : }
776 :
777 :
778 : bool
779 25882 : MSDriveWay::bidiBlockedBy(const MSDriveWay& other) const {
780 417432 : for (const MSLane* lane : myBidi) {
781 1376040 : for (const MSLane* lane2 : other.myForward) {
782 984490 : if (lane == lane2) {
783 : return true;
784 : }
785 : }
786 : }
787 442357 : for (const MSLane* lane : myBidiExtended) {
788 1434689 : for (const MSLane* lane2 : other.myForward) {
789 1014979 : if (lane == lane2) {
790 2257 : if (overlap(other)) {
791 : return true;
792 : }
793 : }
794 : }
795 : }
796 : return false;
797 : }
798 :
799 :
800 : bool
801 8153 : MSDriveWay::bidiBlockedByEnd(const MSDriveWay& other) const {
802 8153 : const MSLane* end = other.myForward.back();
803 65509 : for (const MSLane* lane : myBidi) {
804 60121 : if (lane == end) {
805 : return true;
806 : }
807 : }
808 41886 : for (const MSLane* lane : myBidiExtended) {
809 37979 : if (lane == end) {
810 1481 : if (overlap(other)) {
811 : return true;
812 : }
813 : }
814 : }
815 : return false;
816 : }
817 :
818 : bool
819 5769 : MSDriveWay::forwardRouteConflict(std::set<const MSEdge*> forward, const MSDriveWay& other, bool secondCheck) {
820 : int i = 0;
821 62373 : for (const MSEdge* edge2 : other.myRoute) {
822 61571 : if (i == other.myCoreSize) {
823 : return false;
824 : }
825 61571 : i++;
826 61571 : if (edge2 == myForward.front()->getNextNormal() && !secondCheck) {
827 : // foe should not pass from behind through our own forward section
828 : return false;
829 : }
830 : if (forward.count(edge2->getBidiEdge()) != 0) {
831 : return true;
832 : }
833 : }
834 : return false;
835 : }
836 :
837 : void
838 8303 : MSDriveWay::writeBlocks(OutputDevice& od) const {
839 14649 : od.openTag(myIsSubDriveway ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
840 8303 : od.writeAttr(SUMO_ATTR_ID, myID);
841 8303 : od.writeAttr(SUMO_ATTR_VEHICLE, myFirstVehicle);
842 8303 : od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
843 8303 : if (myCoreSize != (int)myRoute.size()) {
844 0 : od.writeAttr("core", myCoreSize);
845 : }
846 8303 : od.openTag("forward");
847 8303 : od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
848 8303 : od.closeTag();
849 8303 : if (!myIsSubDriveway) {
850 6346 : od.openTag("bidi");
851 6346 : od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
852 6346 : if (myBidiExtended.size() > 0) {
853 1951 : od.lf();
854 1951 : od << " ";
855 3902 : od.writeAttr("deadlockCheck", toString(myBidiExtended));
856 : }
857 6346 : od.closeTag();
858 6346 : od.openTag("flank");
859 6346 : od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
860 6346 : od.closeTag();
861 :
862 12692 : od.openTag("conflictLinks");
863 :
864 : std::vector<std::string> signals;
865 10092 : for (MSLink* link : myConflictLinks) {
866 7492 : signals.push_back(getTLLinkID(link));
867 : }
868 6346 : od.writeAttr("signals", joinToStringSorting(signals, " "));
869 12692 : od.closeTag();
870 :
871 : std::vector<std::string> foes;
872 23265 : for (MSDriveWay* dw : myFoes) {
873 16919 : foes.push_back(dw->myID);
874 : }
875 6346 : if (foes.size() > 0) {
876 6205 : od.openTag("foes");
877 6205 : od.writeAttr("driveWays", joinToStringSorting(foes, " "));
878 12410 : od.closeTag();
879 : }
880 6962 : for (auto item : mySidings) {
881 616 : od.openTag("sidings");
882 616 : od.writeAttr("foe", item.first->getID());
883 3163 : for (auto siding : item.second) {
884 2547 : od.openTag("siding");
885 2547 : od.writeAttr("start", myRoute[siding.start]->getID());
886 2547 : od.writeAttr("end", myRoute[siding.end]->getID());
887 2547 : od.writeAttr("length", siding.length);
888 5094 : od.closeTag();
889 : }
890 1232 : od.closeTag();
891 : }
892 6427 : for (auto item : myDeadlocks) {
893 81 : od.openTag("deadlock");
894 81 : od.writeAttr("foes", joinNamedToStringSorting(item, " "));
895 162 : od.closeTag();
896 : }
897 6346 : }
898 16606 : od.closeTag(); // driveWay
899 :
900 10260 : for (const MSDriveWay* sub : mySubDriveWays) {
901 1957 : sub->writeBlocks(od);
902 : }
903 : #ifdef DRIVEWAY_SANITY_CHECK
904 8303 : std::set<MSDriveWay*> uFoes(myFoes.begin(), myFoes.end());
905 8303 : if (uFoes.size() != myFoes.size()) {
906 0 : WRITE_WARNINGF("Duplicate foes in driveway '%'", getID());
907 :
908 : }
909 : #endif
910 8303 : }
911 :
912 :
913 : void
914 841 : MSDriveWay::writeBlockVehicles(OutputDevice& od) const {
915 1494 : od.openTag(myIsSubDriveway ? "subDriveWay" : "driveWay");
916 841 : od.writeAttr(SUMO_ATTR_ID, myID);
917 2784 : for (const VehicleEvent& ve : myVehicleEvents) {
918 2914 : od.openTag(ve.isEntry ? "entry" : "exit");
919 1943 : od.writeAttr(SUMO_ATTR_ID, ve.id);
920 1943 : od.writeAttr(SUMO_ATTR_TIME, time2string(ve.time));
921 1943 : od.writeAttr("reason", Notifications.getString(ve.reason));
922 3886 : od.closeTag(); // event
923 : }
924 1682 : od.closeTag(); // driveWay
925 :
926 1029 : for (const MSDriveWay* sub : mySubDriveWays) {
927 188 : sub->writeBlockVehicles(od);
928 : }
929 841 : }
930 :
931 :
932 : void
933 8211 : MSDriveWay::buildRoute(const MSLink* origin,
934 : MSRouteIterator next, MSRouteIterator end,
935 : LaneVisitedMap& visited,
936 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) {
937 8211 : double length = 0;
938 : bool seekForwardSignal = true;
939 : bool seekBidiSwitch = true;
940 : bool foundUnsafeSwitch = false;
941 8211 : MSLane* toLane = origin ? origin->getViaLaneOrLane() : (*next)->getLanes()[0];
942 21504 : const std::string warnID = origin ? "rail signal " + getClickableTLLinkID(origin) : "insertion lane '" + toLane->getID() + "'";
943 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
944 : if (gDebugFlag4) std::cout << "buildRoute origin=" << warnID << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
945 : << " visited=" << formatVisitedMap(visited) << "\n";
946 : #endif
947 : while (true) {
948 99635 : if (length > MSGlobals::gMaxRailSignalBlockLength) {
949 : // typical block length in germany on main lines is 3-5km on branch lines up to 7km
950 : // special branches that are used by one train exclusively could also be up to 20km in length
951 : // minimum block size in germany is 37.5m (LZB)
952 : // larger countries (USA, Russia) might see blocks beyond 20km)
953 222 : if (seekForwardSignal && myBlockLengthWarnings.count(myRoute.front()) == 0) {
954 222 : WRITE_WARNINGF("Block after % exceeds maximum length (stopped searching after edge '%' (length=%m).",
955 : warnID, toLane->getEdge().getID(), length);
956 : myBlockLengthWarnings.insert(myRoute.front());
957 : }
958 222 : myAbortedBuild = true;
959 : // length exceeded
960 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
961 : if (gDebugFlag4) {
962 : std::cout << " abort: length=" << length << "\n";
963 : }
964 : #endif
965 8211 : return;
966 : }
967 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
968 : if (gDebugFlag4) {
969 : std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
970 : }
971 : #endif
972 99413 : const MSEdge* current = &toLane->getEdge();
973 99413 : if (current->isNormal()) {
974 62281 : myRoute.push_back(current);
975 62281 : if (next != end) {
976 : next++;
977 : }
978 : }
979 99413 : appendMapIndex(visited, toLane);
980 99413 : length += toLane->getLength();
981 99413 : MSLane* bidi = toLane->getBidiLane();
982 99413 : if (seekForwardSignal) {
983 27694 : if (!foundUnsafeSwitch) {
984 27694 : myForward.push_back(toLane);
985 27694 : if (toLane->isNormal()) {
986 18339 : myForwardEdgeCount++;
987 : }
988 27694 : if (myForward.size() == 1) {
989 8211 : myLane = toLane;
990 8211 : if (MSGlobals::gUseMesoSim) {
991 2412 : MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(myLane->getEdge());
992 2412 : s->addDetector(this, myLane->getIndex());
993 : } else {
994 5799 : toLane->addMoveReminder(this, false);
995 : }
996 : }
997 : }
998 71719 : } else if (bidi == nullptr) {
999 22332 : if (toLane->isInternal() && toLane->getIncomingLanes().front().viaLink->isTurnaround()) {
1000 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1001 : if (gDebugFlag4) {
1002 : std::cout << " continue bidiSearch beyond turnaround\n";
1003 : }
1004 : #endif
1005 : } else {
1006 : seekBidiSwitch = false;
1007 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1008 : if (gDebugFlag4) {
1009 : std::cout << " noBidi, abort search for bidiSwitch\n";
1010 : }
1011 : #endif
1012 : }
1013 : }
1014 99413 : if (bidi != nullptr) {
1015 64790 : if (!seekForwardSignal && !foundUnsafeSwitch && bidi->isNormal()) {
1016 : // look for switch that could protect from oncoming vehicles
1017 22992 : for (const MSLink* const link : bidi->getLinkCont()) {
1018 12903 : if (link->getDirection() == LinkDirection::TURN) {
1019 531 : continue;
1020 : }
1021 24586 : if (!myBidi.empty() && link->getViaLaneOrLane() != myBidi.back()) {
1022 2195 : myCoreSize = (int)myRoute.size() - 1;
1023 2195 : MSLink* used = const_cast<MSLink*>(bidi->getLinkTo(myBidi.back()));
1024 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1025 : if (gDebugFlag4) {
1026 : std::cout << " found unsafe switch " << link->getDescription() << " (used=" << (used == nullptr ? "NULL" : used->getDescription()) << ")\n";
1027 : }
1028 : #endif
1029 : // trains along our route beyond this switch might create deadlock
1030 : foundUnsafeSwitch = true;
1031 : // the switch itself must still be guarded to ensure safety
1032 2195 : if (used != nullptr) {
1033 : // possibly nullptr if there was an intermediate section of unidirectional edges
1034 : flankSwitches.insert(used);
1035 : }
1036 : break;
1037 : }
1038 : }
1039 : }
1040 62595 : if (foundUnsafeSwitch) {
1041 32185 : myBidiExtended.push_back(bidi);
1042 : } else {
1043 32605 : myBidi.push_back(bidi);
1044 : }
1045 : }
1046 99413 : const std::vector<MSLink*>& links = toLane->getLinkCont();
1047 99413 : toLane = nullptr;
1048 105832 : for (const MSLink* const link : links) {
1049 95606 : if ((next != end && &link->getLane()->getEdge() == *next)
1050 190010 : && isRailwayOrShared(link->getViaLaneOrLane()->getPermissions())) {
1051 148829 : toLane = link->getViaLaneOrLane();
1052 91780 : if (link->getTLLogic() != nullptr && link->getTLIndex() >= 0 && link->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
1053 26401 : if (link == origin) {
1054 356 : if (seekForwardSignal) {
1055 0 : WRITE_WARNINGF(TL("Found circular block after % (% edges, length %)"), warnID, toString(myRoute.size()), toString(length));
1056 : }
1057 : //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1058 356 : myAbortedBuild = true;
1059 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1060 : if (gDebugFlag4) {
1061 : std::cout << " abort: found circle\n";
1062 : }
1063 : #endif
1064 356 : return;
1065 : }
1066 : seekForwardSignal = false;
1067 26045 : myFoundSignal = true;
1068 : seekBidiSwitch = bidi != nullptr;
1069 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1070 : if (gDebugFlag4) {
1071 : std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1072 : }
1073 : #endif
1074 : }
1075 : //if (links.size() > 1 && !foundUnsafeSwitch) {
1076 91424 : if (isSwitch(link)) {
1077 : // switch on driveway
1078 : //std::cout << "mySwitchDriveWays " << getID() << " link=" << link->getDescription() << "\n";
1079 52044 : mySwitchDriveWays[link].push_back(this);
1080 : }
1081 91424 : if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1082 : // reversal on driveway
1083 1380 : myReversalDriveWays[current].push_back(this);
1084 1380 : myReversals.push_back(current);
1085 : }
1086 : break;
1087 : }
1088 : }
1089 99057 : if (toLane == nullptr) {
1090 7633 : if (next != end) {
1091 : // no connection found, jump to next route edge
1092 : toLane = (*next)->getLanes()[0];
1093 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1094 : if (gDebugFlag4) {
1095 : std::cout << " abort: turn-around or jump\n";
1096 : }
1097 : #endif
1098 87 : myFoundJump = true;
1099 87 : return;
1100 : } else {
1101 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1102 : if (gDebugFlag4) {
1103 : std::cout << " abort: no next lane available\n";
1104 : }
1105 : #endif
1106 7546 : myTerminateRoute = true;
1107 7546 : return;
1108 : }
1109 : }
1110 91424 : }
1111 : myBidiEnded = !seekBidiSwitch;
1112 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1113 : if (gDebugFlag4) {
1114 : std::cout << " normalEnd myBidiEnded=" << myBidiEnded << "\n";
1115 : }
1116 : #endif
1117 : }
1118 :
1119 :
1120 : bool
1121 102464 : MSDriveWay::isSwitch(const MSLink* link) {
1122 198478 : for (const MSLink* other : link->getLaneBefore()->getNormalPredecessorLane()->getLinkCont()) {
1123 112235 : if (other->getLane() != link->getLane() && !other->isTurnaround()) {
1124 : return true;
1125 : }
1126 : }
1127 140289 : for (auto ili : link->getLane()->getIncomingLanes()) {
1128 98397 : if (ili.viaLink != link && !ili.viaLink->isTurnaround()) {
1129 : return true;
1130 : }
1131 : }
1132 41892 : const MSLane* bidi = link->getLane()->getBidiLane();
1133 41892 : if (bidi != nullptr) {
1134 63081 : for (const MSLink* other : bidi->getLinkCont()) {
1135 32642 : if (other->getLane() != link->getLaneBefore()->getNormalPredecessorLane()->getBidiLane() && !other->isTurnaround()) {
1136 : return true;
1137 : }
1138 : }
1139 : }
1140 : return false;
1141 : }
1142 :
1143 :
1144 : void
1145 32844 : MSDriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited,
1146 : bool allFoes, bool movingBlock, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1147 : #ifdef DEBUG_CHECK_FLANKS
1148 : if (gDebugFlag4) std::cout << " checkFlanks lanes=" << toString(lanes) << " allFoes=" << allFoes << "\n";
1149 : #endif
1150 20328 : const MSLink* reverseOriginLink = originLink != nullptr && originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1151 43588 : ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1152 : : nullptr;
1153 : //std::cout << " originLink=" << originLink->getDescription() << "\n";
1154 10744 : if (reverseOriginLink != nullptr) {
1155 10744 : reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1156 : //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1157 : }
1158 128096 : for (int i = 0; i < (int)lanes.size(); i++) {
1159 95252 : const MSLane* lane = lanes[i];
1160 95252 : const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1161 95252 : const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1162 95252 : if (lane->isInternal()) {
1163 32810 : continue;
1164 : }
1165 129668 : for (auto ili : lane->getIncomingLanes()) {
1166 77965 : if (ili.viaLink == originLink
1167 64815 : || ili.viaLink == reverseOriginLink
1168 61792 : || ili.viaLink->getDirection() == LinkDirection::TURN
1169 56594 : || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND
1170 123820 : || (originLink == nullptr && i == 0 && movingBlock)) {
1171 10739 : continue;
1172 : }
1173 56487 : if (ili.lane != prev && ili.lane != next) {
1174 : #ifdef DEBUG_CHECK_FLANKS
1175 : if (gDebugFlag4) 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";
1176 : #endif
1177 : flankSwitches.insert(ili.viaLink);
1178 44791 : } else if (allFoes) {
1179 : // link is part of the driveway, find foes that cross the driveway without entering
1180 12088 : checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1181 : }
1182 : }
1183 : }
1184 32844 : }
1185 :
1186 :
1187 : void
1188 12088 : MSDriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess>& flankSwitches) const {
1189 : #ifdef DEBUG_CHECK_FLANKS
1190 : if (gDebugFlag4) std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1191 : #endif
1192 : const MSJunction* junction = dwLink->getJunction();
1193 12088 : if (junction == nullptr) {
1194 : return; // unregulated junction;
1195 : }
1196 12014 : const MSJunctionLogic* logic = junction->getLogic();
1197 12014 : if (logic == nullptr) {
1198 : return; // unregulated junction;
1199 : }
1200 65728 : for (const MSEdge* in : junction->getIncoming()) {
1201 53786 : if (in->isInternal()) {
1202 27129 : continue;
1203 : }
1204 53728 : for (MSLane* inLane : in->getLanes()) {
1205 27071 : const MSLane* inBidi = inLane->getBidiLane();
1206 37090 : if (isRailwayOrShared(inLane->getPermissions()) && visited.count(inLane) == 0 && (inBidi == nullptr || visited.count(inBidi) == 0)) {
1207 8584 : for (MSLink* link : inLane->getLinkCont()) {
1208 4481 : if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1209 11485 : && visited.count(link->getLane()) == 0) {
1210 : #ifdef DEBUG_CHECK_FLANKS
1211 : if (gDebugFlag4) std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1212 : #endif
1213 630 : if (link->getViaLane() == nullptr) {
1214 : flankSwitches.insert(link);
1215 : } else {
1216 : flankSwitches.insert(link->getViaLane()->getLinkCont().front());
1217 : }
1218 : }
1219 : }
1220 : }
1221 : }
1222 : }
1223 : }
1224 :
1225 : void
1226 14162 : MSDriveWay::findFlankProtection(MSLink* link, MSLink* origLink, std::vector<const MSLane*>& flank) {
1227 : #ifdef DEBUG_CHECK_FLANKS
1228 : if (gDebugFlag4) std::cout << " findFlankProtection link=" << link->getDescription() << " origLink=" << origLink->getDescription() << "\n";
1229 : #endif
1230 14162 : if (link->getCorrespondingEntryLink()->getTLLogic() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1231 2225 : MSLink* entry = const_cast<MSLink*>(link->getCorrespondingEntryLink());
1232 : // guarded by signal
1233 : #ifdef DEBUG_CHECK_FLANKS
1234 : if (gDebugFlag4) std::cout << " flank guarded by " << entry->getTLLogic()->getID() << "\n";
1235 : #endif
1236 : // @note, technically it's enough to collect links from foe driveways
1237 : // but this also adds "unused" conflict links which may aid comprehension
1238 2225 : myConflictLinks.push_back(entry);
1239 2225 : addFoes(entry);
1240 : } else {
1241 : const MSLane* lane = link->getLaneBefore();
1242 : std::vector<MSLink*> predLinks;
1243 23834 : for (auto ili : lane->getIncomingLanes()) {
1244 11897 : if (!ili.viaLink->isTurnaround()) {
1245 11498 : predLinks.push_back(ili.viaLink);
1246 : }
1247 : }
1248 11937 : if (predLinks.size() > 1) {
1249 : // this is a switch
1250 : #ifdef DEBUG_ADD_FOES
1251 : if (gDebugFlag4) std::cout << " predecessors of " << link->getDescription() << " isSwitch\n";
1252 : #endif
1253 687 : for (MSLink* pred : predLinks) {
1254 458 : addSwitchFoes(pred);
1255 : }
1256 11708 : } else if (predLinks.size() == 1) {
1257 11040 : if (isSwitch(link)) {
1258 9625 : addSwitchFoes(link);
1259 : } else {
1260 : // continue upstream via single predecessor
1261 1415 : findFlankProtection(predLinks.front(), origLink, flank);
1262 : }
1263 : }
1264 : // check for insertions
1265 11937 : if (myDepartureDriveways.count(&lane->getEdge()) != 0) {
1266 298 : for (MSDriveWay* foe : myDepartureDriveways[&lane->getEdge()]) {
1267 151 : if (flankConflict(*foe) || crossingConflict(*foe)) {
1268 : #ifdef DEBUG_ADD_FOES
1269 : if (gDebugFlag4) std::cout << " foe " << foe->getID() << " departs on flank=" << lane->getID() << "\n";
1270 : #endif
1271 111 : myFoes.push_back(foe);
1272 : } else {
1273 : #ifdef DEBUG_ADD_FOES
1274 : if (gDebugFlag4) std::cout << " cand foe " << foe->getID() << " departs on flank=" << lane->getID() << " rejected\n";
1275 : #endif
1276 : }
1277 : }
1278 : }
1279 11937 : }
1280 14162 : }
1281 :
1282 :
1283 : void
1284 10083 : MSDriveWay::addSwitchFoes(MSLink* link) {
1285 : auto it = mySwitchDriveWays.find(link);
1286 10083 : if (it != mySwitchDriveWays.end()) {
1287 : #ifdef DEBUG_ADD_FOES
1288 : if (gDebugFlag4) std::cout << " driveway " << myID << " addSwitchFoes for link " << link->getDescription() << "\n";
1289 : #endif
1290 33971 : for (MSDriveWay* foe : it->second) {
1291 30231 : if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1292 : #ifdef DEBUG_ADD_FOES
1293 : if (gDebugFlag4) std::cout << " foe=" << foe->myID
1294 : << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this)
1295 : << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1296 : #endif
1297 3792 : myFoes.push_back(foe);
1298 : } else {
1299 : #ifdef DEBUG_ADD_FOES
1300 : if (gDebugFlag4) std::cout << " cand=" << foe->myID << "\n";
1301 : #endif
1302 : }
1303 : }
1304 : }
1305 10083 : }
1306 :
1307 :
1308 : MSDriveWay*
1309 8211 : MSDriveWay::buildDriveWay(const std::string& id, const MSLink* link, MSRouteIterator first, MSRouteIterator end) {
1310 : // collect lanes and links that are relevant for setting this signal for the current driveWay
1311 : // For each driveway we collect
1312 : // - conflictLanes (signal must be red if any conflict lane is occupied)
1313 : // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
1314 : // - that cannot break in time (arrivalSpeedBraking > 0)
1315 : // - approached by a vehicle with higher switching priority (see #3941)
1316 : // These objects are construct in steps:
1317 : //
1318 : // forwardBlock
1319 : // - search forward recursive from outgoing lane until controlled railSignal link found
1320 : // -> add all found lanes to conflictLanes
1321 : //
1322 : // bidiBlock (if any forwardBlock edge has bidi edge)
1323 : // - search bidi backward recursive until first switch
1324 : // - from switch search backward recursive all other incoming until controlled rail signal link
1325 : // -> add final links to conflictLinks
1326 : //
1327 : // flanks
1328 : // - search backward recursive from flanking switches
1329 : // until controlled railSignal link or protecting switch is found
1330 : // -> add all found lanes to conflictLanes
1331 : // -> add final links to conflictLinks
1332 8211 : MSDriveWay* dw = new MSDriveWay(link, id);
1333 : LaneVisitedMap visited;
1334 : std::vector<const MSLane*> before;
1335 8211 : MSLane* fromBidi = nullptr;
1336 8211 : if (link != nullptr) {
1337 5082 : appendMapIndex(visited, link->getLaneBefore());
1338 5082 : fromBidi = link->getLaneBefore()->getBidiLane();
1339 : }
1340 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitches; // list of switches that threaten the driveway and for which protection must be found
1341 :
1342 8211 : if (fromBidi != nullptr) {
1343 2768 : before.push_back(fromBidi);
1344 : }
1345 : #ifdef DEBUG_BUILD_DRIVEWAY
1346 : gDebugFlag4 = DEBUG_COND_DW(dw);
1347 : #endif
1348 8211 : dw->buildRoute(link, first, end, visited, flankSwitches);
1349 8211 : dw->myCoreSize = (int)dw->myRoute.size();
1350 :
1351 8211 : MSRailSignal* rs = link ? const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(link->getTLLogic())) : nullptr;
1352 8211 : const bool movingBlock = (rs && rs->isMovingBlock()) || (!rs &&
1353 11340 : (OptionsCont::getOptions().getBool("railsignal-moving-block")
1354 3025 : || MSRailSignalControl::isMovingBlock((*first)->getPermissions())));
1355 :
1356 8211 : dw->checkFlanks(link, dw->myForward, visited, true, movingBlock, flankSwitches);
1357 8211 : dw->checkFlanks(link, dw->myBidi, visited, false, movingBlock, flankSwitches);
1358 8211 : dw->checkFlanks(link, before, visited, true, movingBlock, flankSwitches);
1359 16948 : for (MSLink* fsLink : flankSwitches) {
1360 : #ifdef DEBUG_ADD_FOES
1361 : if (DEBUG_COND_DW(dw)) {
1362 : std::cout << " fsLink=" << fsLink->getDescription() << "\n";
1363 : }
1364 : #endif
1365 8737 : dw->findFlankProtection(fsLink, fsLink, dw->myFlank);
1366 : }
1367 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> flankSwitchesBidiExtended;
1368 8211 : dw->checkFlanks(link, dw->myBidiExtended, visited, false, movingBlock, flankSwitchesBidiExtended);
1369 12221 : for (MSLink* const flink : flankSwitchesBidiExtended) {
1370 : #ifdef DEBUG_ADD_FOES
1371 : if (DEBUG_COND_DW(dw)) {
1372 : std::cout << " fsLinkExtended=" << flink->getDescription() << "\n";
1373 : }
1374 : #endif
1375 4010 : dw->findFlankProtection(flink, flink, dw->myBidiExtended);
1376 : }
1377 : #ifdef DEBUG_BUILD_DRIVEWAY
1378 : if (DEBUG_COND_DW(dw)) {
1379 : std::cout << SIMTIME << " buildDriveWay " << dw->myID << " link=" << (link == nullptr ? "NULL" : link->getDescription())
1380 : << "\n route=" << toString(dw->myRoute)
1381 : << "\n forward=" << toString(dw->myForward)
1382 : << "\n bidi=" << toString(dw->myBidi)
1383 : << "\n bidiEx=" << toString(dw->myBidiExtended)
1384 : << "\n flank=" << toString(dw->myFlank)
1385 : << "\n flankSwitch=" << MSRailSignal::describeLinks(std::vector<MSLink*>(flankSwitches.begin(), flankSwitches.end()))
1386 : << "\n coreSize=" << dw->myCoreSize
1387 : << "\n";
1388 : }
1389 : #endif
1390 8211 : if (!rs || !rs->isMovingBlock()) {
1391 8105 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myForward.begin(), dw->myForward.end());
1392 : }
1393 8211 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myBidi.begin(), dw->myBidi.end());
1394 8211 : dw->myConflictLanes.insert(dw->myConflictLanes.end(), dw->myFlank.begin(), dw->myFlank.end());
1395 8211 : dw->addBidiFoes(rs, false);
1396 8211 : dw->addBidiFoes(rs, true);
1397 8211 : if (!movingBlock) {
1398 : // add driveways that start on the same signal / lane
1399 7923 : dw->addParallelFoes(link, *first);
1400 : }
1401 : // add driveways that reverse along this driveways route
1402 8211 : dw->addReversalFoes(movingBlock);
1403 : // make foes unique and symmetrical
1404 8211 : std::set<MSDriveWay*, ComparatorNumericalIdLess> uniqueFoes(dw->myFoes.begin(), dw->myFoes.end());
1405 : dw->myFoes.clear();
1406 : // check for self-intersecting forward-section in movingBlock mode
1407 8211 : if (movingBlock && uniqueFoes.count(dw) == 0) {
1408 : std::set<const MSJunction*> forwardJunctions;
1409 2698 : for (const MSLane* fw : dw->myForward) {
1410 2454 : if (fw->isNormal()) {
1411 1379 : const MSJunction* fwTo = fw->getEdge().getToJunction();
1412 : if (forwardJunctions.count(fwTo) == 1) {
1413 21 : dw->myFoes.push_back(dw);
1414 : #ifdef DEBUG_ADD_FOES
1415 : if (DEBUG_COND_DW(dw)) {
1416 : std::cout << " self-intersecting movingBlock for dw=" << dw->getID() << "\n";
1417 : }
1418 : #endif
1419 21 : break;
1420 : }
1421 : forwardJunctions.insert(fwTo);
1422 : }
1423 : }
1424 : }
1425 8211 : std::set<MSLink*, MSLink::ComparatorNumericalLaneIdLess> uniqueCLink(dw->myConflictLinks.begin(), dw->myConflictLinks.end());
1426 8211 : const MSEdge* lastEdge = &dw->myForward.back()->getEdge();
1427 14456 : for (MSDriveWay* foe : uniqueFoes) {
1428 6245 : const MSEdge* foeLastEdge = &foe->myForward.back()->getEdge();
1429 6245 : const bool sameLast = foeLastEdge == lastEdge;
1430 6245 : if (sameLast && !movingBlock) {
1431 2456 : dw->myFoes.push_back(foe);
1432 2456 : if (foe != dw) {
1433 2456 : foe->myFoes.push_back(dw);
1434 : }
1435 : } else {
1436 3789 : if (foe->bidiBlockedByEnd(*dw)) {
1437 : #ifdef DEBUG_ADD_FOES
1438 : if (DEBUG_COND_DW(dw)) {
1439 : std::cout << " setting " << dw->getID() << " as foe of " << foe->getID() << "\n";
1440 : }
1441 : #endif
1442 1864 : foe->myFoes.push_back(dw);
1443 1864 : foe->addSidings(dw);
1444 : } else {
1445 1925 : dw->buildSubFoe(foe, movingBlock);
1446 : }
1447 3789 : if (foe != dw) { // check for movingBlock
1448 3766 : if (dw->bidiBlockedByEnd(*foe)) {
1449 : #ifdef DEBUG_ADD_FOES
1450 : if (DEBUG_COND_DW(dw)) {
1451 : std::cout << " addFoeCheckSiding " << foe->getID() << "\n";
1452 : }
1453 : #endif
1454 2043 : dw->myFoes.push_back(foe);
1455 2043 : dw->addSidings(foe);
1456 : } else {
1457 1723 : foe->buildSubFoe(dw, movingBlock);
1458 : }
1459 : }
1460 : }
1461 6245 : if (link) {
1462 4569 : foe->addConflictLink(link);
1463 : }
1464 : // ignore links that have the same start junction
1465 6245 : if (foe->myRoute.front()->getFromJunction() != dw->myRoute.front()->getFromJunction()) {
1466 7784 : for (auto ili : foe->myForward.front()->getIncomingLanes()) {
1467 3580 : if (ili.viaLink->getTLLogic() != nullptr) {
1468 : // ignore links that originate on myBidi
1469 3133 : const MSLane* origin = ili.viaLink->getLaneBefore();
1470 3133 : if (std::find(dw->myBidi.begin(), dw->myBidi.end(), origin) == dw->myBidi.end()) {
1471 : uniqueCLink.insert(ili.viaLink);
1472 : }
1473 : }
1474 : }
1475 : }
1476 : }
1477 : dw->myConflictLinks.clear();
1478 8211 : dw->myConflictLinks.insert(dw->myConflictLinks.begin(), uniqueCLink.begin(), uniqueCLink.end());
1479 8211 : myEndingDriveways[lastEdge].push_back(dw);
1480 8211 : if (!movingBlock) {
1481 : // every driveway is it's own foe (also all driveways that depart in the same block)
1482 18509 : for (MSDriveWay* sameEnd : myEndingDriveways[lastEdge]) {
1483 : if (uniqueFoes.count(sameEnd) == 0) {
1484 8130 : dw->myFoes.push_back(sameEnd);
1485 8130 : if (sameEnd != dw) {
1486 207 : sameEnd->myFoes.push_back(dw);
1487 : }
1488 : }
1489 : }
1490 : }
1491 : #ifdef DEBUG_BUILD_DRIVEWAY
1492 : if (DEBUG_COND_DW(dw)) {
1493 : std::cout << dw->myID << " mb=" << movingBlock << " finalFoes " << toString(dw->myFoes) << "\n";
1494 : }
1495 : gDebugFlag4 = false;
1496 : #endif
1497 8211 : return dw;
1498 8211 : }
1499 :
1500 : std::string
1501 3746 : MSDriveWay::getTLLinkID(const MSLink* link) {
1502 7492 : return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
1503 : }
1504 :
1505 : std::string
1506 0 : MSDriveWay::getJunctionLinkID(const MSLink* link) {
1507 0 : return link->getJunction()->getID() + "_" + toString(link->getIndex());
1508 : }
1509 :
1510 : std::string
1511 5082 : MSDriveWay::getClickableTLLinkID(const MSLink* link) {
1512 15246 : return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
1513 : }
1514 :
1515 : std::string
1516 0 : MSDriveWay::formatVisitedMap(const LaneVisitedMap& visited) {
1517 : UNUSED_PARAMETER(visited);
1518 : /*
1519 : std::vector<const MSLane*> lanes(visited.size(), nullptr);
1520 : for (auto item : visited) {
1521 : lanes[item.second] = item.first;
1522 : }
1523 : for (auto it = lanes.begin(); it != lanes.end();) {
1524 : if (*it == nullptr) {
1525 : it = lanes.erase(it);
1526 : } else {
1527 : it++;
1528 : }
1529 : }
1530 : return toString(lanes);
1531 : */
1532 0 : return "dummy";
1533 : }
1534 :
1535 :
1536 : void
1537 104495 : MSDriveWay::appendMapIndex(LaneVisitedMap& map, const MSLane* lane) {
1538 : // avoid undefined behavior from evaluation order
1539 104495 : const int tmp = (int)map.size();
1540 104495 : map[lane] = tmp;
1541 104495 : }
1542 :
1543 : bool
1544 8981078 : MSDriveWay::match(MSRouteIterator firstIt, MSRouteIterator endIt) const {
1545 : // @todo optimize: it is sufficient to check for specific edges (after each switch)
1546 8981078 : auto itRoute = firstIt;
1547 : auto itDwRoute = myRoute.begin();
1548 : bool match = true;
1549 62319993 : while (itRoute != endIt && itDwRoute != myRoute.end()) {
1550 53529743 : if (*itRoute != *itDwRoute) {
1551 : match = false;
1552 : #ifdef DEBUG_MATCH
1553 : std::cout << " check dw=" << getID() << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
1554 : #endif
1555 : break;
1556 : }
1557 : itRoute++;
1558 : itDwRoute++;
1559 : }
1560 : // if the vehicle arrives before the end of this driveway,
1561 : // we'd rather build a new driveway to avoid superfluous restrictions
1562 8790250 : if (match && itDwRoute == myRoute.end()
1563 17744605 : && (itRoute == endIt || myAbortedBuild || myBidiEnded || myFoundJump || myIsSubDriveway)) {
1564 : //std::cout << " using dw=" << "\n";
1565 8750901 : if (itRoute != endIt) {
1566 : // check whether the current route requires an extended driveway
1567 142390 : const MSEdge* next = *itRoute;
1568 142390 : const MSEdge* prev = myRoute.back();
1569 478 : if (myFoundJump && prev->getBidiEdge() != next && prev->getBidiEdge() != nullptr
1570 142641 : && prev->isConnectedTo(*next, (SUMOVehicleClass)(SVC_RAIL_CLASSES & prev->getPermissions()))) {
1571 : #ifdef DEBUG_MATCH
1572 : std::cout << " check dw=" << getID() << " prev=" << prev->getID() << " next=" << next->getID() << "\n";
1573 : #endif
1574 : return false;
1575 : }
1576 142373 : if (!myFoundJump && prev->getBidiEdge() == next && prev == &myForward.back()->getEdge()) {
1577 : assert(myIsSubDriveway || myBidiEnded);
1578 : // must not leave driveway via reversal
1579 : #ifdef DEBUG_MATCH
1580 : std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, endIt)) << "\n";
1581 : #endif
1582 : return false;
1583 : }
1584 142367 : if (myForward.back()->isInternal() && myForward.back()->getNextNormal() != (*itRoute)) {
1585 : // driveway is part of a direct-control conflict and continues elsewhere
1586 : #ifdef DEBUG_MATCH
1587 : std::cout << getID() << " back=" << myForward.back()->getID() << " noMatch route " << toString(ConstMSEdgeVector(firstIt, itRoute)) << " (direct control)\n";
1588 : #endif
1589 : return false;
1590 : }
1591 : }
1592 8750876 : return true;
1593 : }
1594 : return false;
1595 : }
1596 :
1597 : void
1598 11456 : MSDriveWay::addFoes(const MSLink* link) {
1599 : #ifdef DEBUG_ADD_FOES
1600 : if (gDebugFlag4) std::cout << "driveway " << myID << " addFoes for link " << link->getDescription() << "\n";
1601 : #endif
1602 11456 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
1603 11456 : if (rs != nullptr) {
1604 15834 : for (MSDriveWay* foe : rs->retrieveDriveWays(link->getTLIndex())) {
1605 : #ifdef DEBUG_ADD_FOES
1606 : if (gDebugFlag4) std::cout << " cand foe=" << foe->myID << " fc1=" << flankConflict(*foe) << " fc2=" << foe->flankConflict(*this) << " cc1=" << crossingConflict(*foe) << " cc2=" << foe->crossingConflict(*this) << "\n";
1607 : #endif
1608 4378 : if (foe != this && (flankConflict(*foe) || foe->flankConflict(*this) || crossingConflict(*foe) || foe->crossingConflict(*this))) {
1609 : #ifdef DEBUG_ADD_FOES
1610 : if (gDebugFlag4) std::cout << " foe=" << foe->myID << "\n";
1611 : #endif
1612 3322 : myFoes.push_back(foe);
1613 : }
1614 11456 : }
1615 : }
1616 11456 : }
1617 :
1618 :
1619 : void
1620 16422 : MSDriveWay::addBidiFoes(const MSRailSignal* ownSignal, bool extended) {
1621 : #ifdef DEBUG_ADD_FOES
1622 : if (gDebugFlag4) std::cout << "driveway " << myID << " addBidiFoes extended=" << extended << "\n";
1623 : #endif
1624 16422 : const std::vector<const MSLane*>& bidiLanes = extended ? myBidiExtended : myBidi;
1625 81212 : for (const MSLane* bidi : bidiLanes) {
1626 132674 : for (auto ili : bidi->getIncomingLanes()) {
1627 67884 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(ili.viaLink->getTLLogic());
1628 67884 : if (rs != nullptr && rs != ownSignal &&
1629 67884 : std::find(bidiLanes.begin(), bidiLanes.end(), ili.lane) != bidiLanes.end()) {
1630 4255 : addFoes(ili.viaLink);
1631 : }
1632 : }
1633 64790 : const MSEdge* bidiEdge = &bidi->getEdge();
1634 : if (myDepartureDriveways.count(bidiEdge) != 0) {
1635 3086 : for (MSDriveWay* foe : myDepartureDriveways[bidiEdge]) {
1636 1429 : if (flankConflict(*foe)) {
1637 : #ifdef DEBUG_ADD_FOES
1638 : if (gDebugFlag4) std::cout << " foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << "\n";
1639 : #endif
1640 851 : myFoes.push_back(foe);
1641 : } else {
1642 : #ifdef DEBUG_ADD_FOES
1643 : if (gDebugFlag4) std::cout << " cand foe " << foe->getID() << " departs on bidi=" << bidiEdge->getID() << " rejected\n";
1644 : #endif
1645 : }
1646 : }
1647 : }
1648 : if (myDepartureDrivewaysEnds.count(bidiEdge) != 0) {
1649 2641 : for (MSDriveWay* foe : myDepartureDrivewaysEnds[bidiEdge]) {
1650 1366 : if (flankConflict(*foe)) {
1651 : #ifdef DEBUG_ADD_FOES
1652 : if (gDebugFlag4) std::cout << " foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << "\n";
1653 : #endif
1654 849 : myFoes.push_back(foe);
1655 : } else {
1656 : #ifdef DEBUG_ADD_FOES
1657 : if (gDebugFlag4) std::cout << " cand foe " << foe->getID() << " ends on bidi=" << bidiEdge->getID() << " rejected\n";
1658 : #endif
1659 : }
1660 : }
1661 : }
1662 : }
1663 16422 : }
1664 :
1665 :
1666 : void
1667 7923 : MSDriveWay::addParallelFoes(const MSLink* link, const MSEdge* first) {
1668 : #ifdef DEBUG_ADD_FOES
1669 : if (gDebugFlag4) std::cout << "driveway " << myID << " addParallelFoes\n";
1670 : #endif
1671 7923 : if (link) {
1672 4976 : addFoes(link);
1673 : } else {
1674 : auto it = myDepartureDriveways.find(first);
1675 2947 : if (it != myDepartureDriveways.end()) {
1676 3107 : for (MSDriveWay* foe : it->second) {
1677 : #ifdef DEBUG_ADD_FOES
1678 : if (gDebugFlag4) std::cout << " foe " << foe->getID() << " departs on first=" << first->getID() << "\n";
1679 : #endif
1680 187 : myFoes.push_back(foe);
1681 : }
1682 : }
1683 : }
1684 7923 : }
1685 :
1686 :
1687 : void
1688 8211 : MSDriveWay::addReversalFoes(bool movingBlock) {
1689 : #ifdef DEBUG_ADD_FOES
1690 : if (gDebugFlag4) std::cout << "driveway " << myID << " addReversalFoes\n";
1691 : #endif
1692 : std::set<const MSEdge*> forward;
1693 35905 : for (const MSLane* lane : myForward) {
1694 27694 : if (lane->isNormal()) {
1695 18339 : forward.insert(&lane->getEdge());
1696 : }
1697 : }
1698 : int i = 0;
1699 70492 : for (const MSEdge* e : myRoute) {
1700 18353 : if (forward.count(e) != 0 && !movingBlock) {
1701 : // reversals in our own forward can be ignored because each driveway
1702 : // is automatically a foe of itself by default
1703 : continue;
1704 : }
1705 45455 : if (i == myCoreSize) {
1706 : break;
1707 : }
1708 45455 : i++;
1709 : auto it = myReversalDriveWays.find(e);
1710 45455 : if (it != myReversalDriveWays.end()) {
1711 6336 : for (MSDriveWay* foe : it->second) {
1712 : // check whether the foe reverses into our own forward section
1713 : // (it might reverse again or disappear via arrival)
1714 : #ifdef DEBUG_ADD_FOES
1715 : //std::cout << " candidate foe " << foe->getID() << " reverses on edge=" << e->getID() << " forward=" << joinNamedToString(forward, " ") << " foeRoute=" << toString(foe->myRoute) << "\n";
1716 : #endif
1717 11160 : if (forwardRouteConflict(forward, *foe)) {
1718 : std::set<const MSEdge*> foeForward;
1719 1162 : for (const MSLane* lane : foe->myForward) {
1720 973 : if (lane->isNormal()) {
1721 607 : foeForward.insert(&lane->getEdge());
1722 607 : if (lane->getBidiLane() != nullptr) {
1723 596 : foeForward.insert(lane->getEdge().getBidiEdge());
1724 : }
1725 : }
1726 : }
1727 : #ifdef DEBUG_ADD_FOES
1728 : if (gDebugFlag4) std::cout << " reversal cand=" << foe->getID() << " foeForward " << toString(foeForward) << "\n";
1729 : #endif
1730 378 : if (foe->forwardRouteConflict(foeForward, *this, true)) {
1731 : #ifdef DEBUG_ADD_FOES
1732 : if (gDebugFlag4) std::cout << " foe " << foe->getID() << " reverses on edge=" << e->getID() << "\n";
1733 : #endif
1734 143 : myFoes.push_back(foe);
1735 : }
1736 5391 : } else if (movingBlock && foe == this) {
1737 : #ifdef DEBUG_ADD_FOES
1738 : if (gDebugFlag4) std::cout << " dw " << getID() << " reverses on forward edge=" << e->getID() << " (movingBlock)\n";
1739 : #endif
1740 23 : myFoes.push_back(foe);
1741 : }
1742 : }
1743 : }
1744 : }
1745 8211 : }
1746 :
1747 :
1748 : bool
1749 3648 : MSDriveWay::buildSubFoe(MSDriveWay* foe, bool movingBlock) {
1750 : // Subdriveways (Teilfahrstraße) model the resolution of a driving conflict
1751 : // before a vehicle has left the driveway. This is possible when the driveway diverges from the foe
1752 : // driveway at an earlier point (switch or crossing).
1753 : //
1754 : // We already know that the last edge of this driveway doesn't impact the foe (unless the driveway ends within the block).
1755 : // Remove further edges from the end of the driveway (myForward) until the point of conflict is found.
1756 : //
1757 : // For movingBlock the logic is changed:
1758 : // We remove the conflict-free part as before but then keep removing the conflict part until another non-conconflit part is found
1759 3648 : if (myForward.size() < foe->myForward.size() &&
1760 3648 : myForward == std::vector<const MSLane*>(foe->myForward.begin(), foe->myForward.begin() + myForward.size())) {
1761 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1762 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " is subpart of foe=" << foe->getID() << "\n";
1763 : #endif
1764 29 : foe->myFoes.push_back(this);
1765 29 : return true;
1766 : }
1767 3619 : int subLast = (int)myForward.size() - 2;
1768 3619 : if (movingBlock && myForward.back() == foe->myForward.back()) {
1769 69 : subLast++;
1770 : }
1771 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1772 : if (subLast < 0) {
1773 : if (gDebugFlag4) std::cout << " " << getID() << " cannot build subDriveWay for foe " << foe->getID() << " because myForward has only a single lane\n";
1774 : }
1775 : #endif
1776 : bool foundConflict = false;
1777 : bool flankC = false;
1778 : bool zipperC = false;
1779 : bool crossC = false;
1780 12854 : while (subLast >= 0) {
1781 12112 : const MSLane* lane = myForward[subLast];
1782 12112 : const MSLink* tmpOrigin = subLast > 0 ? myForward[subLast - 1]->getLinkTo(lane) : myOrigin;
1783 12112 : MSDriveWay tmp(tmpOrigin, "tmp", true);
1784 12112 : tmp.myForward.push_back(lane);
1785 12112 : flankC = tmp.flankConflict(*foe);
1786 12112 : const bool bidiConflict = std::find(foe->myBidi.begin(), foe->myBidi.end(), lane) != foe->myBidi.end();
1787 12112 : crossC = tmp.crossingConflict(*foe);
1788 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1789 : if (gDebugFlag4) std::cout << " subLast=" << subLast << " lane=" << lane->getID() << " fc=" << flankC << " cc=" << crossC << " bc=" << bidiConflict << "\n";
1790 : #endif
1791 12112 : if (flankC || crossC || bidiConflict) {
1792 : foundConflict = true;
1793 3188 : if (!movingBlock || bidiConflict) {
1794 : break;
1795 : }
1796 350 : if (((flankC && lane->getFromJunction()->getType() == SumoXMLNodeType::ZIPPER)
1797 52 : || (!flankC && lane->getToJunction()->getType() == SumoXMLNodeType::ZIPPER))
1798 432 : && (isDepartDriveway()
1799 18 : || getForwardDistance(flankC ? subLast - 1 : subLast) > myMovingBlockMaxDist)) {
1800 : zipperC = true;
1801 : foundConflict = false;
1802 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1803 : if (gDebugFlag4) std::cout << " ignored movingBlock zipperConflict\n";
1804 : #endif
1805 18 : if (!flankC && crossC) {
1806 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1807 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
1808 : #endif
1809 : return false;
1810 : }
1811 : }
1812 393 : if (!flankC && crossC) {
1813 : break;
1814 : }
1815 8924 : } else if (foundConflict) {
1816 : break;
1817 : }
1818 9235 : subLast--;
1819 12112 : }
1820 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1821 : if (gDebugFlag4) std::cout << " subLastFinal=" << subLast << " movingBlock=" << movingBlock << " zipperC=" << zipperC << "\n";
1822 : #endif
1823 3610 : if (subLast < 0) {
1824 742 : if (movingBlock && zipperC) {
1825 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1826 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " movingBlock-save\n";
1827 : #endif
1828 : return false;
1829 742 : } else if (&myForward.back()->getEdge() == myRoute.back() && foe->forwardEndOnRoute(this)) {
1830 : // driveway ends in the middle of the block and only the final edge overlaps with the foe driveWay
1831 16 : foe->myFoes.push_back(this);
1832 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1833 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " foe endsOnForward\n";
1834 : #endif
1835 726 : } else if (foe->myTerminateRoute) {
1836 598 : if (bidiBlockedByEnd(*foe) && bidiBlockedBy(*this) && foe->forwardEndOnRoute(this)) {
1837 89 : foe->myFoes.push_back(this);
1838 : // foe will get the sidings
1839 89 : addSidings(foe, true);
1840 : }
1841 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1842 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " terminates\n";
1843 : #endif
1844 128 : } else if (myTerminateRoute && myBidi.size() <= myForward.size()) {
1845 0 : foe->myFoes.push_back(this);
1846 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1847 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " terminates, foe=" << foe->getID() << "\n";
1848 : #endif
1849 0 : return true;
1850 : } else if (foe->myReversals.size() % 2 == 1) {
1851 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1852 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " has " << foe->myReversals.size() << " reversals\n";
1853 : #endif
1854 : } else {
1855 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1856 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " failed\n";
1857 : #endif
1858 : #ifdef SUBDRIVEWAY_WARN_NOCONFLICT
1859 : WRITE_WARNINGF("No point of conflict found between driveway '%' and driveway '%' when creating sub-driveway", getID(), foe->getID());
1860 : #endif
1861 : }
1862 742 : return false;
1863 : }
1864 2868 : int subSize = subLast + 1;
1865 3637 : for (MSDriveWay* cand : mySubDriveWays) {
1866 1436 : if ((int)cand->myForward.size() == subSize) {
1867 : // can re-use existing sub-driveway
1868 667 : foe->myFoes.push_back(cand);
1869 667 : cand->myFoes.push_back(foe);
1870 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1871 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " useExisting=" << cand->getID() << "\n";
1872 : #endif
1873 667 : return true;
1874 : }
1875 : }
1876 2201 : std::vector<const MSLane*> forward(myForward.begin(), myForward.begin() + subSize);
1877 : std::vector<const MSEdge*> route;
1878 11187 : for (const MSLane* lane : forward) {
1879 8986 : if (lane->isNormal()) {
1880 5207 : route.push_back(&lane->getEdge());
1881 : }
1882 : }
1883 2201 : if (route.empty()) {
1884 36 : if (subSize == 1 && crossC
1885 34 : && forward.front()->getFromJunction() == foe->myForward.front()->getFromJunction()
1886 70 : && forward.front()->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1887 : assert(myForward.front()->isInternal());
1888 : // sub-driveway ends after a single internal lane but since the route cannot be empty we add the next edge
1889 34 : route.push_back(foe->myForward.front()->getEdge().getNormalSuccessor());
1890 : } else {
1891 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1892 : if (gDebugFlag4) std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID() << " empty subRoute\n";
1893 : #endif
1894 2 : return false;
1895 : }
1896 : }
1897 2199 : if (myRoute.size() > route.size()) {
1898 : // route continues. make sure the subDriveway does not end with a reversal
1899 2192 : const MSEdge* lastNormal = route.back();
1900 2192 : const MSEdge* nextNormal = myRoute[route.size()];
1901 2192 : if (lastNormal->getBidiEdge() == nextNormal) {
1902 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1903 : if (gDebugFlag4) std::cout << SIMTIME << " abort subFoe dw=" << getID() << " foe=" << foe->getID()
1904 : << " lastNormal=" << lastNormal->getID() << " nextNormal=" << nextNormal->getID() << " endWithReversal\n";
1905 : #endif
1906 : return false;
1907 : }
1908 : }
1909 4358 : MSDriveWay* sub = new MSDriveWay(myOrigin, getID() + "." + toString(mySubDriveWays.size()));
1910 2179 : sub->myLane = myLane;
1911 2179 : sub->myIsSubDriveway = true;
1912 2179 : sub->myForward = forward;
1913 2179 : sub->myRoute = route;
1914 2179 : sub->myCoreSize = (int)sub->myRoute.size();
1915 2179 : myLane->addMoveReminder(sub, false);
1916 :
1917 : // copy trains that are currently on this driveway (and associated entry events)
1918 2312 : for (SUMOVehicle* veh : myTrains) {
1919 133 : auto itOnSub = std::find(sub->myRoute.begin(), sub->myRoute.end(), veh->getEdge());
1920 133 : if (itOnSub != sub->myRoute.end()) {
1921 : sub->myTrains.insert(veh);
1922 : // non-zero is enough to avoid superfluous activation via activateReminders (and removal)
1923 116 : const double pos = sub->myRoute.front()->getLength();
1924 116 : dynamic_cast<MSBaseVehicle*>(veh)->addReminder(sub, pos);
1925 123 : for (const VehicleEvent& ve : myVehicleEvents) {
1926 7 : if (ve.id == veh->getID()) {
1927 7 : sub->myVehicleEvents.push_back(ve);
1928 : }
1929 : }
1930 : }
1931 : }
1932 :
1933 2179 : foe->myFoes.push_back(sub);
1934 2179 : sub->myFoes.push_back(foe);
1935 2179 : mySubDriveWays.push_back(sub);
1936 : #ifdef DEBUG_BUILD_SUBDRIVEWAY
1937 : if (gDebugFlag4) std::cout << SIMTIME << " buildSubFoe dw=" << getID() << " foe=" << foe->getID() << " sub=" << sub->getID() << " route=" << toString(sub->myRoute) << "\n";
1938 : #endif
1939 : return true;
1940 2201 : }
1941 :
1942 :
1943 : double
1944 18 : MSDriveWay::getForwardDistance(int lastIndex) const {
1945 : assert(lastIndex < (int)myForward.size());
1946 : double result = 0;
1947 54 : for (int i = 0; i <= lastIndex; i++) {
1948 36 : result += myForward[i]->getLength();
1949 : }
1950 18 : return result;
1951 : }
1952 :
1953 :
1954 : void
1955 3996 : MSDriveWay::addSidings(MSDriveWay* foe, bool addToFoe) {
1956 3996 : const MSEdge* foeEndBidi = foe->myForward.back()->getEdge().getBidiEdge();
1957 : int forwardNormals = 0;
1958 18071 : for (auto lane : foe->myForward) {
1959 14075 : if (lane->isNormal()) {
1960 9382 : forwardNormals++;
1961 : }
1962 : }
1963 3996 : if (forwardNormals == (int)foe->myRoute.size()) {
1964 : #ifdef DEBUG_BUILD_SIDINGS
1965 : if (gDebugFlag4) std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " forwardNormals=" << forwardNormals << " frSize=" << foe->myRoute.size() << " aborted\n";
1966 : #endif
1967 777 : return;
1968 : }
1969 : auto foeSearchBeg = foe->myRoute.begin() + forwardNormals;
1970 : auto foeSearchEnd = foe->myRoute.end();
1971 3219 : if (foeEndBidi == nullptr) {
1972 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " noBidi\n");
1973 : }
1974 : int i;
1975 : std::vector<int> start;
1976 : std::vector<double> length;
1977 21047 : for (i = 0; i < (int)myRoute.size(); i++) {
1978 21047 : if (myRoute[i] == foeEndBidi) {
1979 : break;
1980 : }
1981 : }
1982 3219 : if (i == (int)myRoute.size()) {
1983 0 : throw ProcessError("checkSiding " + getID() + " foe=" + foe->getID() + " foeEndBidi=" + foeEndBidi->getID() + " not on route\n");
1984 : }
1985 3219 : const MSEdge* next = myRoute[i];
1986 : #ifdef DEBUG_BUILD_SIDINGS
1987 : if (gDebugFlag4) std::cout << "checkSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " next=" << next->getID() << " forwardNormals=" << forwardNormals << " frSize=" << foe->myRoute.size() << " foeSearchBeg=" << (*foeSearchBeg)->getID() << "\n";
1988 : #endif
1989 3219 : i--;
1990 21047 : for (; i >= 0; i--) {
1991 17828 : const MSEdge* cur = myRoute[i];
1992 17828 : if (hasRS(cur, next)) {
1993 5243 : if (std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge()) == foeSearchEnd) {
1994 2876 : start.push_back(i);
1995 2876 : length.push_back(0);
1996 : }
1997 : }
1998 17828 : if (!start.empty()) {
1999 4689 : auto itFind = std::find(foeSearchBeg, foeSearchEnd, cur->getBidiEdge());
2000 4689 : if (itFind != foeSearchEnd) {
2001 : #ifdef DEBUG_BUILD_SIDINGS
2002 : if (gDebugFlag4) std::cout << "endSiding " << getID() << " foe=" << foe->getID() << " i=" << i << " curBidi=" << Named::getIDSecure(cur->getBidiEdge()) << " length=" << toString(length) << "\n";
2003 : #endif
2004 707 : const int firstIndex = i + 1;
2005 707 : if (addToFoe) {
2006 69 : auto& foeSidings = foe->mySidings[this];
2007 : // indices must be mapped onto foe route;
2008 69 : const MSEdge* first = myRoute[firstIndex];
2009 69 : auto itFirst = std::find(foe->myRoute.begin(), foe->myRoute.end(), first);
2010 69 : if (itFirst != foe->myRoute.end()) {
2011 279 : for (int j = 0; j < (int)length.size(); j++) {
2012 221 : const MSEdge* last = myRoute[start[j]];
2013 221 : auto itLast = std::find(itFirst, foe->myRoute.end(), last);
2014 221 : if (itLast != foe->myRoute.end()) {
2015 221 : foeSidings.insert(foeSidings.begin(), Siding((int)(itFirst - foe->myRoute.begin()), (int)(itLast - foe->myRoute.begin()), length[j]));
2016 : }
2017 : }
2018 : }
2019 : } else {
2020 638 : auto& foeSidings = mySidings[foe];
2021 2968 : for (int j = 0; j < (int)length.size(); j++) {
2022 2330 : foeSidings.insert(foeSidings.begin(), Siding(firstIndex, start[j], length[j]));
2023 : }
2024 : }
2025 : start.clear();
2026 : length.clear();
2027 707 : foeSearchBeg = itFind;
2028 : } else {
2029 25300 : for (int j = 0; j < (int)length.size(); j++) {
2030 21318 : length[j] += cur->getLength();
2031 : }
2032 : }
2033 : }
2034 : next = cur;
2035 : }
2036 3219 : }
2037 :
2038 :
2039 : bool
2040 17828 : MSDriveWay::hasRS(const MSEdge* cur, const MSEdge* next) {
2041 17828 : if (cur->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2042 : // check if there is a controlled link between cur and next
2043 13815 : for (auto lane : cur->getLanes()) {
2044 14221 : for (const MSLink* link : lane->getLinkCont()) {
2045 9935 : if (&link->getLane()->getEdge() == next && link->getTLLogic() != nullptr) {
2046 : return true;
2047 : }
2048 : }
2049 : }
2050 : }
2051 : return false;
2052 : }
2053 :
2054 :
2055 : bool
2056 119 : MSDriveWay::forwardEndOnRoute(const MSDriveWay* foe) const {
2057 119 : const MSEdge* foeForwardEnd = &foe->myForward.back()->getNormalPredecessorLane()->getEdge();
2058 119 : return std::find(myRoute.begin(), myRoute.end(), foeForwardEnd) != myRoute.end();
2059 : }
2060 :
2061 : void
2062 4569 : MSDriveWay::addConflictLink(const MSLink* link) {
2063 4569 : if (link->getTLLogic() != nullptr) {
2064 : // ignore links that originate on myBidi
2065 : // and also links from the same junction as my own link
2066 4569 : const MSLane* origin = link->getLaneBefore();
2067 4569 : if (std::find(myBidi.begin(), myBidi.end(), origin) == myBidi.end()) {
2068 3654 : if (link->getJunction() != myRoute.front()->getFromJunction()) {
2069 2184 : if (std::find(myConflictLinks.begin(), myConflictLinks.end(), link) == myConflictLinks.end()) {
2070 1508 : myConflictLinks.push_back(const_cast<MSLink*>(link));
2071 : }
2072 : }
2073 : }
2074 : }
2075 4569 : }
2076 :
2077 : void
2078 306 : MSDriveWay::addDWDeadlock(const std::vector<const MSDriveWay*>& deadlockFoes) {
2079 : std::set<const MSDriveWay*> filtered;
2080 1569 : for (const MSDriveWay* foe : deadlockFoes) {
2081 1263 : if (std::find(myFoes.begin(), myFoes.end(), foe) == myFoes.end()) {
2082 : filtered.insert(foe);
2083 : }
2084 : }
2085 306 : if (std::find(myDeadlocks.begin(), myDeadlocks.end(), filtered) == myDeadlocks.end()) {
2086 81 : myDeadlocks.push_back(filtered);
2087 : //std::cout << getID() << " deadlockFoes=" << toString(deadlockFoes) << "\n";
2088 : }
2089 306 : }
2090 :
2091 : const MSDriveWay*
2092 62139 : MSDriveWay::getDepartureDriveway(const SUMOVehicle* veh, bool init) {
2093 62139 : const MSEdge* edge = init ? veh->getRoute().getEdges()[veh->getDepartEdge()] : veh->getEdge();
2094 : assert(isRailwayOrShared(edge->getPermissions()));
2095 62139 : if (edge->getFromJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
2096 3490 : for (const MSLane* lane : edge->getLanes()) {
2097 3799 : for (auto ili : lane->getIncomingLanes()) {
2098 2328 : const MSLink* entry = ili.viaLink->getCorrespondingEntryLink();
2099 2328 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(entry->getTLLogic());
2100 1693 : if (rs != nullptr) {
2101 1693 : const MSDriveWay* dw = &const_cast<MSRailSignal*>(rs)->retrieveDriveWayForVeh(entry->getTLIndex(), veh);
2102 1693 : if (&dw->myForward.front()->getEdge() == edge) {
2103 : return dw;
2104 : }
2105 : }
2106 : }
2107 : }
2108 : }
2109 64918 : for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2110 61789 : auto matchStart = init ? veh->getRoute().begin() + veh->getDepartEdge() : veh->getCurrentRouteEdge();
2111 61789 : if (dw->match(matchStart, veh->getRoute().end())) {
2112 58462 : return dw;
2113 : }
2114 : }
2115 6258 : const std::string id = edge->getFromJunction()->getID() + ".d" + toString(myDepartDrivewayIndex[edge->getFromJunction()]++);
2116 3129 : MSDriveWay* dw = buildDriveWay(id, nullptr, veh->getCurrentRouteEdge(), veh->getRoute().end());
2117 3129 : myDepartureDriveways[edge].push_back(dw);
2118 3129 : myDepartureDrivewaysEnds[&dw->myForward.back()->getEdge()].push_back(dw);
2119 : dw->setVehicle(veh->getID());
2120 : return dw;
2121 : }
2122 :
2123 :
2124 : void
2125 1441 : MSDriveWay::writeDepatureBlocks(OutputDevice& od, bool writeVehicles) {
2126 3598 : for (auto item : myDepartureDriveways) {
2127 2157 : const MSEdge* edge = item.first;
2128 2157 : if (item.second.size() > 0) {
2129 4314 : od.openTag("departJunction");
2130 2157 : od.writeAttr(SUMO_ATTR_ID, edge->getFromJunction()->getID());
2131 4539 : for (const MSDriveWay* dw : item.second) {
2132 2382 : if (writeVehicles) {
2133 258 : dw->writeBlockVehicles(od);
2134 : } else {
2135 2124 : dw->writeBlocks(od);
2136 : }
2137 : }
2138 4314 : od.closeTag(); // departJunction
2139 : }
2140 : }
2141 1441 : }
2142 :
2143 : void
2144 476 : MSDriveWay::saveState(OutputDevice& out) {
2145 : // all driveways are in myEndingDriveways which makes it convenient
2146 551 : for (auto item : myEndingDriveways) {
2147 164 : for (MSDriveWay* dw : item.second) {
2148 89 : dw->_saveState(out);
2149 107 : for (MSDriveWay* sub : dw->mySubDriveWays) {
2150 18 : sub->_saveState(out);
2151 : }
2152 : }
2153 : }
2154 476 : }
2155 :
2156 : void
2157 107 : MSDriveWay::_saveState(OutputDevice& out) const {
2158 107 : if (!myTrains.empty() || haveSubTrains()) {
2159 73 : out.openTag(myIsSubDriveway ? SUMO_TAG_SUBDRIVEWAY : SUMO_TAG_DRIVEWAY);
2160 38 : out.writeAttr(SUMO_ATTR_ID, getID());
2161 38 : out.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
2162 38 : if (!myTrains.empty()) {
2163 : std::vector<std::string> trainIDs;
2164 76 : for (SUMOVehicle* veh : myTrains) {
2165 38 : trainIDs.push_back(veh->getID());
2166 : }
2167 38 : out.writeAttr(SUMO_ATTR_VEHICLES, toString(trainIDs));
2168 38 : }
2169 76 : out.closeTag();
2170 : }
2171 107 : }
2172 :
2173 :
2174 : bool
2175 69 : MSDriveWay::haveSubTrains() const {
2176 76 : for (MSDriveWay* sub : mySubDriveWays) {
2177 7 : if (!sub->myTrains.empty()) {
2178 : return true;
2179 : }
2180 : }
2181 : return false;
2182 : }
2183 :
2184 : void
2185 38 : MSDriveWay::loadState(const SUMOSAXAttributes& attrs, int tag) {
2186 38 : if ((int)myDriveWayRouteLookup.size() < myGlobalDriveWayIndex) {
2187 100 : for (auto item : myEndingDriveways) {
2188 158 : for (MSDriveWay* dw : item.second) {
2189 81 : myDriveWayRouteLookup[dw->myRoute] = dw;
2190 : }
2191 : }
2192 : }
2193 38 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
2194 : bool ok;
2195 38 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
2196 38 : const std::string edges = attrs.get<std::string>(SUMO_ATTR_EDGES, id.c_str(), ok);
2197 : ConstMSEdgeVector route;
2198 38 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
2199 38 : MSEdge::parseEdgesList(edges, route, id);
2200 : }
2201 : MSDriveWay* dw = nullptr;
2202 38 : if (tag == SUMO_TAG_DRIVEWAY) {
2203 : auto it = myDriveWayRouteLookup.find(route);
2204 35 : if (it == myDriveWayRouteLookup.end()) {
2205 : //WRITE_WARNING(TLF("Unknown driveWay '%' with route '%'", id, edges));
2206 : //return;
2207 0 : throw ProcessError(TLF("Unknown driveWay '%' with route '%'", id, edges));
2208 : }
2209 35 : dw = it->second;
2210 35 : myDriveWayLookup[id] = dw;
2211 : } else {
2212 3 : std::string parentID = id.substr(0, id.rfind('.'));
2213 : auto it = myDriveWayLookup.find(parentID);
2214 3 : if (it == myDriveWayLookup.end()) {
2215 : //WRITE_WARNING(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2216 : //return;
2217 0 : throw ProcessError(TLF("Unknown parent driveway '%' for subDriveWay '%'", parentID, id));
2218 : }
2219 3 : MSDriveWay* parent = it->second;
2220 3 : for (MSDriveWay* sub : parent->mySubDriveWays) {
2221 1 : if (sub->myRoute == route) {
2222 : dw = sub;
2223 : break;
2224 : }
2225 : }
2226 3 : if (dw == nullptr) {
2227 : // missing subdriveways can be ignored. They may have been created
2228 : // as foes for driveways that are not relevant at state loading time
2229 : return;
2230 : }
2231 : }
2232 72 : const std::string vehicles = attrs.getOpt<std::string>(SUMO_ATTR_VEHICLES, id.c_str(), ok, "");
2233 108 : for (const std::string& vehID : StringTokenizer(vehicles).getVector()) {
2234 36 : MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(c.getVehicle(vehID));
2235 36 : if (veh == nullptr) {
2236 0 : throw ProcessError(TLF("Unknown vehicle '%' in driveway '%'", vehID, id));
2237 : }
2238 36 : if (!dw->hasTrain(veh)) {
2239 4 : dw->myTrains.insert(veh);
2240 4 : veh->addReminder(dw);
2241 : }
2242 36 : }
2243 38 : }
2244 :
2245 : const MSDriveWay*
2246 0 : MSDriveWay::retrieveDepartDriveWay(const MSEdge* edge, const std::string& id) {
2247 0 : for (MSDriveWay* dw : myDepartureDriveways[edge]) {
2248 0 : if (dw->getID() == id) {
2249 : return dw;
2250 : }
2251 : }
2252 : return nullptr;
2253 : }
2254 :
2255 :
2256 : bool
2257 1493 : MSDriveWay::hasTrain(SUMOVehicle* veh) const {
2258 1493 : return myTrains.count(veh) != 0;
2259 : }
2260 :
2261 : /****************************************************************************/
|