Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSRailSignal.cpp
15 : /// @author Melanie Weber
16 : /// @author Andreas Kendziorra
17 : /// @author Jakob Erdmann
18 : /// @date Jan 2015
19 : ///
20 : // A rail signal logic
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <cassert>
25 : #include <utility>
26 : #include <vector>
27 : #include <bitset>
28 : #ifdef HAVE_FOX
29 : #include <utils/foxtools/MFXWorkerThread.h>
30 : #endif
31 : #include <utils/iodevices/OutputDevice_COUT.h>
32 : #include <microsim/MSEventControl.h>
33 : #include <microsim/MSNet.h>
34 : #include <microsim/MSEdge.h>
35 : #include <microsim/MSEdgeControl.h>
36 : #include <microsim/MSLane.h>
37 : #include <microsim/MSLink.h>
38 : #include <microsim/MSJunctionLogic.h>
39 : #include <microsim/MSVehicle.h>
40 : #include <microsim/devices/MSDevice_Routing.h>
41 : #include <microsim/devices/MSRoutingEngine.h>
42 : #include <microsim/MSLane.h>
43 :
44 : #include "MSTLLogicControl.h"
45 : #include "MSTrafficLightLogic.h"
46 : #include "MSPhaseDefinition.h"
47 : #include "MSTLLogicControl.h"
48 : #include "MSRailSignalConstraint.h"
49 : #include "MSRailSignalControl.h"
50 : #include "MSRailSignal.h"
51 :
52 : // typical block length in germany on main lines is 3-5km on branch lines up to 7km
53 : // special branches that are used by one train exclusively could also be up to 20km in length
54 : // minimum block size in germany is 37.5m (LZB)
55 : // larger countries (USA, Russia) might see blocks beyond 20km)
56 : #define MAX_BLOCK_LENGTH 20000
57 : #define MAX_SIGNAL_WARNINGS 10
58 :
59 : //#define DEBUG_SELECT_DRIVEWAY
60 : //#define DEBUG_BUILD_DRIVEWAY
61 : //#define DEBUG_DRIVEWAY_UPDATE
62 : //#define DEBUG_DRIVEWAY_BUILDROUTE
63 : //#define DEBUG_CHECK_FLANKS
64 :
65 : //#define DEBUG_SIGNALSTATE
66 : //#define DEBUG_SIGNALSTATE_PRIORITY
67 : //#define DEBUG_FIND_PROTECTION
68 : //#define DEBUG_REROUTE
69 :
70 : #define DEBUG_COND DEBUG_HELPER(this)
71 : #define DEBUG_COND_LINKINFO DEBUG_HELPER(myLink->getTLLogic())
72 : #define DEBUG_HELPER(obj) ((obj)->isSelected())
73 : //#define DEBUG_HELPER(obj) ((obj)->getID() == "")
74 : //#define DEBUG_HELPER(obj) (true)
75 :
76 : // ===========================================================================
77 : // static value definitions
78 : // ===========================================================================
79 : int MSRailSignal::myNumWarnings(0);
80 :
81 : int MSRailSignal::myDriveWayIndex(0);
82 :
83 : bool MSRailSignal::myStoreVehicles(false);
84 : MSRailSignal::VehicleVector MSRailSignal::myBlockingVehicles;
85 : MSRailSignal::VehicleVector MSRailSignal::myRivalVehicles;
86 : MSRailSignal::VehicleVector MSRailSignal::myPriorityVehicles;
87 : std::string MSRailSignal::myConstraintInfo;
88 :
89 : // ===========================================================================
90 : // method definitions
91 : // ===========================================================================
92 2725 : MSRailSignal::MSRailSignal(MSTLLogicControl& tlcontrol,
93 : const std::string& id, const std::string& programID, SUMOTime delay,
94 2725 : const Parameterised::Map& parameters) :
95 : MSTrafficLightLogic(tlcontrol, id, programID, 0, TrafficLightType::RAIL_SIGNAL, delay, parameters),
96 8175 : myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X')), // dummy phase
97 5450 : myPhaseIndex(0) {
98 2725 : myDefaultCycleTime = DELTA_T;
99 2725 : myMovingBlock = OptionsCont::getOptions().getBool("railsignal-moving-block");
100 2725 : MSRailSignalControl::getInstance().addSignal(this);
101 2725 : }
102 :
103 : void
104 2725 : MSRailSignal::init(NLDetectorBuilder&) {
105 2725 : if (myLanes.size() == 0) {
106 9 : WRITE_WARNINGF(TL("Rail signal at junction '%' does not control any links"), getID());
107 : }
108 6647 : for (LinkVector& links : myLinks) { //for every link index
109 3922 : if (links.size() != 1) {
110 0 : throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
111 0 : + " links controlled by index " + toString(links[0]->getTLIndex()));
112 : }
113 7844 : myLinkInfos.push_back(LinkInfo(links[0]));
114 : }
115 2725 : updateCurrentPhase();
116 2725 : setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
117 2725 : myNumLinks = (int)myLinks.size();
118 2725 : }
119 :
120 :
121 5450 : MSRailSignal::~MSRailSignal() {
122 2725 : removeConstraints();
123 8175 : }
124 :
125 :
126 : // ----------- Handling of controlled links
127 : void
128 0 : MSRailSignal::adaptLinkInformationFrom(const MSTrafficLightLogic& logic) {
129 0 : MSTrafficLightLogic::adaptLinkInformationFrom(logic);
130 0 : updateCurrentPhase();
131 0 : }
132 :
133 :
134 : // ------------ Switching and setting current rows
135 : SUMOTime
136 27557889 : MSRailSignal::trySwitch() {
137 27557889 : updateCurrentPhase();
138 27557889 : return DELTA_T;
139 : }
140 :
141 :
142 :
143 : void
144 27560619 : MSRailSignal::updateCurrentPhase() {
145 : #ifdef DEBUG_SIGNALSTATE
146 : gDebugFlag4 = DEBUG_COND;
147 : #endif
148 : // green by default so vehicles can be inserted at the borders of the network
149 : std::string state(myLinks.size(), 'G');
150 81132771 : for (LinkInfo& li : myLinkInfos) {
151 53572152 : if (li.myLink->getApproaching().size() > 0) {
152 6839968 : Approaching closest = getClosest(li.myLink);
153 6839968 : DriveWay& driveway = li.getDriveWay(closest.first);
154 : //std::cout << SIMTIME << " signal=" << getTLLinkID(li.myLink) << " veh=" << closest.first->getID() << " dw:\n";
155 : //driveway.writeBlocks(*OutputDevice_COUT::getDevice());
156 6839968 : const bool mustWait = !constraintsAllow(closest.first);
157 : MSEdgeVector occupied;
158 6839968 : if (mustWait || !driveway.reserve(closest, occupied)) {
159 6564527 : state[li.myLink->getTLIndex()] = 'r';
160 6564527 : if (occupied.size() > 0) {
161 15240 : li.reroute(const_cast<SUMOVehicle*>(closest.first), occupied);
162 : }
163 : #ifdef DEBUG_SIGNALSTATE
164 : if (gDebugFlag4) {
165 : std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " notReserved\n";
166 : }
167 : #endif
168 : } else {
169 275441 : state[li.myLink->getTLIndex()] = 'G';
170 275441 : if (driveway.myFlank.size() > 0 && myCurrentPhase.getState()[li.myLink->getTLIndex()] != 'G') {
171 : // schedule recheck
172 2806 : MSRailSignalControl::getInstance().addGreenFlankSwitch(li.myLink, driveway.myNumericalID);
173 : }
174 : #ifdef DEBUG_SIGNALSTATE
175 : if (gDebugFlag4) {
176 : std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " reserved\n";
177 : }
178 : #endif
179 : }
180 : } else {
181 46732184 : if (li.myDriveways.empty()) {
182 : #ifdef DEBUG_SIGNALSTATE
183 : if (gDebugFlag4) {
184 : std::cout << SIMTIME << " rsl=" << li.getID() << " red for unitialized signal (no driveways yet)\n";
185 : }
186 : #endif
187 26168683 : state[li.myLink->getTLIndex()] = 'r';
188 : } else {
189 : DriveWay& driveway = li.myDriveways.front();
190 41127002 : if (driveway.conflictLaneOccupied() || driveway.conflictLinkApproached()) {
191 : #ifdef DEBUG_SIGNALSTATE
192 : if (gDebugFlag4) {
193 : std::cout << SIMTIME << " rsl=" << li.getID() << " red for default driveway (" << toString(driveway.myRoute) << ")\n";
194 : }
195 : #endif
196 6707440 : state[li.myLink->getTLIndex()] = 'r';
197 : } else {
198 : #ifdef DEBUG_SIGNALSTATE
199 : if (gDebugFlag4) {
200 : std::cout << SIMTIME << " rsl=" << li.getID() << " green for default driveway (" << toString(driveway.myRoute) << ")\n";
201 : }
202 : #endif
203 : }
204 : }
205 : }
206 : }
207 27560619 : if (myCurrentPhase.getState() != state) {
208 : myCurrentPhase.setState(state);
209 18122 : myPhaseIndex = 1 - myPhaseIndex;
210 : }
211 : #ifdef DEBUG_SIGNALSTATE
212 : gDebugFlag4 = false;
213 : #endif
214 27560619 : }
215 :
216 :
217 : bool
218 6859538 : MSRailSignal::constraintsAllow(const SUMOVehicle* veh) const {
219 6859538 : if (myConstraints.size() == 0) {
220 : return true;
221 : } else {
222 12977682 : const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
223 : auto it = myConstraints.find(tripID);
224 6488841 : if (it != myConstraints.end()) {
225 6507886 : for (MSRailSignalConstraint* c : it->second) {
226 : // ignore insertion constraints here
227 6483512 : if (!c->isInsertionConstraint() && !c->cleared()) {
228 : #ifdef DEBUG_SIGNALSTATE
229 : if (gDebugFlag4) {
230 : std::cout << " constraint '" << c->getDescription() << "' not cleared\n";
231 : }
232 : #endif
233 6459471 : if (myStoreVehicles) {
234 0 : myConstraintInfo = c->getDescription();
235 : }
236 : return false;
237 : }
238 : }
239 : }
240 29370 : return true;
241 : }
242 : }
243 :
244 :
245 : void
246 945 : MSRailSignal::addConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
247 945 : myConstraints[tripId].push_back(constraint);
248 945 : }
249 :
250 :
251 : bool
252 257 : MSRailSignal::removeConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
253 : if (myConstraints.count(tripId) != 0) {
254 257 : auto& constraints = myConstraints[tripId];
255 257 : auto it = std::find(constraints.begin(), constraints.end(), constraint);
256 257 : if (it != constraints.end()) {
257 257 : delete *it;
258 : constraints.erase(it);
259 : return true;
260 : }
261 : }
262 : return false;
263 : }
264 :
265 : void
266 2755 : MSRailSignal::removeConstraints() {
267 3532 : for (auto item : myConstraints) {
268 1465 : for (MSRailSignalConstraint* c : item.second) {
269 688 : delete c;
270 : }
271 777 : }
272 : myConstraints.clear();
273 2755 : }
274 :
275 :
276 : // ------------ Static Information Retrieval
277 : int
278 0 : MSRailSignal::getPhaseNumber() const {
279 0 : return 0;
280 : }
281 :
282 : const MSTrafficLightLogic::Phases&
283 2725 : MSRailSignal::getPhases() const {
284 2725 : return myPhases;
285 : }
286 :
287 : const MSPhaseDefinition&
288 0 : MSRailSignal::getPhase(int) const {
289 0 : return myCurrentPhase;
290 : }
291 :
292 : // ------------ Dynamic Information Retrieval
293 : int
294 55141612 : MSRailSignal::getCurrentPhaseIndex() const {
295 55141612 : return myPhaseIndex;
296 : }
297 :
298 : const MSPhaseDefinition&
299 86656 : MSRailSignal::getCurrentPhaseDef() const {
300 86656 : return myCurrentPhase;
301 : }
302 :
303 : // ------------ Conversion between time and phase
304 : SUMOTime
305 0 : MSRailSignal::getPhaseIndexAtTime(SUMOTime) const {
306 0 : return 0;
307 : }
308 :
309 : SUMOTime
310 0 : MSRailSignal::getOffsetFromIndex(int) const {
311 0 : return 0;
312 : }
313 :
314 : int
315 0 : MSRailSignal::getIndexFromOffset(SUMOTime) const {
316 0 : return 0;
317 : }
318 :
319 :
320 : void
321 3922 : MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
322 3922 : if (pos >= 0) {
323 3922 : MSTrafficLightLogic::addLink(link, lane, pos);
324 : } // ignore uncontrolled link
325 3922 : }
326 :
327 :
328 : std::string
329 908 : MSRailSignal::getTLLinkID(MSLink* link) {
330 1816 : return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
331 : }
332 :
333 : std::string
334 421 : MSRailSignal::getJunctionLinkID(MSLink* link) {
335 842 : return link->getJunction()->getID() + "_" + toString(link->getIndex());
336 : }
337 :
338 : std::string
339 7 : MSRailSignal::getClickableTLLinkID(MSLink* link) {
340 14 : return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
341 : }
342 :
343 : std::string
344 0 : MSRailSignal::describeLinks(std::vector<MSLink*> links) {
345 : std::string result;
346 0 : for (MSLink* link : links) {
347 0 : result += link->getDescription() + " ";
348 : }
349 0 : return result;
350 : }
351 :
352 : std::string
353 0 : MSRailSignal::formatVisitedMap(const LaneVisitedMap& visited) {
354 0 : std::vector<const MSLane*> lanes(visited.size(), nullptr);
355 0 : for (auto item : visited) {
356 0 : lanes[item.second] = item.first;
357 : }
358 0 : return toString(lanes);
359 : }
360 :
361 :
362 : void
363 49315 : MSRailSignal::appendMapIndex(LaneVisitedMap& map, const MSLane* lane) {
364 : // avoid undefined behavior from evaluation order
365 49315 : const int tmp = (int)map.size();
366 49315 : map[lane] = tmp;
367 49315 : }
368 :
369 :
370 : MSRailSignal::Approaching
371 6878360 : MSRailSignal::getClosest(MSLink* link) {
372 : assert(link->getApproaching().size() > 0);
373 : double minDist = std::numeric_limits<double>::max();
374 : auto closestIt = link->getApproaching().begin();
375 13767653 : for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
376 6889293 : if (apprIt->second.dist < minDist) {
377 : minDist = apprIt->second.dist;
378 : closestIt = apprIt;
379 : }
380 : }
381 : // maybe a parallel link has a closer vehicle
382 : /*
383 : for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
384 : if (link2 != link) {
385 : for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
386 : if (apprIt2->second.dist < minDist) {
387 : minDist = apprIt2->second.dist;
388 : closestIt = apprIt2;
389 : }
390 : }
391 : }
392 : }
393 : */
394 6878360 : return *closestIt;
395 : }
396 :
397 :
398 : void
399 1469 : MSRailSignal::writeBlocks(OutputDevice& od) const {
400 2938 : od.openTag("railSignal");
401 : od.writeAttr(SUMO_ATTR_ID, getID());
402 3231 : for (const LinkInfo& li : myLinkInfos) {
403 1762 : MSLink* link = li.myLink;
404 3524 : od.openTag("link");
405 3524 : od.writeAttr(SUMO_ATTR_TLLINKINDEX, link->getTLIndex());
406 : od.writeAttr(SUMO_ATTR_FROM, link->getLaneBefore()->getID());
407 : od.writeAttr(SUMO_ATTR_TO, link->getViaLaneOrLane()->getID());
408 3224 : for (const DriveWay& dw : li.myDriveways) {
409 1462 : dw.writeBlocks(od);
410 : }
411 3524 : od.closeTag(); // link
412 : }
413 1469 : od.closeTag(); // railSignal
414 1469 : }
415 :
416 :
417 : void
418 3326 : MSRailSignal::initDriveWays(const SUMOVehicle* ego, bool update) {
419 3326 : const ConstMSEdgeVector& edges = ego->getRoute().getEdges();
420 3326 : int endIndex = ego->getParameter().arrivalEdge;
421 3326 : if (endIndex < 0) {
422 3326 : endIndex = (int)edges.size() - 1;
423 : }
424 22855 : for (int i = ego->getParameter().departEdge; i <= endIndex - 1; i++) {
425 19529 : const MSEdge* e = edges[i];
426 19529 : if (e->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
427 10927 : const MSEdge* e2 = edges[i + 1];
428 21854 : for (MSLane* lane : e->getLanes()) {
429 22362 : for (MSLink* link : lane->getLinkCont()) {
430 11435 : if (&link->getLane()->getEdge() == e2) {
431 8569 : MSRailSignal* rs = const_cast<MSRailSignal*>(dynamic_cast<const MSRailSignal*>(link->getTLLogic()));
432 8569 : if (rs != nullptr) {
433 8569 : LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
434 8569 : if (li.myDriveways.empty()) {
435 : // init driveway
436 2196 : li.getDriveWay(ego);
437 2196 : if (update && rs->isActive()) {
438 : // vehicle may have rerouted its intial trip
439 : // after the states have been set
440 : // @note: This is a hack because it could lead to invalid tls-output
441 : // (it's still an improvement over switching based on default driveways)
442 1550 : rs->trySwitch();
443 1550 : rs->setTrafficLightSignals(SIMSTEP);
444 : }
445 : }
446 : }
447 : }
448 : }
449 : }
450 : }
451 : }
452 3326 : }
453 :
454 :
455 : bool
456 2976 : MSRailSignal::hasOncomingRailTraffic(MSLink* link, const MSVehicle* ego, bool& brakeBeforeSignal) {
457 : // @note: this check is intended to prevent deadlock / collision by an inserted vehicle that
458 : // waits at a red signal and thus checks different things than ::reverse()
459 : bool hadOncoming = false;
460 2976 : if (link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
461 2976 : const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
462 2976 : if (bidi == nullptr) {
463 1530 : brakeBeforeSignal = false;
464 2496 : return false;
465 : }
466 1446 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
467 1360 : if (rs != nullptr) {
468 1360 : const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
469 1756 : for (const DriveWay& dw : li.myDriveways) {
470 : //std::cout << SIMTIME << " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
471 9233 : for (const MSLane* lane : dw.myBidi) {
472 : if (!lane->isEmpty()) {
473 641 : MSVehicle* veh = lane->getFirstAnyVehicle();
474 641 : if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
475 : #ifdef DEBUG_SIGNALSTATE
476 : if (DEBUG_HELPER(rs)) {
477 : std::cout << " oncoming vehicle on bidi-lane " << lane->getID() << "\n";
478 : }
479 : #endif
480 : return true;
481 : }
482 : }
483 : }
484 4510 : for (const MSLane* lane : dw.myFlank) {
485 : if (!lane->isEmpty()) {
486 126 : MSVehicle* veh = lane->getFirstAnyVehicle();
487 126 : if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
488 : #ifdef DEBUG_SIGNALSTATE
489 : if (DEBUG_HELPER(rs)) {
490 : std::cout << " oncoming vehicle on flank-lane " << lane->getID() << "\n";
491 : }
492 : #endif
493 : return true;
494 : }
495 : }
496 : }
497 597 : if (dw.myProtectingSwitchesBidi.size() > 0) {
498 : #ifdef DEBUG_SIGNALSTATE
499 : gDebugFlag4 = DEBUG_HELPER(rs);
500 : #endif
501 : // yield to all foeLinks beyond switch
502 : Approaching approaching(ego,
503 351 : MSLink::ApproachingVehicleInformation(SIMSTEP, 0, 0, 0, false, 0, 0, std::numeric_limits<double>::max(), 0, 0));
504 561 : for (MSLink* const switchLink : dw.myProtectingSwitchesBidi) {
505 : myBlockingVehicles.clear();
506 : myRivalVehicles.clear();
507 : myPriorityVehicles.clear();
508 : myConstraintInfo = "";
509 387 : myStoreVehicles = true;
510 387 : const bool hasProtection = dw.findProtection(approaching, switchLink);
511 387 : myStoreVehicles = false;
512 387 : if (!hasProtection) {
513 184 : for (const SUMOVehicle* veh : myBlockingVehicles) {
514 : hadOncoming = true;
515 177 : if (!brakeBeforeSignal || std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
516 : #ifdef DEBUG_SIGNALSTATE
517 : if (DEBUG_HELPER(rs)) {
518 : std::cout << " no protection at bidi-switch " << switchLink->getDescription() << " from veh=" << veh->getID() << "\n";
519 : gDebugFlag4 = false;
520 : }
521 : #endif
522 : return true;
523 : }
524 : }
525 14 : for (const SUMOVehicle* veh : myRivalVehicles) {
526 : hadOncoming = true;
527 7 : if (!brakeBeforeSignal || std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
528 : #ifdef DEBUG_SIGNALSTATE
529 : if (DEBUG_HELPER(rs)) {
530 : std::cout << " no protection at bidi-switch " << switchLink->getDescription() << " from linkRival veh=" << veh->getID() << "\n";
531 : gDebugFlag4 = false;
532 : }
533 : #endif
534 : return true;
535 : }
536 : }
537 : }
538 : }
539 : #ifdef DEBUG_SIGNALSTATE
540 : gDebugFlag4 = false;
541 : #endif
542 : }
543 755 : for (MSLink* foeLink : dw.myConflictLinks) {
544 359 : if (foeLink->getApproaching().size() != 0) {
545 95 : Approaching closest = getClosest(foeLink);
546 95 : const SUMOVehicle* veh = closest.first;
547 128 : if (veh->getSpeed() > 0 && closest.second.arrivalSpeedBraking > 0
548 128 : && std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
549 : #ifdef DEBUG_SIGNALSTATE
550 : if (DEBUG_HELPER(rs)) {
551 : std::cout << " oncoming vehicle approaching foe link " << foeLink->getDescription() << "\n";
552 : }
553 : #endif
554 24 : return true;
555 : }
556 : }
557 : }
558 : }
559 : }
560 : }
561 480 : brakeBeforeSignal = hadOncoming;
562 480 : return false;
563 : }
564 :
565 : bool
566 17265 : MSRailSignal::hasInsertionConstraint(MSLink* link, const MSVehicle* veh, std::string& info, bool& isInsertionOrder) {
567 17265 : if (link->getJunction() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
568 5632 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
569 5040 : if (rs != nullptr && rs->myConstraints.size() > 0) {
570 5474 : const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
571 : auto it = rs->myConstraints.find(tripID);
572 2737 : if (it != rs->myConstraints.end()) {
573 2993 : for (MSRailSignalConstraint* c : it->second) {
574 2082 : if (c->isInsertionConstraint() && !c->cleared()) {
575 : #ifdef DEBUG_SIGNALSTATE
576 : if (DEBUG_HELPER(rs)) {
577 : std::cout << SIMTIME << " rsl=" << rs->getID() << " insertion constraint '" << c->getDescription() << "' for vehicle '" << veh->getID() << "' not cleared\n";
578 : }
579 : #endif
580 3604 : info = c->getDescription();
581 1802 : isInsertionOrder = c->getType() == MSRailSignalConstraint::ConstraintType::INSERTION_ORDER;
582 : return true;
583 : }
584 : }
585 : }
586 : }
587 : }
588 : return false;
589 : }
590 :
591 : // ===========================================================================
592 : // LinkInfo method definitions
593 : // ===========================================================================
594 :
595 3922 : MSRailSignal::LinkInfo::LinkInfo(MSLink* link):
596 3922 : myLink(link) {
597 3922 : reset();
598 3922 : }
599 :
600 :
601 : void
602 3927 : MSRailSignal::LinkInfo::reset() {
603 3927 : myLastRerouteTime = -1;
604 3927 : myLastRerouteVehicle = nullptr;
605 : myDriveways.clear();
606 3927 : }
607 :
608 :
609 : std::string
610 180 : MSRailSignal::LinkInfo::getID() const {
611 360 : return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
612 : }
613 :
614 :
615 : MSRailSignal::DriveWay&
616 6864917 : MSRailSignal::LinkInfo::getDriveWay(const SUMOVehicle* veh) {
617 6864917 : MSEdge* first = &myLink->getLane()->getEdge();
618 6864917 : MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
619 6864917 : if (firstIt == veh->getRoute().end()) {
620 : // possibly the vehicle has already gone past the first edge (i.e.
621 : // because first is short or the step-length is high)
622 : // lets look backward along the route
623 : // give some slack because the vehicle might have been braking from a higher speed and using ballistic integration
624 60 : double lookBack = SPEED2DIST(veh->getSpeed() + 10);
625 60 : int routeIndex = veh->getRoutePosition() - 1;
626 66 : while (lookBack > 0 && routeIndex > 0) {
627 59 : const MSEdge* prevEdge = veh->getRoute().getEdges()[routeIndex];
628 59 : if (prevEdge == first) {
629 53 : firstIt = veh->getRoute().begin() + routeIndex;
630 53 : break;
631 : }
632 6 : lookBack -= prevEdge->getLength();
633 6 : routeIndex--;
634 : }
635 : }
636 6864917 : if (firstIt == veh->getRoute().end()) {
637 14 : WRITE_WARNING("Invalid approach information to rail signal '" + getClickableTLLinkID(myLink) + "' after rerouting for vehicle '" + veh->getID()
638 : + "' first driveway edge '" + first->getID() + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
639 7 : if (myDriveways.empty()) {
640 : ConstMSEdgeVector dummyRoute;
641 0 : dummyRoute.push_back(&myLink->getLane()->getEdge());
642 0 : DriveWay dw = buildDriveWay(dummyRoute.begin(), dummyRoute.end());
643 0 : myDriveways.push_back(dw);
644 0 : }
645 7 : return myDriveways.front();
646 : }
647 : //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
648 6890481 : for (DriveWay& dw : myDriveways) {
649 : // @todo optimize: it is sufficient to check for specific edges (after each switch)
650 : auto itRoute = firstIt;
651 : auto itDwRoute = dw.myRoute.begin();
652 : bool match = true;
653 41882378 : while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
654 35016707 : if (*itRoute != *itDwRoute) {
655 : match = false;
656 : //std::cout << " check dw=" << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
657 : break;
658 : }
659 : itRoute++;
660 : itDwRoute++;
661 : }
662 : // if the vehicle arrives before the end of this driveway,
663 : // we'd rather build a new driveway to avoid superfluous restrictions
664 6865671 : if (match && itDwRoute == dw.myRoute.end()
665 13753713 : && (itRoute == veh->getRoute().end() || dw.myFoundSignal || dw.myFoundReversal)) {
666 : //std::cout << " using dw=" << "\n";
667 : return dw;
668 : }
669 : #ifdef DEBUG_SELECT_DRIVEWAY
670 : std::cout << SIMTIME << " rs=" << getID() << " veh=" << veh->getID() << " other dwSignal=" << dw.myFoundSignal << " dwRoute=" << toString(dw.myRoute) << " route=" << toString(veh->getRoute().getEdges()) << "\n";
671 : #endif
672 : }
673 2439 : DriveWay dw = buildDriveWay(firstIt, veh->getRoute().end());
674 : #ifdef DEBUG_SELECT_DRIVEWAY
675 : std::cout << SIMTIME << " rs=" << getID() << " veh=" << veh->getID() << " new dwSignal=" << dw.myFoundSignal << " dwRoute=" << toString(dw.myRoute) << " route=" << toString(veh->getRoute().getEdges()) << "\n";
676 : #endif
677 2439 : myDriveways.push_back(dw);
678 : return myDriveways.back();
679 2439 : }
680 :
681 :
682 : MSRailSignal::DriveWay
683 2498 : MSRailSignal::LinkInfo::buildDriveWay(MSRouteIterator first, MSRouteIterator end) {
684 : // collect lanes and links that are relevant for setting this signal for the current driveWay
685 : // For each driveway we collect
686 : // - conflictLanes (signal must be red if any conflict lane is occupied)
687 : // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
688 : // - that cannot break in time (arrivalSpeedBraking > 0)
689 : // - approached by a vehicle with higher switching priority (see #3941)
690 : // These objects are construct in steps:
691 : //
692 : // forwardBlock
693 : // - search forward recursive from outgoing lane until controlled railSignal link found
694 : // -> add all found lanes to conflictLanes
695 : //
696 : // bidiBlock (if any forwardBlock edge has bidi edge)
697 : // - search bidi backward recursive until first switch
698 : // - from switch search backward recursive all other incoming until controlled rail signal link
699 : // -> add final links to conflictLinks
700 : //
701 : // flanks
702 : // - search backward recursive from flanking switches
703 : // until controlled railSignal link or protecting switch is found
704 : // -> add all found lanes to conflictLanes
705 : // -> add final links to conflictLinks
706 :
707 2498 : DriveWay dw;
708 : LaneVisitedMap visited;
709 : std::vector<const MSLane*> before;
710 2498 : appendMapIndex(visited, myLink->getLaneBefore());
711 2498 : MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
712 2498 : if (fromBidi != nullptr) {
713 : // do not extend to forward block beyond the entering track (in case of a loop)
714 1341 : appendMapIndex(visited, fromBidi);
715 1341 : before.push_back(fromBidi);
716 : }
717 2498 : dw.buildRoute(myLink, 0., first, end, visited);
718 2498 : if (dw.myProtectedBidi == nullptr) {
719 2215 : dw.myCoreSize = (int)dw.myRoute.size();
720 : }
721 2498 : dw.checkFlanks(myLink, dw.myForward, visited, true, dw.myFlankSwitches);
722 2498 : dw.checkFlanks(myLink, dw.myBidi, visited, false, dw.myFlankSwitches);
723 2498 : dw.checkFlanks(myLink, before, visited, true, dw.myFlankSwitches);
724 5613 : for (MSLink* link : dw.myFlankSwitches) {
725 : //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
726 3115 : dw.findFlankProtection(link, 0, visited, link, dw.myFlank);
727 : }
728 : std::vector<MSLink*> flankSwitchesBidiExtended;
729 2498 : dw.checkFlanks(myLink, dw.myBidiExtended, visited, false, flankSwitchesBidiExtended);
730 2619 : for (MSLink* link : flankSwitchesBidiExtended) {
731 : //std::cout << getID() << " flankSwitchBEx=" << link->getDescription() << "\n";
732 121 : dw.findFlankProtection(link, 0, visited, link, dw.myBidiExtended);
733 : }
734 :
735 : #ifdef DEBUG_BUILD_DRIVEWAY
736 : if (DEBUG_COND_LINKINFO) {
737 : std::cout << " buildDriveWay railSignal=" << getID()
738 : << "\n route=" << toString(dw.myRoute)
739 : << "\n forward=" << toString(dw.myForward)
740 : << "\n bidi=" << toString(dw.myBidi)
741 : << "\n flank=" << toString(dw.myFlank)
742 : << "\n flankSwitch=" << describeLinks(dw.myFlankSwitches)
743 : << "\n protSwitch=" << describeLinks(dw.myProtectingSwitches)
744 : << "\n coreSize=" << dw.myCoreSize
745 : << "\n";
746 : }
747 : #endif
748 2498 : MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(myLink->getTLLogic()));
749 2498 : if (!rs->myMovingBlock) {
750 2473 : dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
751 : }
752 2498 : dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
753 2498 : dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
754 2498 : if (dw.myProtectedBidi != nullptr) {
755 283 : MSRailSignalControl::getInstance().registerProtectedDriveway(rs, dw.myNumericalID, dw.myProtectedBidi);
756 : }
757 :
758 2498 : return dw;
759 0 : }
760 :
761 :
762 : void
763 15240 : MSRailSignal::LinkInfo::reroute(SUMOVehicle* veh, const MSEdgeVector& occupied) {
764 15240 : MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
765 15240 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
766 : if (rDev != nullptr
767 11214 : && rDev->mayRerouteRailSignal()
768 22956 : && (myLastRerouteVehicle != veh
769 : // reroute each vehicle only once if no periodic routing is allowed,
770 : // otherwise with the specified period
771 7596 : || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
772 180 : myLastRerouteVehicle = veh;
773 180 : myLastRerouteTime = now;
774 :
775 : #ifdef DEBUG_REROUTE
776 : ConstMSEdgeVector oldRoute = veh->getRoute().getEdges();
777 : if (DEBUG_COND_LINKINFO) {
778 : std::cout << SIMTIME << " reroute veh=" << veh->getID() << " rs=" << getID() << " occupied=" << toString(occupied) << "\n";
779 : }
780 : #endif
781 360 : MSRoutingEngine::reroute(*veh, now, "railSignal:" + getID(), false, true, occupied);
782 : #ifdef DEBUG_REROUTE
783 : // attention this works only if we are not parallel!
784 : if (DEBUG_COND_LINKINFO) {
785 : if (veh->getRoute().getEdges() != oldRoute) {
786 : std::cout << " rerouting successful\n";
787 : }
788 : }
789 : #endif
790 : }
791 15240 : }
792 :
793 :
794 : // ===========================================================================
795 : // DriveWay method definitions
796 : // ===========================================================================
797 :
798 : bool
799 396159 : MSRailSignal::DriveWay::reserve(const Approaching& closest, MSEdgeVector& occupied) {
800 396159 : std::string joinVehicle = "";
801 396159 : if (!MSGlobals::gUseMesoSim) {
802 395446 : const SUMOVehicleParameter::Stop* stop = closest.first->getNextStopParameter();
803 395446 : if (stop != nullptr) {
804 281813 : joinVehicle = stop->join;
805 : }
806 : }
807 396159 : if (conflictLaneOccupied(joinVehicle, true, closest.first)) {
808 932994 : for (const MSLane* bidi : myBidi) {
809 823536 : if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
810 15300 : occupied.push_back(&bidi->getBidiLane()->getEdge());
811 : }
812 : }
813 : #ifdef DEBUG_SIGNALSTATE
814 : if (gDebugFlag4) {
815 : std::cout << " conflictLaneOccupied by=" << toString(myBlockingVehicles) << " ego=" << Named::getIDSecure(closest.first) << "\n";
816 : }
817 : #endif
818 : return false;
819 : }
820 348718 : for (MSLink* link : myProtectingSwitches) {
821 65111 : if (!findProtection(closest, link)) {
822 : #ifdef DEBUG_SIGNALSTATE
823 : if (gDebugFlag4) {
824 : std::cout << " no protection at switch " << link->getDescription() << "\n";
825 : }
826 : #endif
827 : return false;
828 : }
829 : }
830 369558 : for (MSLink* foeLink : myConflictLinks) {
831 90397 : if (hasLinkConflict(closest, foeLink)) {
832 : #ifdef DEBUG_SIGNALSTATE
833 : if (gDebugFlag4) {
834 : std::cout << " linkConflict with " << getTLLinkID(foeLink) << "\n";
835 : }
836 : #endif
837 : return false;
838 : }
839 : }
840 279161 : if (deadlockLaneOccupied()) {
841 : return false;
842 : }
843 277673 : myActive = closest.first;
844 277673 : return true;
845 : }
846 :
847 :
848 : bool
849 20338879 : MSRailSignal::DriveWay::conflictLinkApproached() const {
850 27202719 : for (MSLink* foeLink : myConflictLinks) {
851 13328823 : if (foeLink->getApproaching().size() > 0) {
852 : #ifdef DEBUG_SIGNALSTATE
853 : if (gDebugFlag4) {
854 : std::cout << SIMTIME << " foeLink=" << foeLink->getDescription() << " approachedBy=" << foeLink->getApproaching().begin()->first->getID() << "\n";
855 : }
856 : #endif
857 : return true;
858 : }
859 : }
860 : return false;
861 : }
862 :
863 :
864 : bool
865 90397 : MSRailSignal::DriveWay::hasLinkConflict(const Approaching& veh, MSLink* foeLink) const {
866 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
867 : if (gDebugFlag4) {
868 : std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
869 : }
870 : #endif
871 90397 : if (foeLink->getApproaching().size() > 0) {
872 20308 : Approaching foe = getClosest(foeLink);
873 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
874 : if (gDebugFlag4) {
875 : std::cout << " approaching foe=" << foe.first->getID() << "\n";
876 : }
877 : #endif
878 : const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
879 : assert(foeTLL != nullptr);
880 20308 : const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
881 : MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
882 20308 : if (foeRS != nullptr) {
883 20308 : const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
884 58861 : if (foeDriveWay.conflictLaneOccupied("", false, foe.first) ||
885 35370 : foeDriveWay.deadlockLaneOccupied(false) ||
886 45412 : !foeRS->constraintsAllow(foe.first) ||
887 7979 : !overlap(foeDriveWay)) {
888 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
889 : if (gDebugFlag4) {
890 : if (foeDriveWay.conflictLaneOccupied("", false, foe.first)) {
891 : std::cout << " foe blocked\n";
892 : } else if (!foeRS->constraintsAllow(foe.first)) {
893 : std::cout << " foe constrained\n";
894 : } else {
895 : std::cout << " no overlap\n";
896 : }
897 : }
898 : #endif
899 20308 : return false;
900 : }
901 : #ifdef DEBUG_SIGNALSTATE_PRIORITY
902 : if (gDebugFlag4) {
903 : std::cout
904 : << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
905 : << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
906 : << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
907 : << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
908 : << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
909 : << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
910 : << "\n";
911 : }
912 : #endif
913 7793 : const bool yield = mustYield(veh, foe);
914 7793 : if (myStoreVehicles) {
915 1155 : myRivalVehicles.push_back(foe.first);
916 1155 : if (yield) {
917 487 : myPriorityVehicles.push_back(foe.first);
918 : }
919 : }
920 7793 : return yield;
921 : }
922 : }
923 : return false;
924 : }
925 :
926 :
927 : bool
928 7796 : MSRailSignal::DriveWay::mustYield(const Approaching& veh, const Approaching& foe) {
929 7796 : if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
930 3425 : if (foe.second.arrivalTime == veh.second.arrivalTime) {
931 325 : if (foe.first->getSpeed() == veh.first->getSpeed()) {
932 304 : if (foe.second.dist == veh.second.dist) {
933 276 : if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
934 261 : return foe.first->getNumericalID() < veh.first->getNumericalID();
935 : } else {
936 15 : return foe.first->getWaitingTime() > veh.first->getWaitingTime();
937 : }
938 : } else {
939 28 : return foe.second.dist < veh.second.dist;
940 : }
941 : } else {
942 21 : return foe.first->getSpeed() > veh.first->getSpeed();
943 : }
944 : } else {
945 3100 : return foe.second.arrivalTime < veh.second.arrivalTime;
946 : }
947 : } else {
948 4371 : return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
949 : }
950 : }
951 :
952 :
953 : bool
954 20999564 : MSRailSignal::DriveWay::conflictLaneOccupied(const std::string& joinVehicle, bool store, const SUMOVehicle* ego) const {
955 159875711 : for (const MSLane* lane : myConflictLanes) {
956 : if (!lane->isEmpty()) {
957 : #ifdef DEBUG_SIGNALSTATE
958 : if (gDebugFlag4) {
959 : std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
960 : if (joinVehicle != "") {
961 : std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
962 : lane->releaseVehicles();
963 : }
964 : }
965 : #endif
966 362516 : if (lane->getVehicleNumberWithPartials() == 1) {
967 361442 : MSVehicle* foe = lane->getLastAnyVehicle();
968 361442 : if (joinVehicle != "") {
969 108 : if (foe->getID() == joinVehicle && foe->isStopped()) {
970 : #ifdef DEBUG_SIGNALSTATE
971 : if (gDebugFlag4) {
972 : std::cout << " ignore join-target '" << joinVehicle << "\n";
973 : }
974 : #endif
975 9 : continue;
976 : }
977 : }
978 361433 : if (ego != nullptr) {
979 112264 : if (foe == ego && std::find(myBidi.begin(), myBidi.end(), lane) != myBidi.end()) {
980 : #ifdef DEBUG_SIGNALSTATE
981 : if (gDebugFlag4) {
982 : std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
983 : }
984 : #endif
985 999 : continue;
986 : }
987 111265 : if (foe->isStopped() && foe->getNextStopParameter()->join == ego->getID()) {
988 : #ifdef DEBUG_SIGNALSTATE
989 : if (gDebugFlag4) {
990 : std::cout << " ignore " << foe->getID() << " for which ego is join-target\n";
991 : }
992 : #endif
993 9 : continue;
994 : }
995 : }
996 : }
997 361499 : if (myStoreVehicles && store) {
998 6463 : myBlockingVehicles.push_back(lane->getLastAnyVehicle());
999 : }
1000 361499 : return true;
1001 : }
1002 : }
1003 20638065 : return false;
1004 : }
1005 :
1006 : bool
1007 297406 : MSRailSignal::DriveWay::deadlockLaneOccupied(bool store) const {
1008 318443 : for (const MSLane* lane : myBidiExtended) {
1009 23645 : if (!lane->empty()) {
1010 : assert(myBidi.size() != 0);
1011 2608 : const MSEdge* lastBidi = myBidi.back()->getNextNormal();
1012 2608 : MSVehicle* foe = lane->getVehiclesSecure().front();
1013 : #ifdef DEBUG_SIGNALSTATE
1014 : if (gDebugFlag4) {
1015 : std::cout << " check for deadlock with " << foe->getID() << "\n";
1016 : }
1017 : #endif
1018 : // check of foe will enter myBidi (need to check at most
1019 : // myBidiExtended.size edges)
1020 2608 : const int minEdges = (int)myBidiExtended.size();
1021 2608 : auto foeIt = foe->getCurrentRouteEdge() + 1;
1022 2608 : auto foeEnd = foe->getRoute().end();
1023 : bool conflict = false;
1024 5068 : for (int i = 0; i < minEdges && foeIt != foeEnd; i++) {
1025 5068 : if ((*foeIt) == lastBidi) {
1026 : #ifdef DEBUG_SIGNALSTATE
1027 : if (gDebugFlag4) {
1028 : std::cout << " vehicle will enter " << lastBidi->getID() << "\n";
1029 : }
1030 : #endif
1031 : conflict = true;
1032 : break;
1033 : }
1034 : foeIt++;
1035 : }
1036 2608 : lane->releaseVehicles();
1037 2608 : if (conflict) {
1038 2608 : if (myStoreVehicles && store) {
1039 0 : myBlockingVehicles.push_back(foe);
1040 : }
1041 2608 : return true;
1042 : }
1043 : }
1044 : }
1045 : return false;
1046 : }
1047 :
1048 :
1049 : bool
1050 65498 : MSRailSignal::DriveWay::findProtection(const Approaching& veh, MSLink* link) const {
1051 : double flankApproachingDist = std::numeric_limits<double>::max();
1052 65498 : if (link->getApproaching().size() > 0) {
1053 4071 : Approaching closest = getClosest(link);
1054 4071 : flankApproachingDist = closest.second.dist;
1055 : }
1056 : #ifdef DEBUG_FIND_PROTECTION
1057 : if (gDebugFlag4) {
1058 : std::cout << SIMTIME << " findProtection for link=" << link->getDescription() << " flankApproachingDist=" << flankApproachingDist << "\n";
1059 : }
1060 : #endif
1061 171839 : for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
1062 118972 : if (l2->getLane() != link->getLane()) {
1063 : #ifdef DEBUG_FIND_PROTECTION
1064 : if (gDebugFlag4) {
1065 : std::cout << " protectionCandidate=" << l2->getDescription() << " l2Via=" << Named::getIDSecure(l2->getViaLane())
1066 : << " occupied=" << (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) << "\n";
1067 : }
1068 : #endif
1069 65873 : if (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) {
1070 : #ifdef DEBUG_FIND_PROTECTION
1071 : if (gDebugFlag4) {
1072 : std::cout << " protection from internal=" << l2->getViaLane()->getID() << "\n";
1073 : }
1074 : #endif
1075 : return true;
1076 : }
1077 64709 : if (l2->getApproaching().size() > 0) {
1078 11467 : Approaching closest2 = getClosest(l2);
1079 11467 : if (closest2.second.dist < flankApproachingDist) {
1080 : #ifdef DEBUG_FIND_PROTECTION
1081 : if (gDebugFlag4) {
1082 : std::cout << " protection from veh=" << closest2.first->getID() << "\n";
1083 : }
1084 : #endif
1085 11467 : return true;
1086 : }
1087 : }
1088 : }
1089 : }
1090 52867 : if (link->getApproaching().size() == 0) {
1091 : return true;
1092 : } else {
1093 : // find protection further upstream
1094 4071 : DriveWay tmp(true);
1095 4071 : const MSLane* before = link->getLaneBefore();
1096 4071 : tmp.myFlank.push_back(before);
1097 : LaneVisitedMap visited;
1098 8432 : for (auto ili : before->getIncomingLanes()) {
1099 4361 : tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink, tmp.myFlank);
1100 : }
1101 4071 : tmp.myConflictLanes = tmp.myFlank;
1102 4071 : tmp.myRoute = myRoute;
1103 4071 : tmp.myCoreSize = myCoreSize;
1104 : MSEdgeVector occupied;
1105 4071 : if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
1106 0 : << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
1107 4071 : return tmp.reserve(veh, occupied);
1108 4071 : }
1109 : }
1110 :
1111 :
1112 : bool
1113 7979 : MSRailSignal::DriveWay::overlap(const DriveWay& other) const {
1114 12522 : for (int i = 0; i < myCoreSize; i++) {
1115 53434 : for (int j = 0; j < other.myCoreSize; j++) {
1116 48891 : const MSEdge* edge = myRoute[i];
1117 48891 : const MSEdge* edge2 = other.myRoute[j];
1118 : if (edge->getToJunction() == edge2->getToJunction()
1119 48891 : || edge->getToJunction() == edge2->getFromJunction()) {
1120 : // XXX might be rail_crossing with parallel tracks
1121 : return true;
1122 : }
1123 : }
1124 : }
1125 : return false;
1126 : }
1127 :
1128 : bool
1129 29 : MSRailSignal::DriveWay::flankConflict(const DriveWay& other) const {
1130 140 : for (const MSLane* lane : myForward) {
1131 534 : for (const MSLane* lane2 : other.myForward) {
1132 420 : if (lane == lane2) {
1133 : return true;
1134 : }
1135 : }
1136 1273 : for (const MSLane* lane2 : other.myBidi) {
1137 1162 : if (lane == lane2) {
1138 : return true;
1139 : }
1140 : }
1141 : }
1142 : return false;
1143 : }
1144 :
1145 : void
1146 1462 : MSRailSignal::DriveWay::writeBlocks(OutputDevice& od) const {
1147 1462 : od.openTag("driveWay");
1148 1462 : od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
1149 1462 : if (myCoreSize != (int)myRoute.size()) {
1150 188 : od.writeAttr("core", myCoreSize);
1151 : }
1152 1462 : od.openTag("forward");
1153 1462 : od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
1154 1462 : od.closeTag();
1155 1462 : od.openTag("bidi");
1156 2924 : od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
1157 1462 : if (myBidiExtended.size() > 0) {
1158 72 : od.lf();
1159 72 : od << " ";
1160 196 : od.writeAttr("deadlockCheck", toString(myBidiExtended));
1161 : }
1162 1462 : od.closeTag();
1163 1462 : od.openTag("flank");
1164 1462 : od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
1165 1462 : od.closeTag();
1166 :
1167 2924 : od.openTag("protectingSwitches");
1168 : std::vector<std::string> links;
1169 1883 : for (MSLink* link : myProtectingSwitches) {
1170 842 : links.push_back(getJunctionLinkID(link));
1171 : }
1172 2924 : od.writeAttr("links", joinToString(links, " "));
1173 1462 : od.closeTag();
1174 :
1175 2924 : od.openTag("conflictLinks");
1176 : std::vector<std::string> signals;
1177 2370 : for (MSLink* link : myConflictLinks) {
1178 1816 : signals.push_back(getTLLinkID(link));
1179 : }
1180 2924 : od.writeAttr("signals", joinToString(signals, " "));
1181 1462 : od.closeTag();
1182 1462 : od.closeTag(); // driveWay
1183 1462 : }
1184 :
1185 :
1186 : void
1187 2498 : MSRailSignal::DriveWay::buildRoute(MSLink* origin, double length,
1188 : MSRouteIterator next, MSRouteIterator end,
1189 : LaneVisitedMap& visited) {
1190 : bool seekForwardSignal = true;
1191 : bool seekBidiSwitch = true;
1192 : bool foundUnsafeSwitch = false;
1193 2498 : MSLane* toLane = origin->getViaLaneOrLane();
1194 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1195 : gDebugFlag4 = DEBUG_HELPER(origin->getTLLogic());
1196 : if (gDebugFlag4) std::cout << "buildRoute origin=" << getTLLinkID(origin) << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1197 : << " visited=" << formatVisitedMap(visited) << "\n";
1198 : #endif
1199 13838 : while ((seekForwardSignal || seekBidiSwitch)) {
1200 13072 : if (length > MAX_BLOCK_LENGTH) {
1201 0 : if (myNumWarnings < MAX_SIGNAL_WARNINGS) {
1202 0 : WRITE_WARNING("Block after rail signal " + getClickableTLLinkID(origin) +
1203 : " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
1204 : }
1205 0 : myNumWarnings++;
1206 : // length exceeded
1207 1732 : return;
1208 : }
1209 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1210 : if (gDebugFlag4) {
1211 : std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1212 : }
1213 : #endif
1214 : if (visited.count(toLane) != 0) {
1215 0 : WRITE_WARNINGF(TL("Found circular block after railSignal % (% edges, length %)"), getClickableTLLinkID(origin), toString(myRoute.size()), toString(length));
1216 : //std::cout << getClickableTLLinkID(origin) << " circularBlock1=" << toString(myRoute) << " visited=" << formatVisitedMap(visited) << "\n";
1217 0 : return;
1218 : }
1219 13072 : if (toLane->getEdge().isNormal()) {
1220 8254 : myRoute.push_back(&toLane->getEdge());
1221 8254 : if (next != end) {
1222 : next++;
1223 : }
1224 : }
1225 13072 : appendMapIndex(visited, toLane);
1226 13072 : length += toLane->getLength();
1227 13072 : MSLane* bidi = toLane->getBidiLane();
1228 13072 : if (seekForwardSignal) {
1229 7888 : if (!foundUnsafeSwitch) {
1230 7888 : myForward.push_back(toLane);
1231 : }
1232 5184 : } else if (bidi == nullptr) {
1233 : seekBidiSwitch = false;
1234 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1235 : if (gDebugFlag4) {
1236 : std::cout << " noBidi, abort search for bidiSwitch\n";
1237 : }
1238 : #endif
1239 : }
1240 13072 : if (bidi != nullptr) {
1241 9710 : if (foundUnsafeSwitch) {
1242 459 : myBidiExtended.push_back(bidi);
1243 : } else {
1244 9251 : myBidi.push_back(bidi);
1245 : }
1246 9710 : appendMapIndex(visited, bidi);
1247 9710 : if (!seekForwardSignal) {
1248 : // look for switch that could protect from oncoming vehicles
1249 9562 : for (const auto& ili : bidi->getIncomingLanes()) {
1250 4949 : if (ili.viaLink->getDirection() == LinkDirection::TURN) {
1251 240 : continue;
1252 : }
1253 9488 : for (const MSLink* const link : ili.lane->getLinkCont()) {
1254 5062 : if (link->getDirection() == LinkDirection::TURN) {
1255 101 : continue;
1256 : }
1257 4961 : if (link->getViaLaneOrLane() != bidi) {
1258 : // this switch is special beause it still lies on the current route
1259 : //myProtectingSwitches.push_back(ili.viaLink);
1260 449 : const MSEdge* const bidiNext = bidi->getNextNormal();
1261 449 : myCoreSize = (int)myRoute.size();
1262 449 : if (MSRailSignalControl::getInstance().getUsedEdges().count(bidiNext) == 0) {
1263 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1264 : if (gDebugFlag4) {
1265 : std::cout << " abort: found protecting switch " << ili.viaLink->getDescription() << "\n";
1266 : }
1267 : #endif
1268 : // if bidi is actually used by a train (rather than
1269 : // the other route) we must later adapt this driveway for additional checks (myBidiExtended)
1270 283 : myProtectedBidi = bidiNext;
1271 : std::set<const MSEdge*> visitedEdges;
1272 5125 : for (auto item : visited) {
1273 4842 : visitedEdges.insert(&item.first->getEdge());
1274 : }
1275 2151 : while (next != end && visitedEdges.count(*next) == 0) {
1276 : // the driveway is route specific but only but stop recording if it loops back on itself
1277 : visitedEdges.insert(*next);
1278 1868 : const MSEdge* nextBidi = (*next)->getBidiEdge();
1279 1868 : if (nextBidi != nullptr) {
1280 : visitedEdges.insert(nextBidi);
1281 : }
1282 1868 : myRoute.push_back(*next);
1283 : next++;
1284 : }
1285 : return;
1286 : } else {
1287 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1288 : if (gDebugFlag4) {
1289 : std::cout << " found unsafe switch " << ili.viaLink->getDescription() << " (used=" << bidiNext->getID() << ")\n";
1290 : }
1291 : #endif
1292 : // trains along our route beyond this switch
1293 : // might create deadlock
1294 : foundUnsafeSwitch = true;
1295 : // the switch itself must still be guarded to ensure safety
1296 348 : for (const auto& ili2 : bidi->getIncomingLanes()) {
1297 182 : if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
1298 174 : myFlankSwitches.push_back(ili.viaLink);
1299 : }
1300 : }
1301 : }
1302 : }
1303 : }
1304 : }
1305 : }
1306 : }
1307 12789 : const std::vector<MSLink*>& links = toLane->getLinkCont();
1308 : const MSEdge* current = &toLane->getEdge();
1309 12789 : toLane = nullptr;
1310 13870 : for (const MSLink* const link : links) {
1311 12013 : if ((next != end && &link->getLane()->getEdge() == *next)
1312 23917 : && isRailway(link->getViaLaneOrLane()->getPermissions())) {
1313 11418 : toLane = link->getViaLaneOrLane();
1314 11418 : if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1315 : // do not follow turn-arounds even if the route contains a reversal
1316 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1317 : if (gDebugFlag4) {
1318 : std::cout << " abort: turn-around\n";
1319 : }
1320 : #endif
1321 78 : myFoundReversal = true;
1322 78 : return;
1323 : }
1324 11340 : if (link->getTLLogic() != nullptr) {
1325 2991 : if (link->getTLLogic() == origin->getTLLogic()) {
1326 0 : WRITE_WARNINGF(TL("Found circular block at railSignal % (% edges, length %)"), getClickableTLLinkID(origin), toString(myRoute.size()), toString(length));
1327 : //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1328 0 : return;
1329 : }
1330 : seekForwardSignal = false;
1331 2991 : myFoundSignal = true;
1332 2991 : seekBidiSwitch = bidi != nullptr;
1333 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1334 : if (gDebugFlag4) {
1335 : std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1336 : }
1337 : #endif
1338 : }
1339 : break;
1340 : }
1341 : }
1342 12711 : if (toLane == nullptr) {
1343 1371 : if (next != end) {
1344 : // no connection found, jump to next route edge
1345 : toLane = (*next)->getLanes()[0];
1346 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1347 : if (gDebugFlag4) {
1348 : std::cout << " abort: turn-around or jump\n";
1349 : }
1350 : #endif
1351 33 : myFoundReversal = true;
1352 33 : return;
1353 : } else {
1354 : #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1355 : if (gDebugFlag4) {
1356 : std::cout << " abort: no next lane available\n";
1357 : }
1358 : #endif
1359 : return;
1360 : }
1361 : }
1362 : }
1363 : }
1364 :
1365 :
1366 : void
1367 9992 : MSRailSignal::DriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes, std::vector<MSLink*>& flankSwitches) const {
1368 : #ifdef DEBUG_CHECK_FLANKS
1369 : std::cout << " checkFlanks lanes=" << toString(lanes) << "\n visited=" << formatVisitedMap(visited) << " allFoes=" << allFoes << "\n";
1370 : #endif
1371 15532 : const MSLink* reverseOriginLink = originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1372 15120 : ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1373 : : nullptr;
1374 : //std::cout << " originLink=" << originLink->getDescription() << "\n";
1375 5128 : if (reverseOriginLink != nullptr) {
1376 5128 : reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1377 : //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1378 : }
1379 28931 : for (int i = 0; i < (int)lanes.size(); i++) {
1380 18939 : const MSLane* lane = lanes[i];
1381 18939 : const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1382 18939 : const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1383 18939 : if (lane->isInternal()) {
1384 6384 : continue;
1385 : }
1386 27835 : for (auto ili : lane->getIncomingLanes()) {
1387 18890 : if (ili.viaLink == originLink
1388 14012 : || ili.viaLink == reverseOriginLink
1389 12730 : || ili.viaLink->getDirection() == LinkDirection::TURN
1390 26950 : || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND) {
1391 3610 : continue;
1392 : }
1393 11670 : if (ili.lane != prev && ili.lane != next) {
1394 : #ifdef DEBUG_CHECK_FLANKS
1395 : 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";
1396 : #endif
1397 3042 : flankSwitches.push_back(ili.viaLink);
1398 8628 : } else if (allFoes) {
1399 : // link is part of the driveway, find foes that cross the driveway without entering
1400 4067 : checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1401 : }
1402 : }
1403 : }
1404 9992 : }
1405 :
1406 :
1407 : void
1408 4067 : MSRailSignal::DriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::vector<MSLink*>& flankSwitches) const {
1409 : #ifdef DEBUG_CHECK_FLANKS
1410 : std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1411 : #endif
1412 : const MSJunction* junction = dwLink->getJunction();
1413 4067 : if (junction == nullptr) {
1414 : return; // unregulated junction;
1415 : }
1416 4061 : const MSJunctionLogic* logic = junction->getLogic();
1417 4061 : if (logic == nullptr) {
1418 : return; // unregulated junction;
1419 : }
1420 21040 : for (const MSEdge* in : junction->getIncoming()) {
1421 16983 : if (in->isInternal()) {
1422 8355 : continue;
1423 : }
1424 17256 : for (MSLane* inLane : in->getLanes()) {
1425 8628 : if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
1426 4194 : for (MSLink* link : inLane->getLinkCont()) {
1427 2220 : if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1428 6084 : && visited.count(link->getLane()) == 0) {
1429 : #ifdef DEBUG_CHECK_FLANKS
1430 : std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1431 : #endif
1432 20 : if (link->getViaLane() == nullptr) {
1433 8 : flankSwitches.push_back(link);
1434 : } else {
1435 12 : flankSwitches.push_back(link->getViaLane()->getLinkCont().front());
1436 : }
1437 : }
1438 : }
1439 : }
1440 : }
1441 : }
1442 : }
1443 :
1444 : void
1445 28567 : MSRailSignal::DriveWay::findFlankProtection(MSLink* link, double length, LaneVisitedMap& visited, MSLink* origLink, std::vector<const MSLane*>& flank) {
1446 : #ifdef DEBUG_CHECK_FLANKS
1447 : std::cout << " findFlankProtection link=" << link->getDescription() << " length=" << length << " origLink=" << origLink->getDescription() << "\n";
1448 : #endif
1449 28567 : if (link->getTLLogic() != nullptr) {
1450 : // guarded by signal
1451 : #ifdef DEBUG_CHECK_FLANKS
1452 : std::cout << " flank guarded by " << link->getTLLogic()->getID() << "\n";
1453 : #endif
1454 5598 : myConflictLinks.push_back(link);
1455 22969 : } else if (length > MAX_BLOCK_LENGTH) {
1456 : // length exceeded
1457 0 : if (myNumWarnings < MAX_SIGNAL_WARNINGS) {
1458 0 : WRITE_WARNING("Incoming block at junction '" + origLink->getJunction()->getID() + "', link " + toString(origLink->getIndex()) + " exceeds maximum length (stopped searching after lane '" + link->getLane()->getID() + "' (length=" + toString(length) + "m).");
1459 : }
1460 0 : myNumWarnings++;
1461 : } else {
1462 : // find normal lane before this link
1463 22969 : const MSLane* lane = link->getLaneBefore();
1464 : const bool isNew = visited.count(lane) == 0;
1465 275 : if (isNew || (visited[lane] > visited[origLink->getLane()] && std::find(myForward.begin(), myForward.end(), lane) == myForward.end())) {
1466 22905 : if (isNew) {
1467 22694 : appendMapIndex(visited, lane);
1468 : }
1469 22905 : length += lane->getLength();
1470 22905 : if (lane->isInternal()) {
1471 12625 : flank.push_back(lane);
1472 12625 : findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink, flank);
1473 : } else {
1474 : bool foundPSwitch = false;
1475 22258 : for (MSLink* l2 : lane->getLinkCont()) {
1476 : #ifdef DEBUG_CHECK_FLANKS
1477 : std::cout << " lane=" << lane->getID() << " visitedIndex=" << visited[lane] << " origIndex=" << visited[origLink->getLane()] << " cand=" << l2->getDescription() << "\n";
1478 : #endif
1479 11978 : if (l2->getDirection() != LinkDirection::TURN && l2->getLane() != link->getLane()) {
1480 : foundPSwitch = true;
1481 : // found potential protection
1482 : #ifdef DEBUG_CHECK_FLANKS
1483 : std::cout << " protectingSwitch=" << l2->getDescription() << " for flank=" << link->getDescription() << "\n";
1484 : #endif
1485 1688 : myProtectingSwitches.push_back(link);
1486 1688 : if (std::find(myBidi.begin(), myBidi.end(), origLink->getLane()) != myBidi.end()) {
1487 : #ifdef DEBUG_CHECK_FLANKS
1488 : std::cout << " (is bidi-switch)\n";
1489 : #endif
1490 485 : myProtectingSwitchesBidi.push_back(link);
1491 : }
1492 : }
1493 : }
1494 10280 : if (!foundPSwitch) {
1495 8592 : flank.push_back(lane);
1496 : // continue search for protection upstream recursively
1497 16965 : for (auto ili : lane->getIncomingLanes()) {
1498 8373 : if (ili.viaLink->getDirection() != LinkDirection::TURN) {
1499 8345 : findFlankProtection(ili.viaLink, length, visited, origLink, flank);
1500 : }
1501 : }
1502 : }
1503 : }
1504 : } else {
1505 : #ifdef DEBUG_CHECK_FLANKS
1506 : std::cout << " laneBefore=" << lane->getID() << " already visited. index=" << visited[lane] << " origAfter=" << origLink->getLane()->getID() << " origIndex=" << visited[origLink->getLane()] << "\n";
1507 : #endif
1508 : }
1509 : }
1510 28567 : myMaxFlankLength = MAX2(myMaxFlankLength, length);
1511 28567 : }
1512 :
1513 : void
1514 22656 : MSRailSignal::storeTraCIVehicles(int linkIndex) {
1515 : myBlockingVehicles.clear();
1516 : myRivalVehicles.clear();
1517 : myPriorityVehicles.clear();
1518 : myConstraintInfo = "";
1519 22656 : myStoreVehicles = true;
1520 22656 : LinkInfo& li = myLinkInfos[linkIndex];
1521 22656 : if (li.myLink->getApproaching().size() > 0) {
1522 2445 : Approaching closest = getClosest(li.myLink);
1523 2445 : DriveWay& driveway = li.getDriveWay(closest.first);
1524 : MSEdgeVector occupied;
1525 : // call for side effects
1526 2445 : driveway.reserve(closest, occupied);
1527 2445 : constraintsAllow(closest.first);
1528 20211 : } else if (li.myDriveways.size() > 0) {
1529 39192 : li.myDriveways.front().conflictLaneOccupied();
1530 19596 : li.myDriveways.front().conflictLinkApproached();
1531 : }
1532 22656 : myStoreVehicles = false;
1533 22656 : }
1534 :
1535 : MSRailSignal::VehicleVector
1536 7560 : MSRailSignal::getBlockingVehicles(int linkIndex) {
1537 7560 : storeTraCIVehicles(linkIndex);
1538 7560 : return myBlockingVehicles;
1539 : }
1540 :
1541 : MSRailSignal::VehicleVector
1542 7548 : MSRailSignal::getRivalVehicles(int linkIndex) {
1543 7548 : storeTraCIVehicles(linkIndex);
1544 7548 : return myRivalVehicles;
1545 : }
1546 :
1547 : MSRailSignal::VehicleVector
1548 7548 : MSRailSignal::getPriorityVehicles(int linkIndex) {
1549 7548 : storeTraCIVehicles(linkIndex);
1550 7548 : return myPriorityVehicles;
1551 : }
1552 :
1553 : std::string
1554 0 : MSRailSignal::getConstraintInfo(int linkIndex) {
1555 0 : storeTraCIVehicles(linkIndex);
1556 0 : return myConstraintInfo;
1557 : }
1558 :
1559 : const MSRailSignal::DriveWay&
1560 32 : MSRailSignal::retrieveDriveWay(int numericalID) const {
1561 32 : for (const LinkInfo& li : myLinkInfos) {
1562 32 : for (const DriveWay& dw : li.myDriveways) {
1563 32 : if (dw.myNumericalID == numericalID) {
1564 32 : return dw;
1565 : }
1566 : }
1567 : }
1568 0 : throw ProcessError("Invalid driveway id " + toString(numericalID) + " at railSignal '" + getID() + "'");
1569 : }
1570 :
1571 :
1572 : void
1573 59 : MSRailSignal::updateDriveway(int numericalID) {
1574 115 : for (LinkInfo& li : myLinkInfos) {
1575 115 : for (auto it = li.myDriveways.begin(); it != li.myDriveways.end(); it++) {
1576 : const DriveWay& dw = *it;
1577 59 : if (dw.myNumericalID == numericalID) {
1578 : #ifdef DEBUG_DRIVEWAY_UPDATE
1579 : std::cout << SIMTIME << " rail signal junction '" << getID() << "' requires update for driveway " << numericalID << "\n";
1580 : #endif
1581 59 : std::vector<const MSEdge*> route = dw.myRoute;
1582 59 : li.myDriveways.erase(it);
1583 59 : if (li.myDriveways.size() == 0) {
1584 : // rebuild default driveway
1585 118 : li.myDriveways.push_back(li.buildDriveWay(route.begin(), route.end()));
1586 : }
1587 : return;
1588 : }
1589 : }
1590 : }
1591 : }
1592 :
1593 : std::string
1594 0 : MSRailSignal::getBlockingVehicleIDs() const {
1595 : MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1596 0 : if (myLinkInfos.size() == 1) {
1597 0 : return toString(rs->getBlockingVehicles(0));
1598 : } else {
1599 : std::string result;
1600 0 : for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1601 0 : result += toString(i) + ": " + toString(rs->getBlockingVehicles(i)) + ";";
1602 : }
1603 : return result;
1604 : }
1605 : }
1606 : std::string
1607 0 : MSRailSignal::getRivalVehicleIDs() const {
1608 : MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1609 0 : if (myLinkInfos.size() == 1) {
1610 0 : return toString(rs->getRivalVehicles(0));
1611 : } else {
1612 : std::string result;
1613 0 : for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1614 0 : result += toString(i) + ": " + toString(rs->getRivalVehicles(i)) + ";";
1615 : }
1616 : return result;
1617 : }
1618 : }
1619 : std::string
1620 0 : MSRailSignal::getPriorityVehicleIDs() const {
1621 : MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1622 0 : if (myLinkInfos.size() == 1) {
1623 0 : return toString(rs->getPriorityVehicles(0));
1624 : } else {
1625 : std::string result;
1626 0 : for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1627 0 : result += toString(i) + ": " + toString(rs->getPriorityVehicles(i)) + ";";
1628 : }
1629 : return result;
1630 : }
1631 : }
1632 : std::string
1633 0 : MSRailSignal::getConstraintInfo() const {
1634 : MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1635 0 : if (myLinkInfos.size() == 1) {
1636 0 : return rs->getConstraintInfo(0);
1637 : } else {
1638 : std::string result;
1639 0 : for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1640 0 : result += toString(i) + ": " + rs->getConstraintInfo(i);
1641 : }
1642 : return result;
1643 : }
1644 : }
1645 :
1646 : void
1647 5 : MSRailSignal::setParameter(const std::string& key, const std::string& value) {
1648 : // some pre-defined parameters can be updated at runtime
1649 5 : if (key == "moving-block") {
1650 5 : bool movingBlock = StringUtils::toBool(value);
1651 5 : if (movingBlock != myMovingBlock) {
1652 : // recompute driveways
1653 5 : myMovingBlock = movingBlock;
1654 10 : for (LinkInfo& li : myLinkInfos) {
1655 5 : li.reset();
1656 : }
1657 5 : updateCurrentPhase();
1658 5 : setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1659 : }
1660 : }
1661 5 : Parameterised::setParameter(key, value);
1662 5 : }
1663 :
1664 : /****************************************************************************/
|