Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSRailSignal.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2023 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/****************************************************************************/
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
30#endif
33#include <microsim/MSNet.h>
34#include <microsim/MSEdge.h>
36#include <microsim/MSLane.h>
37#include <microsim/MSLink.h>
39#include <microsim/MSVehicle.h>
42#include <microsim/MSLane.h>
43
44#include "MSTLLogicControl.h"
45#include "MSTrafficLightLogic.h"
46#include "MSPhaseDefinition.h"
47#include "MSTLLogicControl.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_RECHECKGREEN
69//#define DEBUG_REROUTE
70
71#define DEBUG_COND DEBUG_HELPER(this)
72#define DEBUG_COND_LINKINFO DEBUG_HELPER(myLink->getTLLogic())
73#define DEBUG_HELPER(obj) ((obj)->isSelected())
74//#define DEBUG_HELPER(obj) ((obj)->getID() == "")
75//#define DEBUG_HELPER(obj) (true)
76
77// ===========================================================================
78// static value definitions
79// ===========================================================================
81
82std::vector<std::pair<MSLink*, int> > MSRailSignal::mySwitchedGreenFlanks;
83std::map<std::pair<int, int>, bool> MSRailSignal::myDriveWayCompatibility;
85
91
92// ===========================================================================
93// method definitions
94// ===========================================================================
96 const std::string& id, const std::string& programID, SUMOTime delay,
97 const Parameterised::Map& parameters) :
98 MSTrafficLightLogic(tlcontrol, id, programID, 0, TrafficLightType::RAIL_SIGNAL, delay, parameters),
99 myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X')), // dummy phase
100 myPhaseIndex(0) {
102 myMovingBlock = OptionsCont::getOptions().getBool("railsignal-moving-block");
104}
105
106void
108 if (myLanes.size() == 0) {
109 WRITE_WARNINGF(TL("Rail signal at junction '%' does not control any links"), getID());
110 }
111 for (LinkVector& links : myLinks) { //for every link index
112 if (links.size() != 1) {
113 throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
114 + " links controlled by index " + toString(links[0]->getTLIndex()));
115 }
116 myLinkInfos.push_back(LinkInfo(links[0]));
117 }
119 setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
120 myNumLinks = (int)myLinks.size();
121}
122
123
127
128
129// ----------- Handling of controlled links
130void
135
136
137// ------------ Switching and setting current rows
143
144
145
146void
148#ifdef DEBUG_SIGNALSTATE
150#endif
151 // green by default so vehicles can be inserted at the borders of the network
152 std::string state(myLinks.size(), 'G');
153 for (LinkInfo& li : myLinkInfos) {
154 if (li.myLink->getApproaching().size() > 0) {
155 Approaching closest = getClosest(li.myLink);
156 DriveWay& driveway = li.getDriveWay(closest.first);
157 //std::cout << SIMTIME << " signal=" << getTLLinkID(li.myLink) << " veh=" << closest.first->getID() << " dw:\n";
158 //driveway.writeBlocks(*OutputDevice_COUT::getDevice());
159 const bool mustWait = !constraintsAllow(closest.first);
160 MSEdgeVector occupied;
161 if (mustWait || !driveway.reserve(closest, occupied)) {
162 state[li.myLink->getTLIndex()] = 'r';
163 if (occupied.size() > 0) {
164 li.reroute(const_cast<SUMOVehicle*>(closest.first), occupied);
165 }
166#ifdef DEBUG_SIGNALSTATE
167 if (gDebugFlag4) {
168 std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " notReserved\n";
169 }
170#endif
171 } else {
172 state[li.myLink->getTLIndex()] = 'G';
173 if (driveway.myFlank.size() > 0 && myCurrentPhase.getState()[li.myLink->getTLIndex()] != 'G') {
174 // schedule recheck
175 mySwitchedGreenFlanks.push_back(std::make_pair(li.myLink, driveway.myNumericalID));
176 }
177#ifdef DEBUG_SIGNALSTATE
178 if (gDebugFlag4) {
179 std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " reserved\n";
180 }
181#endif
182 }
183 } else {
184 if (li.myDriveways.empty()) {
185#ifdef DEBUG_SIGNALSTATE
186 if (gDebugFlag4) {
187 std::cout << SIMTIME << " rsl=" << li.getID() << " red for unitialized signal (no driveways yet)\n";
188 }
189#endif
190 state[li.myLink->getTLIndex()] = 'r';
191 } else {
192 DriveWay& driveway = li.myDriveways.front();
193 if (driveway.conflictLaneOccupied() || driveway.conflictLinkApproached()) {
194#ifdef DEBUG_SIGNALSTATE
195 if (gDebugFlag4) {
196 std::cout << SIMTIME << " rsl=" << li.getID() << " red for default driveway (" << toString(driveway.myRoute) << ")\n";
197 }
198#endif
199 state[li.myLink->getTLIndex()] = 'r';
200 } else {
201#ifdef DEBUG_SIGNALSTATE
202 if (gDebugFlag4) {
203 std::cout << SIMTIME << " rsl=" << li.getID() << " green for default driveway (" << toString(driveway.myRoute) << ")\n";
204 }
205#endif
206 }
207 }
208 }
209 }
210 if (myCurrentPhase.getState() != state) {
213 }
214#ifdef DEBUG_SIGNALSTATE
215 gDebugFlag4 = false;
216#endif
217}
218
219
220bool
222 if (myConstraints.size() == 0) {
223 return true;
224 } else {
225 const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
226 auto it = myConstraints.find(tripID);
227 if (it != myConstraints.end()) {
228 for (MSRailSignalConstraint* c : it->second) {
229 // ignore insertion constraints here
230 if (!c->isInsertionConstraint() && !c->cleared()) {
231#ifdef DEBUG_SIGNALSTATE
232 if (gDebugFlag4) {
233 std::cout << " constraint '" << c->getDescription() << "' not cleared\n";
234 }
235#endif
236 if (myStoreVehicles) {
237 myConstraintInfo = c->getDescription();
238 }
239 return false;
240 }
241 }
242 }
243 return true;
244 }
245}
246
247
248void
249MSRailSignal::addConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
250 myConstraints[tripId].push_back(constraint);
251}
252
253
254bool
255MSRailSignal::removeConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
256 if (myConstraints.count(tripId) != 0) {
257 auto& constraints = myConstraints[tripId];
258 auto it = std::find(constraints.begin(), constraints.end(), constraint);
259 if (it != constraints.end()) {
260 delete *it;
261 constraints.erase(it);
262 return true;
263 }
264 }
265 return false;
266}
267
268void
270 for (auto item : myConstraints) {
271 for (MSRailSignalConstraint* c : item.second) {
272 delete c;
273 }
274 }
275 myConstraints.clear();
276}
277
278
279// ------------ Static Information Retrieval
280int
282 return 0;
283}
284
287 return myPhases;
288}
289
292 return myCurrentPhase;
293}
294
295// ------------ Dynamic Information Retrieval
296int
300
305
306// ------------ Conversion between time and phase
309 return 0;
310}
311
314 return 0;
315}
316
317int
319 return 0;
320}
321
322
323void
324MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
325 if (pos >= 0) {
326 MSTrafficLightLogic::addLink(link, lane, pos);
327 } // ignore uncontrolled link
328}
329
330
331std::string
333 return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
334}
335
336std::string
338 return link->getJunction()->getID() + "_" + toString(link->getIndex());
339}
340
341std::string
343 return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
344}
345
346std::string
347MSRailSignal::describeLinks(std::vector<MSLink*> links) {
348 std::string result;
349 for (MSLink* link : links) {
350 result += link->getDescription() + " ";
351 }
352 return result;
353}
354
355std::string
357 std::vector<const MSLane*> lanes(visited.size(), nullptr);
358 for (auto item : visited) {
359 lanes[item.second] = item.first;
360 }
361 return toString(lanes);
362}
363
364
365void
367 // avoid undefined behavior from evaluation order
368 const int tmp = (int)map.size();
369 map[lane] = tmp;
370}
371
372
375 assert(link->getApproaching().size() > 0);
376 double minDist = std::numeric_limits<double>::max();
377 auto closestIt = link->getApproaching().begin();
378 for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
379 if (apprIt->second.dist < minDist) {
380 minDist = apprIt->second.dist;
381 closestIt = apprIt;
382 }
383 }
384 // maybe a parallel link has a closer vehicle
385 /*
386 for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
387 if (link2 != link) {
388 for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
389 if (apprIt2->second.dist < minDist) {
390 minDist = apprIt2->second.dist;
391 closestIt = apprIt2;
392 }
393 }
394 }
395 }
396 */
397 return *closestIt;
398}
399
400
401void
403 od.openTag("railSignal");
405 for (const LinkInfo& li : myLinkInfos) {
406 MSLink* link = li.myLink;
407 od.openTag("link");
411 for (const DriveWay& dw : li.myDriveways) {
412 dw.writeBlocks(od);
413 }
414 od.closeTag(); // link
415 }
416 od.closeTag(); // railSignal
417}
418
419
420void
422 const ConstMSEdgeVector& edges = ego->getRoute().getEdges();
423 int endIndex = ego->getParameter().arrivalEdge;
424 if (endIndex < 0) {
425 endIndex = (int)edges.size() - 1;
426 }
427 for (int i = ego->getParameter().departEdge; i <= endIndex - 1; i++) {
428 const MSEdge* e = edges[i];
430 const MSEdge* e2 = edges[i + 1];
431 for (MSLane* lane : e->getLanes()) {
432 for (MSLink* link : lane->getLinkCont()) {
433 if (&link->getLane()->getEdge() == e2) {
434 MSRailSignal* rs = const_cast<MSRailSignal*>(dynamic_cast<const MSRailSignal*>(link->getTLLogic()));
435 if (rs != nullptr) {
436 LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
437 if (li.myDriveways.empty()) {
438 // init driveway
439 li.getDriveWay(ego);
440 if (update && rs->isActive()) {
441 // vehicle may have rerouted it's intial trip
442 // after the states have been set
443 // @note: This is a hack because it could lead to invalid tls-output
444 // (it's still an improvement over switching based on default driveways)
445 rs->trySwitch();
447 }
448 }
449 }
450 }
451 }
452 }
453 }
454 }
455}
456
457
458bool
459MSRailSignal::hasOncomingRailTraffic(MSLink* link, const MSVehicle* ego, bool& brakeBeforeSignal) {
460 // @note: this check is intended to prevent deadlock / collision by an inserted vehicle that
461 // waits at a red signal and thus checks different things than ::reverse()
462 bool hadOncoming = false;
464 const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
465 if (bidi == nullptr) {
466 brakeBeforeSignal = false;
467 return false;
468 }
469 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
470 if (rs != nullptr) {
471 const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
472 for (const DriveWay& dw : li.myDriveways) {
473 //std::cout << SIMTIME << " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
474 for (const MSLane* lane : dw.myBidi) {
475 if (!lane->isEmpty()) {
476 MSVehicle* veh = lane->getFirstAnyVehicle();
477 if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
478#ifdef DEBUG_SIGNALSTATE
479 if (DEBUG_HELPER(rs)) {
480 std::cout << " oncoming vehicle on bidi-lane " << lane->getID() << "\n";
481 }
482#endif
483 return true;
484 }
485 }
486 }
487 for (const MSLane* lane : dw.myFlank) {
488 if (!lane->isEmpty()) {
489 MSVehicle* veh = lane->getFirstAnyVehicle();
490 if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
491#ifdef DEBUG_SIGNALSTATE
492 if (DEBUG_HELPER(rs)) {
493 std::cout << " oncoming vehicle on flank-lane " << lane->getID() << "\n";
494 }
495#endif
496 return true;
497 }
498 }
499 }
500 if (dw.myProtectingSwitchesBidi.size() > 0) {
501#ifdef DEBUG_SIGNALSTATE
503#endif
504 // yield to all foeLinks beyond switch
505 Approaching approaching(ego,
506 MSLink::ApproachingVehicleInformation(SIMSTEP, 0, 0, 0, false, 0, 0, std::numeric_limits<double>::max(), 0, 0));
507 for (MSLink* const switchLink : dw.myProtectingSwitchesBidi) {
508 myBlockingVehicles.clear();
509 myRivalVehicles.clear();
510 myPriorityVehicles.clear();
511 myConstraintInfo = "";
512 myStoreVehicles = true;
513 const bool hasProtection = dw.findProtection(approaching, switchLink);
514 myStoreVehicles = false;
515 if (!hasProtection) {
516 for (const SUMOVehicle* veh : myBlockingVehicles) {
517 hadOncoming = true;
518 if (!brakeBeforeSignal || std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
519#ifdef DEBUG_SIGNALSTATE
520 if (DEBUG_HELPER(rs)) {
521 std::cout << " no protection at bidi-switch " << switchLink->getDescription() << " from veh=" << veh->getID() << "\n";
522 gDebugFlag4 = false;
523 }
524#endif
525 return true;
526 }
527 }
528 for (const SUMOVehicle* veh : myRivalVehicles) {
529 hadOncoming = true;
530 if (!brakeBeforeSignal || std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
531#ifdef DEBUG_SIGNALSTATE
532 if (DEBUG_HELPER(rs)) {
533 std::cout << " no protection at bidi-switch " << switchLink->getDescription() << " from linkRival veh=" << veh->getID() << "\n";
534 gDebugFlag4 = false;
535 }
536#endif
537 return true;
538 }
539 }
540 }
541 }
542#ifdef DEBUG_SIGNALSTATE
543 gDebugFlag4 = false;
544#endif
545 }
546 for (MSLink* foeLink : dw.myConflictLinks) {
547 if (foeLink->getApproaching().size() != 0) {
548 Approaching closest = getClosest(foeLink);
549 const SUMOVehicle* veh = closest.first;
550 if (veh->getSpeed() > 0 && closest.second.arrivalSpeedBraking > 0
551 && std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
552#ifdef DEBUG_SIGNALSTATE
553 if (DEBUG_HELPER(rs)) {
554 std::cout << " oncoming vehicle approaching foe link " << foeLink->getDescription() << "\n";
555 }
556#endif
557 return true;
558 }
559 }
560 }
561 }
562 }
563 }
564 brakeBeforeSignal = hadOncoming;
565 return false;
566}
567
568bool
569MSRailSignal::hasInsertionConstraint(MSLink* link, const MSVehicle* veh, std::string& info, bool& isInsertionOrder) {
570 if (link->getJunction() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
571 const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
572 if (rs != nullptr && rs->myConstraints.size() > 0) {
573 const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
574 auto it = rs->myConstraints.find(tripID);
575 if (it != rs->myConstraints.end()) {
576 for (MSRailSignalConstraint* c : it->second) {
577 if (c->isInsertionConstraint() && !c->cleared()) {
578#ifdef DEBUG_SIGNALSTATE
579 if (DEBUG_HELPER(rs)) {
580 std::cout << SIMTIME << " rsl=" << rs->getID() << " insertion constraint '" << c->getDescription() << "' for vehicle '" << veh->getID() << "' not cleared\n";
581 }
582#endif
583 info = c->getDescription();
584 isInsertionOrder = c->getType() == MSRailSignalConstraint::ConstraintType::INSERTION_ORDER;
585 return true;
586 }
587 }
588 }
589 }
590 }
591 return false;
592}
593
594// ===========================================================================
595// LinkInfo method definitions
596// ===========================================================================
597
599 myLink(link) {
600 reset();
601}
602
603
604void
606 myLastRerouteTime = -1;
607 myLastRerouteVehicle = nullptr;
608 myDriveways.clear();
609}
610
611
612std::string
614 return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
615}
616
617
620 MSEdge* first = &myLink->getLane()->getEdge();
621 MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
622 if (firstIt == veh->getRoute().end()) {
623 // possibly the vehicle has already gone past the first edge (i.e.
624 // because first is short or the step-length is high)
625 // lets look backward along the route
626 // give some slack because the vehicle might have been braking from a higher speed and using ballistic integration
627 double lookBack = SPEED2DIST(veh->getSpeed() + 10);
628 int routeIndex = veh->getRoutePosition() - 1;
629 while (lookBack > 0 && routeIndex > 0) {
630 const MSEdge* prevEdge = veh->getRoute().getEdges()[routeIndex];
631 if (prevEdge == first) {
632 firstIt = veh->getRoute().begin() + routeIndex;
633 break;
634 }
635 lookBack -= prevEdge->getLength();
636 routeIndex--;
637 }
638 }
639 if (firstIt == veh->getRoute().end()) {
640 WRITE_WARNING("Invalid approach information to rail signal '" + getClickableTLLinkID(myLink) + "' after rerouting for vehicle '" + veh->getID()
641 + "' first driveway edge '" + first->getID() + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
642 if (myDriveways.empty()) {
643 ConstMSEdgeVector dummyRoute;
644 dummyRoute.push_back(&myLink->getLane()->getEdge());
645 DriveWay dw = buildDriveWay(dummyRoute.begin(), dummyRoute.end());
646 myDriveways.push_back(dw);
647 }
648 return myDriveways.front();
649 }
650 //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
651 for (DriveWay& dw : myDriveways) {
652 // @todo optimize: it is sufficient to check for specific edges (after each switch)
653 auto itRoute = firstIt;
654 auto itDwRoute = dw.myRoute.begin();
655 bool match = true;
656 while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
657 if (*itRoute != *itDwRoute) {
658 match = false;
659 //std::cout << " check dw=" << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
660 break;
661 }
662 itRoute++;
663 itDwRoute++;
664 }
665 // if the vehicle arrives before the end of this driveway,
666 // we'd rather build a new driveway to avoid superfluous restrictions
667 if (match && itDwRoute == dw.myRoute.end()
668 && (itRoute == veh->getRoute().end() || dw.myFoundSignal || dw.myFoundReversal)) {
669 //std::cout << " using dw=" << "\n";
670 return dw;
671 }
672#ifdef DEBUG_SELECT_DRIVEWAY
673 std::cout << SIMTIME << " rs=" << getID() << " veh=" << veh->getID() << " other dwSignal=" << dw.myFoundSignal << " dwRoute=" << toString(dw.myRoute) << " route=" << toString(veh->getRoute().getEdges()) << "\n";
674#endif
675 }
676 DriveWay dw = buildDriveWay(firstIt, veh->getRoute().end());
677#ifdef DEBUG_SELECT_DRIVEWAY
678 std::cout << SIMTIME << " rs=" << getID() << " veh=" << veh->getID() << " new dwSignal=" << dw.myFoundSignal << " dwRoute=" << toString(dw.myRoute) << " route=" << toString(veh->getRoute().getEdges()) << "\n";
679#endif
680 myDriveways.push_back(dw);
681 return myDriveways.back();
682}
683
684
687 // collect lanes and links that are relevant for setting this signal for the current driveWay
688 // For each driveway we collect
689 // - conflictLanes (signal must be red if any conflict lane is occupied)
690 // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
691 // - that cannot break in time (arrivalSpeedBraking > 0)
692 // - approached by a vehicle with higher switching priority (see #3941)
693 // These objects are construct in steps:
694 //
695 // forwardBlock
696 // - search forward recursive from outgoing lane until controlled railSignal link found
697 // -> add all found lanes to conflictLanes
698 //
699 // bidiBlock (if any forwardBlock edge has bidi edge)
700 // - search bidi backward recursive until first switch
701 // - from switch search backward recursive all other incoming until controlled rail signal link
702 // -> add final links to conflictLinks
703 //
704 // flanks
705 // - search backward recursive from flanking switches
706 // until controlled railSignal link or protecting switch is found
707 // -> add all found lanes to conflictLanes
708 // -> add final links to conflictLinks
709
710 DriveWay dw;
711 LaneVisitedMap visited;
712 std::vector<const MSLane*> before;
713 appendMapIndex(visited, myLink->getLaneBefore());
714 MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
715 if (fromBidi != nullptr) {
716 // do not extend to forward block beyond the entering track (in case of a loop)
717 appendMapIndex(visited, fromBidi);
718 before.push_back(fromBidi);
719 }
720 dw.buildRoute(myLink, 0., first, end, visited);
721 if (dw.myProtectedBidi == nullptr) {
722 dw.myCoreSize = (int)dw.myRoute.size();
723 }
724 dw.checkFlanks(myLink, dw.myForward, visited, true, dw.myFlankSwitches);
725 dw.checkFlanks(myLink, dw.myBidi, visited, false, dw.myFlankSwitches);
726 dw.checkFlanks(myLink, before, visited, true, dw.myFlankSwitches);
727 for (MSLink* link : dw.myFlankSwitches) {
728 //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
729 dw.findFlankProtection(link, 0, visited, link, dw.myFlank);
730 }
731 std::vector<MSLink*> flankSwitchesBidiExtended;
732 dw.checkFlanks(myLink, dw.myBidiExtended, visited, false, flankSwitchesBidiExtended);
733 for (MSLink* link : flankSwitchesBidiExtended) {
734 //std::cout << getID() << " flankSwitchBEx=" << link->getDescription() << "\n";
735 dw.findFlankProtection(link, 0, visited, link, dw.myBidiExtended);
736 }
737
738#ifdef DEBUG_BUILD_DRIVEWAY
740 std::cout << " buildDriveWay railSignal=" << getID()
741 << "\n route=" << toString(dw.myRoute)
742 << "\n forward=" << toString(dw.myForward)
743 << "\n bidi=" << toString(dw.myBidi)
744 << "\n flank=" << toString(dw.myFlank)
745 << "\n flankSwitch=" << describeLinks(dw.myFlankSwitches)
746 << "\n protSwitch=" << describeLinks(dw.myProtectingSwitches)
747 << "\n coreSize=" << dw.myCoreSize
748 << "\n";
749 }
750#endif
751 MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(myLink->getTLLogic()));
752 if (!rs->myMovingBlock) {
753 dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
754 }
755 dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
756 dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
757 if (dw.myProtectedBidi != nullptr) {
759 }
760
761 return dw;
762}
763
764
765void
767 MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
769 if (rDev != nullptr
770 && rDev->mayRerouteRailSignal()
771 && (myLastRerouteVehicle != veh
772 // reroute each vehicle only once if no periodic routing is allowed,
773 // otherwise with the specified period
774 || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
775 myLastRerouteVehicle = veh;
776 myLastRerouteTime = now;
777
778#ifdef DEBUG_REROUTE
779 ConstMSEdgeVector oldRoute = veh->getRoute().getEdges();
781 std::cout << SIMTIME << " reroute veh=" << veh->getID() << " rs=" << getID() << " occupied=" << toString(occupied) << "\n";
782 }
783#endif
784 MSRoutingEngine::reroute(*veh, now, "railSignal:" + getID(), false, true, occupied);
785#ifdef DEBUG_REROUTE
786 // attention this works only if we are not parallel!
788 if (veh->getRoute().getEdges() != oldRoute) {
789 std::cout << " rerouting successful\n";
790 }
791 }
792#endif
793 }
794}
795
796
797// ===========================================================================
798// DriveWay method definitions
799// ===========================================================================
800
801bool
803 std::string joinVehicle = "";
805 const SUMOVehicleParameter::Stop* stop = closest.first->getNextStopParameter();
806 if (stop != nullptr) {
807 joinVehicle = stop->join;
808 }
809 }
810 if (conflictLaneOccupied(joinVehicle, true, closest.first)) {
811 for (const MSLane* bidi : myBidi) {
812 if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
813 occupied.push_back(&bidi->getBidiLane()->getEdge());
814 }
815 }
816#ifdef DEBUG_SIGNALSTATE
817 if (gDebugFlag4) {
818 std::cout << " conflictLaneOccupied by=" << toString(myBlockingVehicles) << " ego=" << Named::getIDSecure(closest.first) << "\n";
819 }
820#endif
821 return false;
822 }
823 for (MSLink* link : myProtectingSwitches) {
824 if (!findProtection(closest, link)) {
825#ifdef DEBUG_SIGNALSTATE
826 if (gDebugFlag4) {
827 std::cout << " no protection at switch " << link->getDescription() << "\n";
828 }
829#endif
830 return false;
831 }
832 }
833 for (MSLink* foeLink : myConflictLinks) {
834 if (hasLinkConflict(closest, foeLink)) {
835#ifdef DEBUG_SIGNALSTATE
836 if (gDebugFlag4) {
837 std::cout << " linkConflict with " << getTLLinkID(foeLink) << "\n";
838 }
839#endif
840 return false;
841 }
842 }
843 if (deadlockLaneOccupied()) {
844 return false;
845 }
846 myActive = closest.first;
847 return true;
848}
849
850
851bool
853 for (MSLink* foeLink : myConflictLinks) {
854 if (foeLink->getApproaching().size() > 0) {
855#ifdef DEBUG_SIGNALSTATE
856 if (gDebugFlag4) {
857 std::cout << SIMTIME << " foeLink=" << foeLink->getDescription() << " approachedBy=" << foeLink->getApproaching().begin()->first->getID() << "\n";
858 }
859#endif
860 return true;
861 }
862 }
863 return false;
864}
865
866
867bool
869#ifdef DEBUG_SIGNALSTATE_PRIORITY
870 if (gDebugFlag4) {
871 std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
872 }
873#endif
874 if (foeLink->getApproaching().size() > 0) {
875 Approaching foe = getClosest(foeLink);
876#ifdef DEBUG_SIGNALSTATE_PRIORITY
877 if (gDebugFlag4) {
878 std::cout << " approaching foe=" << foe.first->getID() << "\n";
879 }
880#endif
881 const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
882 assert(foeTLL != nullptr);
883 const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
884 MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
885 if (foeRS != nullptr) {
886 const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
887 if (foeDriveWay.conflictLaneOccupied("", false, foe.first) ||
888 foeDriveWay.deadlockLaneOccupied(false) ||
889 !foeRS->constraintsAllow(foe.first) ||
890 !overlap(foeDriveWay)) {
891#ifdef DEBUG_SIGNALSTATE_PRIORITY
892 if (gDebugFlag4) {
893 if (foeDriveWay.conflictLaneOccupied("", false, foe.first)) {
894 std::cout << " foe blocked\n";
895 } else if (!foeRS->constraintsAllow(foe.first)) {
896 std::cout << " foe constrained\n";
897 } else {
898 std::cout << " no overlap\n";
899 }
900 }
901#endif
902 return false;
903 }
904#ifdef DEBUG_SIGNALSTATE_PRIORITY
905 if (gDebugFlag4) {
906 std::cout
907 << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
908 << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
909 << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
910 << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
911 << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
912 << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
913 << "\n";
914 }
915#endif
916 const bool yield = mustYield(veh, foe);
917 if (myStoreVehicles) {
918 myRivalVehicles.push_back(foe.first);
919 if (yield) {
920 myPriorityVehicles.push_back(foe.first);
921 }
922 }
923 return yield;
924 }
925 }
926 return false;
927}
928
929
930bool
932 if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
933 if (foe.second.arrivalTime == veh.second.arrivalTime) {
934 if (foe.first->getSpeed() == veh.first->getSpeed()) {
935 if (foe.second.dist == veh.second.dist) {
936 if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
937 return foe.first->getNumericalID() < veh.first->getNumericalID();
938 } else {
939 return foe.first->getWaitingTime() > veh.first->getWaitingTime();
940 }
941 } else {
942 return foe.second.dist < veh.second.dist;
943 }
944 } else {
945 return foe.first->getSpeed() > veh.first->getSpeed();
946 }
947 } else {
948 return foe.second.arrivalTime < veh.second.arrivalTime;
949 }
950 } else {
951 return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
952 }
953}
954
955
956bool
957MSRailSignal::DriveWay::conflictLaneOccupied(const std::string& joinVehicle, bool store, const SUMOVehicle* ego) const {
958 for (const MSLane* lane : myConflictLanes) {
959 if (!lane->isEmpty()) {
960#ifdef DEBUG_SIGNALSTATE
961 if (gDebugFlag4) {
962 std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied ego=" << Named::getIDSecure(ego) << " vehNumber=" << lane->getVehicleNumber() << "\n";
963 if (joinVehicle != "") {
964 std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
965 lane->releaseVehicles();
966 }
967 }
968#endif
969 if (lane->getVehicleNumberWithPartials() == 1) {
970 MSVehicle* foe = lane->getLastAnyVehicle();
971 if (joinVehicle != "") {
972 if (foe->getID() == joinVehicle && foe->isStopped()) {
973#ifdef DEBUG_SIGNALSTATE
974 if (gDebugFlag4) {
975 std::cout << " ignore join-target '" << joinVehicle << "\n";
976 }
977#endif
978 continue;
979 }
980 }
981 if (ego != nullptr) {
982 if (foe == ego && std::find(myBidi.begin(), myBidi.end(), lane) != myBidi.end()) {
983#ifdef DEBUG_SIGNALSTATE
984 if (gDebugFlag4) {
985 std::cout << " ignore ego as oncoming '" << ego->getID() << "\n";
986 }
987#endif
988 continue;
989 }
990 }
991 }
992 if (myStoreVehicles && store) {
993 myBlockingVehicles.push_back(lane->getLastAnyVehicle());
994 }
995 return true;
996 }
997 }
998 return false;
999}
1000
1001bool
1003 for (const MSLane* lane : myBidiExtended) {
1004 if (!lane->empty()) {
1005 assert(myBidi.size() != 0);
1006 const MSEdge* lastBidi = myBidi.back()->getNextNormal();
1007 MSVehicle* foe = lane->getVehiclesSecure().front();
1008#ifdef DEBUG_SIGNALSTATE
1009 if (gDebugFlag4) {
1010 std::cout << " check for deadlock with " << foe->getID() << "\n";
1011 }
1012#endif
1013 // check of foe will enter myBidi (need to check at most
1014 // myBidiExtended.size edges)
1015 const int minEdges = (int)myBidiExtended.size();
1016 auto foeIt = foe->getCurrentRouteEdge() + 1;
1017 auto foeEnd = foe->getRoute().end();
1018 bool conflict = false;
1019 for (int i = 0; i < minEdges && foeIt != foeEnd; i++) {
1020 if ((*foeIt) == lastBidi) {
1021#ifdef DEBUG_SIGNALSTATE
1022 if (gDebugFlag4) {
1023 std::cout << " vehicle will enter " << lastBidi->getID() << "\n";
1024 }
1025#endif
1026 conflict = true;
1027 break;
1028 }
1029 foeIt++;
1030 }
1031 lane->releaseVehicles();
1032 if (conflict) {
1033 if (myStoreVehicles && store) {
1034 myBlockingVehicles.push_back(foe);
1035 }
1036 return true;
1037 }
1038 }
1039 }
1040 return false;
1041}
1042
1043
1044bool
1046 double flankApproachingDist = std::numeric_limits<double>::max();
1047 if (link->getApproaching().size() > 0) {
1048 Approaching closest = getClosest(link);
1049 flankApproachingDist = closest.second.dist;
1050 }
1051#ifdef DEBUG_FIND_PROTECTION
1052 if (gDebugFlag4) {
1053 std::cout << SIMTIME << " findProtection for link=" << link->getDescription() << " flankApproachingDist=" << flankApproachingDist << "\n";
1054 }
1055#endif
1056 for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
1057 if (l2->getLane() != link->getLane()) {
1058#ifdef DEBUG_FIND_PROTECTION
1059 if (gDebugFlag4) {
1060 std::cout << " protectionCandidate=" << l2->getDescription() << " l2Via=" << Named::getIDSecure(l2->getViaLane())
1061 << " occupied=" << (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) << "\n";
1062 }
1063#endif
1064 if (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) {
1065#ifdef DEBUG_FIND_PROTECTION
1066 if (gDebugFlag4) {
1067 std::cout << " protection from internal=" << l2->getViaLane()->getID() << "\n";
1068 }
1069#endif
1070 return true;
1071 }
1072 if (l2->getApproaching().size() > 0) {
1073 Approaching closest2 = getClosest(l2);
1074 if (closest2.second.dist < flankApproachingDist) {
1075#ifdef DEBUG_FIND_PROTECTION
1076 if (gDebugFlag4) {
1077 std::cout << " protection from veh=" << closest2.first->getID() << "\n";
1078 }
1079#endif
1080 return true;
1081 }
1082 }
1083 }
1084 }
1085 if (link->getApproaching().size() == 0) {
1086 return true;
1087 } else {
1088 // find protection further upstream
1089 DriveWay tmp(true);
1090 const MSLane* before = link->getLaneBefore();
1091 tmp.myFlank.push_back(before);
1092 LaneVisitedMap visited;
1093 for (auto ili : before->getIncomingLanes()) {
1094 tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink, tmp.myFlank);
1095 }
1096 tmp.myConflictLanes = tmp.myFlank;
1097 tmp.myRoute = myRoute;
1098 tmp.myCoreSize = myCoreSize;
1099 MSEdgeVector occupied;
1100 if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
1101 << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
1102 return tmp.reserve(veh, occupied);
1103 }
1104}
1105
1106
1107bool
1109 for (int i = 0; i < myCoreSize; i++) {
1110 for (int j = 0; j < other.myCoreSize; j++) {
1111 const MSEdge* edge = myRoute[i];
1112 const MSEdge* edge2 = other.myRoute[j];
1113 if (edge->getToJunction() == edge2->getToJunction()
1114 || edge->getToJunction() == edge2->getFromJunction()) {
1115 // XXX might be rail_crossing with parallel tracks
1116 return true;
1117 }
1118 }
1119 }
1120 return false;
1121}
1122
1123bool
1125 for (const MSLane* lane : myForward) {
1126 for (const MSLane* lane2 : other.myForward) {
1127 if (lane == lane2) {
1128 return true;
1129 }
1130 }
1131 for (const MSLane* lane2 : other.myBidi) {
1132 if (lane == lane2) {
1133 return true;
1134 }
1135 }
1136 }
1137 return false;
1138}
1139
1140void
1142 od.openTag("driveWay");
1143 od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
1144 if (myCoreSize != (int)myRoute.size()) {
1145 od.writeAttr("core", myCoreSize);
1146 }
1147 od.openTag("forward");
1148 od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
1149 od.closeTag();
1150 od.openTag("bidi");
1151 od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
1152 if (myBidiExtended.size() > 0) {
1153 od.lf();
1154 od << " ";
1155 od.writeAttr("deadlockCheck", toString(myBidiExtended));
1156 }
1157 od.closeTag();
1158 od.openTag("flank");
1159 od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
1160 od.closeTag();
1161
1162 od.openTag("protectingSwitches");
1163 std::vector<std::string> links;
1164 for (MSLink* link : myProtectingSwitches) {
1165 links.push_back(getJunctionLinkID(link));
1166 }
1167 od.writeAttr("links", joinToString(links, " "));
1168 od.closeTag();
1169
1170 od.openTag("conflictLinks");
1171 std::vector<std::string> signals;
1172 for (MSLink* link : myConflictLinks) {
1173 signals.push_back(getTLLinkID(link));
1174 }
1175 od.writeAttr("signals", joinToString(signals, " "));
1176 od.closeTag();
1177 od.closeTag(); // driveWay
1178}
1179
1180
1181void
1184 LaneVisitedMap& visited) {
1185 bool seekForwardSignal = true;
1186 bool seekBidiSwitch = true;
1187 bool foundUnsafeSwitch = false;
1188 MSLane* toLane = origin->getViaLaneOrLane();
1189#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1190 gDebugFlag4 = DEBUG_HELPER(origin->getTLLogic());
1191 if (gDebugFlag4) std::cout << "buildRoute origin=" << getTLLinkID(origin) << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1192 << " visited=" << formatVisitedMap(visited) << "\n";
1193#endif
1194 while ((seekForwardSignal || seekBidiSwitch)) {
1195 if (length > MAX_BLOCK_LENGTH) {
1197 WRITE_WARNING("Block after rail signal " + getClickableTLLinkID(origin) +
1198 " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
1199 }
1200 myNumWarnings++;
1201 // length exceeded
1202 return;
1203 }
1204#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1205 if (gDebugFlag4) {
1206 std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1207 }
1208#endif
1209 if (visited.count(toLane) != 0) {
1210 WRITE_WARNINGF(TL("Found circular block after railSignal % (% edges, length %)"), getClickableTLLinkID(origin), toString(myRoute.size()), toString(length));
1211 //std::cout << getClickableTLLinkID(origin) << " circularBlock1=" << toString(myRoute) << " visited=" << formatVisitedMap(visited) << "\n";
1212 return;
1213 }
1214 if (toLane->getEdge().isNormal()) {
1215 myRoute.push_back(&toLane->getEdge());
1216 if (next != end) {
1217 next++;
1218 }
1219 }
1220 appendMapIndex(visited, toLane);
1221 length += toLane->getLength();
1222 MSLane* bidi = toLane->getBidiLane();
1223 if (seekForwardSignal) {
1224 if (!foundUnsafeSwitch) {
1225 myForward.push_back(toLane);
1226 }
1227 } else if (bidi == nullptr) {
1228 seekBidiSwitch = false;
1229#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1230 if (gDebugFlag4) {
1231 std::cout << " noBidi, abort search for bidiSwitch\n";
1232 }
1233#endif
1234 }
1235 if (bidi != nullptr) {
1236 if (foundUnsafeSwitch) {
1237 myBidiExtended.push_back(bidi);
1238 } else {
1239 myBidi.push_back(bidi);
1240 }
1241 appendMapIndex(visited, bidi);
1242 if (!seekForwardSignal) {
1243 // look for switch that could protect from oncoming vehicles
1244 for (const auto& ili : bidi->getIncomingLanes()) {
1245 if (ili.viaLink->getDirection() == LinkDirection::TURN) {
1246 continue;
1247 }
1248 for (const MSLink* const link : ili.lane->getLinkCont()) {
1249 if (link->getDirection() == LinkDirection::TURN) {
1250 continue;
1251 }
1252 if (link->getViaLaneOrLane() != bidi) {
1253 // this switch is special beause it still lies on the current route
1254 //myProtectingSwitches.push_back(ili.viaLink);
1255 const MSEdge* const bidiNext = bidi->getNextNormal();
1256 myCoreSize = (int)myRoute.size();
1257 if (MSRailSignalControl::getInstance().getUsedEdges().count(bidiNext) == 0) {
1258#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1259 if (gDebugFlag4) {
1260 std::cout << " abort: found protecting switch " << ili.viaLink->getDescription() << "\n";
1261 }
1262#endif
1263 // if bidi is actually used by a train (rather than
1264 // the other route) we must later adapt this driveway for additional checks (myBidiExtended)
1265 myProtectedBidi = bidiNext;
1266 std::set<const MSEdge*> visitedEdges;
1267 for (auto item : visited) {
1268 visitedEdges.insert(&item.first->getEdge());
1269 }
1270 while (next != end && visitedEdges.count(*next) == 0) {
1271 // the driveway is route specific but only but stop recording if it loops back on itself
1272 visitedEdges.insert(*next);
1273 const MSEdge* nextBidi = (*next)->getBidiEdge();
1274 if (nextBidi != nullptr) {
1275 visitedEdges.insert(nextBidi);
1276 }
1277 myRoute.push_back(*next);
1278 next++;
1279 }
1280 return;
1281 } else {
1282#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1283 if (gDebugFlag4) {
1284 std::cout << " found unsafe switch " << ili.viaLink->getDescription() << " (used=" << bidiNext->getID() << ")\n";
1285 }
1286#endif
1287 // trains along our route beyond this switch
1288 // might create deadlock
1289 foundUnsafeSwitch = true;
1290 // the switch itself must still be guarded to ensure safety
1291 for (const auto& ili2 : bidi->getIncomingLanes()) {
1292 if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
1293 myFlankSwitches.push_back(ili.viaLink);
1294 }
1295 }
1296 }
1297 }
1298 }
1299 }
1300 }
1301 }
1302 const std::vector<MSLink*>& links = toLane->getLinkCont();
1303 const MSEdge* current = &toLane->getEdge();
1304 toLane = nullptr;
1305 for (const MSLink* const link : links) {
1306 if ((next != end && &link->getLane()->getEdge() == *next)
1307 && isRailway(link->getViaLaneOrLane()->getPermissions())) {
1308 toLane = link->getViaLaneOrLane();
1309 if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1310 // do not follow turn-arounds even if the route contains a reversal
1311#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1312 if (gDebugFlag4) {
1313 std::cout << " abort: turn-around\n";
1314 }
1315#endif
1316 myFoundReversal = true;
1317 return;
1318 }
1319 if (link->getTLLogic() != nullptr) {
1320 if (link->getTLLogic() == origin->getTLLogic()) {
1321 WRITE_WARNINGF(TL("Found circular block at railSignal % (% edges, length %)"), getClickableTLLinkID(origin), toString(myRoute.size()), toString(length));
1322 //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1323 return;
1324 }
1325 seekForwardSignal = false;
1326 myFoundSignal = true;
1327 seekBidiSwitch = bidi != nullptr;
1328#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1329 if (gDebugFlag4) {
1330 std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1331 }
1332#endif
1333 }
1334 break;
1335 }
1336 }
1337 if (toLane == nullptr) {
1338 if (next != end) {
1339 // no connection found, jump to next route edge
1340 toLane = (*next)->getLanes()[0];
1341 } else {
1342#ifdef DEBUG_DRIVEWAY_BUILDROUTE
1343 if (gDebugFlag4) {
1344 std::cout << " abort: no next lane available\n";
1345 }
1346#endif
1347 return;
1348 }
1349 }
1350 }
1351}
1352
1353
1354void
1355MSRailSignal::DriveWay::checkFlanks(const MSLink* originLink, const std::vector<const MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes, std::vector<MSLink*>& flankSwitches) const {
1356#ifdef DEBUG_CHECK_FLANKS
1357 std::cout << " checkFlanks lanes=" << toString(lanes) << "\n visited=" << formatVisitedMap(visited) << " allFoes=" << allFoes << "\n";
1358#endif
1359 const MSLink* reverseOriginLink = originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1360 ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1361 : nullptr;
1362 //std::cout << " originLink=" << originLink->getDescription() << "\n";
1363 if (reverseOriginLink != nullptr) {
1364 reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1365 //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1366 }
1367 for (int i = 0; i < (int)lanes.size(); i++) {
1368 const MSLane* lane = lanes[i];
1369 const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1370 const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1371 if (lane->isInternal()) {
1372 continue;
1373 }
1374 for (auto ili : lane->getIncomingLanes()) {
1375 if (ili.viaLink == originLink
1376 || ili.viaLink == reverseOriginLink
1377 || ili.viaLink->getDirection() == LinkDirection::TURN
1378 || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND) {
1379 continue;
1380 }
1381 if (ili.lane != prev && ili.lane != next) {
1382#ifdef DEBUG_CHECK_FLANKS
1383 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";
1384#endif
1385 flankSwitches.push_back(ili.viaLink);
1386 } else if (allFoes) {
1387 // link is part of the driveway, find foes that cross the driveway without entering
1388 checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1389 }
1390 }
1391 }
1392}
1393
1394
1395void
1396MSRailSignal::DriveWay::checkCrossingFlanks(MSLink* dwLink, const LaneVisitedMap& visited, std::vector<MSLink*>& flankSwitches) const {
1397#ifdef DEBUG_CHECK_FLANKS
1398 std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1399#endif
1400 const MSJunction* junction = dwLink->getJunction();
1401 if (junction == nullptr) {
1402 return; // unregulated junction;
1403 }
1404 const MSJunctionLogic* logic = junction->getLogic();
1405 if (logic == nullptr) {
1406 return; // unregulated junction;
1407 }
1408 for (const MSEdge* in : junction->getIncoming()) {
1409 if (in->isInternal()) {
1410 continue;
1411 }
1412 for (MSLane* inLane : in->getLanes()) {
1413 if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
1414 for (MSLink* link : inLane->getLinkCont()) {
1415 if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1416 && visited.count(link->getLane()) == 0) {
1417#ifdef DEBUG_CHECK_FLANKS
1418 std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1419#endif
1420 if (link->getViaLane() == nullptr) {
1421 flankSwitches.push_back(link);
1422 } else {
1423 flankSwitches.push_back(link->getViaLane()->getLinkCont().front());
1424 }
1425 }
1426 }
1427 }
1428 }
1429 }
1430}
1431
1432void
1433MSRailSignal::DriveWay::findFlankProtection(MSLink* link, double length, LaneVisitedMap& visited, MSLink* origLink, std::vector<const MSLane*>& flank) {
1434#ifdef DEBUG_CHECK_FLANKS
1435 std::cout << " findFlankProtection link=" << link->getDescription() << " length=" << length << " origLink=" << origLink->getDescription() << "\n";
1436#endif
1437 if (link->getTLLogic() != nullptr) {
1438 // guarded by signal
1439#ifdef DEBUG_CHECK_FLANKS
1440 std::cout << " flank guarded by " << link->getTLLogic()->getID() << "\n";
1441#endif
1442 myConflictLinks.push_back(link);
1443 } else if (length > MAX_BLOCK_LENGTH) {
1444 // length exceeded
1446 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).");
1447 }
1448 myNumWarnings++;
1449 } else {
1450 // find normal lane before this link
1451 const MSLane* lane = link->getLaneBefore();
1452 const bool isNew = visited.count(lane) == 0;
1453 if (isNew || (visited[lane] > visited[origLink->getLane()] && std::find(myForward.begin(), myForward.end(), lane) == myForward.end())) {
1454 if (isNew) {
1455 appendMapIndex(visited, lane);
1456 }
1457 length += lane->getLength();
1458 if (lane->isInternal()) {
1459 flank.push_back(lane);
1460 findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink, flank);
1461 } else {
1462 bool foundPSwitch = false;
1463 for (MSLink* l2 : lane->getLinkCont()) {
1464#ifdef DEBUG_CHECK_FLANKS
1465 std::cout << " lane=" << lane->getID() << " visitedIndex=" << visited[lane] << " origIndex=" << visited[origLink->getLane()] << " cand=" << l2->getDescription() << "\n";
1466#endif
1467 if (l2->getDirection() != LinkDirection::TURN && l2->getLane() != link->getLane()) {
1468 foundPSwitch = true;
1469 // found potential protection
1470#ifdef DEBUG_CHECK_FLANKS
1471 std::cout << " protectingSwitch=" << l2->getDescription() << " for flank=" << link->getDescription() << "\n";
1472#endif
1473 myProtectingSwitches.push_back(link);
1474 if (std::find(myBidi.begin(), myBidi.end(), origLink->getLane()) != myBidi.end()) {
1475#ifdef DEBUG_CHECK_FLANKS
1476 std::cout << " (is bidi-switch)\n";
1477#endif
1478 myProtectingSwitchesBidi.push_back(link);
1479 }
1480 }
1481 }
1482 if (!foundPSwitch) {
1483 flank.push_back(lane);
1484 // continue search for protection upstream recursively
1485 for (auto ili : lane->getIncomingLanes()) {
1486 if (ili.viaLink->getDirection() != LinkDirection::TURN) {
1487 findFlankProtection(ili.viaLink, length, visited, origLink, flank);
1488 }
1489 }
1490 }
1491 }
1492 } else {
1493#ifdef DEBUG_CHECK_FLANKS
1494 std::cout << " laneBefore=" << lane->getID() << " already visited. index=" << visited[lane] << " origAfter=" << origLink->getLane()->getID() << " origIndex=" << visited[origLink->getLane()] << "\n";
1495#endif
1496 }
1497 }
1498 myMaxFlankLength = MAX2(myMaxFlankLength, length);
1499}
1500
1501void
1503 myBlockingVehicles.clear();
1504 myRivalVehicles.clear();
1505 myPriorityVehicles.clear();
1506 myConstraintInfo = "";
1507 myStoreVehicles = true;
1508 LinkInfo& li = myLinkInfos[linkIndex];
1509 if (li.myLink->getApproaching().size() > 0) {
1510 Approaching closest = getClosest(li.myLink);
1511 DriveWay& driveway = li.getDriveWay(closest.first);
1512 MSEdgeVector occupied;
1513 // call for side effects
1514 driveway.reserve(closest, occupied);
1515 constraintsAllow(closest.first);
1516 } else if (li.myDriveways.size() > 0) {
1517 li.myDriveways.front().conflictLaneOccupied();
1518 li.myDriveways.front().conflictLinkApproached();
1519 }
1520 myStoreVehicles = false;
1521}
1522
1525 storeTraCIVehicles(linkIndex);
1526 return myBlockingVehicles;
1527}
1528
1531 storeTraCIVehicles(linkIndex);
1532 return myRivalVehicles;
1533}
1534
1537 storeTraCIVehicles(linkIndex);
1538 return myPriorityVehicles;
1539}
1540
1541std::string
1543 storeTraCIVehicles(linkIndex);
1544 return myConstraintInfo;
1545}
1546
1548MSRailSignal::retrieveDriveWay(int numericalID) const {
1549 for (const LinkInfo& li : myLinkInfos) {
1550 for (const DriveWay& dw : li.myDriveways) {
1551 if (dw.myNumericalID == numericalID) {
1552 return dw;
1553 }
1554 }
1555 }
1556 throw ProcessError("Invalid driveway id " + toString(numericalID) + " at railSignal '" + getID() + "'");
1557}
1558
1559
1560void
1562 if (mySwitchedGreenFlanks.size() > 0) {
1563 for (const auto& item : mySwitchedGreenFlanks) {
1564 for (const auto& item2 : mySwitchedGreenFlanks) {
1565 if (item.second < item2.second) {
1566 bool conflict = false;
1567 std::pair<int, int> code(item.second, item2.second);
1568 auto it = myDriveWayCompatibility.find(code);
1569 if (it != myDriveWayCompatibility.end()) {
1570 conflict = it->second;
1571 } else {
1572 // new driveway pair
1573 const MSRailSignal* rs = static_cast<const MSRailSignal*>(item.first->getTLLogic());
1574 const MSRailSignal* rs2 = static_cast<const MSRailSignal*>(item2.first->getTLLogic());
1575 const DriveWay& dw = rs->retrieveDriveWay(item.second);
1576 const DriveWay& dw2 = rs2->retrieveDriveWay(item2.second);
1577 // overlap may return true if the driveways are consecutive forward sections
1578 conflict = dw.flankConflict(dw2) || dw2.flankConflict(dw);
1579 myDriveWayCompatibility[code] = conflict;
1580#ifdef DEBUG_RECHECKGREEN
1581 std::cout << SIMTIME << " new code " << code.first << "," << code.second << " conflict=" << conflict << " dw=" << toString(dw.myRoute) << " dw2=" << toString(dw2.myRoute) << "\n";
1582#endif
1583 }
1584 if (conflict) {
1585 MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item.first->getTLLogic()));
1586 MSRailSignal* rs2 = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item2.first->getTLLogic()));
1587 const Approaching& veh = rs->getClosest(item.first);
1588 const Approaching& veh2 = rs2->getClosest(item2.first);
1589 if (DriveWay::mustYield(veh, veh2)) {
1590 std::string state = rs->myCurrentPhase.getState();
1591 state[item.first->getTLIndex()] = 'r';
1592 rs->myCurrentPhase.setState(state);
1594#ifdef DEBUG_RECHECKGREEN
1595 std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1596 << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1597#endif
1598#ifdef DEBUG_SIGNALSTATE
1599 if (DEBUG_HELPER(rs)) {
1600 std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1601 << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1602 }
1603#endif
1604 } else {
1605 std::string state = rs2->myCurrentPhase.getState();
1606 state[item2.first->getTLIndex()] = 'r';
1607 rs2->myCurrentPhase.setState(state);
1608 rs2->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1609#ifdef DEBUG_RECHECKGREEN
1610 std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1611 << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1612#endif
1613#ifdef DEBUG_SIGNALSTATE
1614 if (DEBUG_HELPER(rs2)) {
1615 std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1616 << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1617 }
1618#endif
1619 }
1620 }
1621 }
1622 }
1623 }
1624 mySwitchedGreenFlanks.clear();
1625 }
1626}
1627
1628void
1630 for (LinkInfo& li : myLinkInfos) {
1631 for (auto it = li.myDriveways.begin(); it != li.myDriveways.end(); it++) {
1632 const DriveWay& dw = *it;
1633 if (dw.myNumericalID == numericalID) {
1634#ifdef DEBUG_DRIVEWAY_UPDATE
1635 std::cout << SIMTIME << " rail signal junction '" << getID() << "' requires update for driveway " << numericalID << "\n";
1636#endif
1637 std::vector<const MSEdge*> route = dw.myRoute;
1638 li.myDriveways.erase(it);
1639 if (li.myDriveways.size() == 0) {
1640 // rebuild default driveway
1641 li.myDriveways.push_back(li.buildDriveWay(route.begin(), route.end()));
1642 }
1643 return;
1644 }
1645 }
1646 }
1647}
1648
1649std::string
1651 MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1652 if (myLinkInfos.size() == 1) {
1653 return toString(rs->getBlockingVehicles(0));
1654 } else {
1655 std::string result;
1656 for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1657 result += toString(i) + ": " + toString(rs->getBlockingVehicles(i)) + ";";
1658 }
1659 return result;
1660 }
1661}
1662std::string
1664 MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1665 if (myLinkInfos.size() == 1) {
1666 return toString(rs->getRivalVehicles(0));
1667 } else {
1668 std::string result;
1669 for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1670 result += toString(i) + ": " + toString(rs->getRivalVehicles(i)) + ";";
1671 }
1672 return result;
1673 }
1674}
1675std::string
1677 MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1678 if (myLinkInfos.size() == 1) {
1679 return toString(rs->getPriorityVehicles(0));
1680 } else {
1681 std::string result;
1682 for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1683 result += toString(i) + ": " + toString(rs->getPriorityVehicles(i)) + ";";
1684 }
1685 return result;
1686 }
1687}
1688std::string
1690 MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1691 if (myLinkInfos.size() == 1) {
1692 return rs->getConstraintInfo(0);
1693 } else {
1694 std::string result;
1695 for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1696 result += toString(i) + ": " + rs->getConstraintInfo(i);
1697 }
1698 return result;
1699 }
1700}
1701
1702void
1703MSRailSignal::setParameter(const std::string& key, const std::string& value) {
1704 // some pre-defined parameters can be updated at runtime
1705 if (key == "moving-block") {
1706 bool movingBlock = StringUtils::toBool(value);
1707 if (movingBlock != myMovingBlock) {
1708 // recompute driveways
1709 myMovingBlock = movingBlock;
1710 for (LinkInfo& li : myLinkInfos) {
1711 li.reset();
1712 }
1714 setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1715 }
1716 }
1717 Parameterised::setParameter(key, value);
1718}
1719
1720/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
#define DEBUG_COND_LINKINFO
#define DEBUG_HELPER(obj)
#define MAX_SIGNAL_WARNINGS
#define MAX_BLOCK_LENGTH
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition MSRoute.h:56
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:271
#define WRITE_WARNING(msg)
Definition MsgHandler.h:270
#define TL(string)
Definition MsgHandler.h:287
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMSTEP
Definition SUMOTime.h:61
#define SIMTIME
Definition SUMOTime.h:62
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
@ TURN
The link is a 180 degree turn.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ SUMO_ATTR_EDGES
the edges of a route
@ SUMO_ATTR_LANES
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_ID
@ SUMO_ATTR_TLLINKINDEX
link: the index of the link within the traffic light
bool gDebugFlag4
Definition StdDefs.cpp:38
T MAX2(T a, T b)
Definition StdDefs.h:82
#define SUMO_MAX_CONNECTIONS
the maximum number of connections across an intersection
Definition StdDefs.h:41
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
const MSRoute & getRoute() const
Returns the current route.
bool isStopped() const
Returns whether the vehicle is at a stop.
A device that performs vehicle rerouting based on current edge speeds.
SUMOTime getPeriod() const
bool mayRerouteRailSignal() const
return whether the equipped vehicle may receive dispatch information at a rail signal
A road/street connecting two junctions.
Definition MSEdge.h:77
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:279
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:260
const MSJunction * getToJunction() const
Definition MSEdge.h:415
double getLength() const
return the length of the edge
Definition MSEdge.h:658
const MSJunction * getFromJunction() const
Definition MSEdge.h:411
static bool gUseMesoSim
Definition MSGlobals.h:103
The base class for an intersection.
Definition MSJunction.h:58
SumoXMLNodeType getType() const
return the type of this Junction
Definition MSJunction.h:135
virtual const MSJunctionLogic * getLogic() const
Definition MSJunction.h:143
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:110
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2560
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2301
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:923
double getLength() const
Returns the lane's length.
Definition MSLane.h:593
bool isInternal() const
Definition MSLane.cpp:2456
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4425
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:745
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:707
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:183
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:322
The definition of a single phase of a tls logic.
const std::string & getState() const
Returns the state within this phase.
void setState(const std::string &_state)
A base class for constraints.
void addSignal(MSRailSignal *signal)
static MSRailSignalControl & getInstance()
const std::set< const MSEdge * > & getUsedEdges() const
void registerProtectedDriveway(MSRailSignal *rs, int driveWayID, const MSEdge *protectedBidi)
mark driveway that must receive additional checks if protectedBidi is ever used by a train route
A signal for rails.
bool constraintsAllow(const SUMOVehicle *veh) const
whether the given vehicle is free to drive
static VehicleVector myRivalVehicles
std::string getBlockingVehicleIDs() const
Phases myPhases
The list of phases this logic uses.
std::string getConstraintInfo(int linkIndex)
return information regarding active rail signal constraints for the closest approaching vehicle
static VehicleVector myPriorityVehicles
int myPhaseIndex
MSTrafficLightLogic requires that the phase index changes whenever signals change their state.
SUMOTime getOffsetFromIndex(int index) const override
Returns the position (start of a phase during a cycle) from of a given step.
void setParameter(const std::string &key, const std::string &value) override
Sets a parameter and updates internal constants.
static std::string myConstraintInfo
MSPhaseDefinition myCurrentPhase
The current phase.
void addConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for signal switching
static std::string getClickableTLLinkID(MSLink *link)
return logicID_linkIndex in a way that allows clicking in sumo-gui
std::vector< LinkInfo > myLinkInfos
data storage for every link at this node (more than one when directly guarding a switch)
SUMOTime getPhaseIndexAtTime(SUMOTime simStep) const override
Returns the index of the logic at the given simulation step.
std::string getPriorityVehicleIDs() const
MSRailSignal(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, SUMOTime delay, const Parameterised::Map &parameters)
Constructor.
static void appendMapIndex(LaneVisitedMap &map, const MSLane *lane)
append to map by map index and avoid undefined behavior
VehicleVector getBlockingVehicles(int linkIndex) override
return vehicles that block the intersection/rail signal for vehicles that wish to pass the given link...
VehicleVector getRivalVehicles(int linkIndex) override
return vehicles that approach the intersection/rail signal and are in conflict with vehicles that wis...
static int myDriveWayIndex
static std::string describeLinks(std::vector< MSLink * > links)
print link descriptions
void writeBlocks(OutputDevice &od) const
write rail signal block output for all links and driveways
~MSRailSignal()
Destructor.
void adaptLinkInformationFrom(const MSTrafficLightLogic &logic) override
Applies information about controlled links and lanes from the given logic.
static VehicleVector myBlockingVehicles
void removeConstraints()
void storeTraCIVehicles(int linkIndex)
update vehicle lists for traci calls
int getIndexFromOffset(SUMOTime offset) const override
Returns the step (the phasenumber) of a given position of the cycle.
static Approaching getClosest(MSLink *link)
get the closest vehicle approaching the given link
void init(NLDetectorBuilder &nb) override
Initialises the rail signal with information about adjacent rail signals.
std::map< std::string, std::vector< MSRailSignalConstraint * > > myConstraints
map from tripId to constraint list
static std::map< std::pair< int, int >, bool > myDriveWayCompatibility
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
int getPhaseNumber() const override
Returns the number of phases.
const MSPhaseDefinition & getPhase(int givenstep) const override
Returns the definition of the phase from the given position within the plan.
static void recheckGreen()
final check for driveway compatibility of signals that switched green in this step
static std::string getJunctionLinkID(MSLink *link)
return junctionID_junctionLinkIndex
static int myNumWarnings
SUMOTime trySwitch() override
Switches to the next phase.
const DriveWay & retrieveDriveWay(int numericalID) const
static bool myStoreVehicles
std::map< const MSLane *, int, ComparatorNumericalIdLess > LaneVisitedMap
bool myMovingBlock
whether the signal is in moving block mode (only protects from oncoming and flanking trains)
bool removeConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
remove contraint for signal switching
static bool hasOncomingRailTraffic(MSLink *link, const MSVehicle *ego, bool &brakeBeforeSignal)
static std::vector< std::pair< MSLink *, int > > mySwitchedGreenFlanks
list of signals that switched green along with driveway index
const Phases & getPhases() const override
Returns the phases of this tls program.
const MSPhaseDefinition & getCurrentPhaseDef() const override
Returns the definition of the current phase.
void updateDriveway(int numericalID)
update driveway for extended deadlock protection
std::string getConstraintInfo() const
static std::string formatVisitedMap(const LaneVisitedMap &visited)
print link descriptions
static void initDriveWays(const SUMOVehicle *ego, bool update)
void updateCurrentPhase()
returns the state of the signal that actually required
void addLink(MSLink *link, MSLane *lane, int pos) override
Adds a link on building.
std::string getRivalVehicleIDs() const
static bool hasInsertionConstraint(MSLink *link, const MSVehicle *veh, std::string &info, bool &isInsertionOrder)
VehicleVector getPriorityVehicles(int linkIndex) override
return vehicles that approach the intersection/rail signal and have priority over vehicles that wish ...
static std::string getTLLinkID(MSLink *link)
return logicID_linkIndex
int getCurrentPhaseIndex() const override
Returns the current index within the program.
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:124
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition MSRoute.cpp:79
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
static void reroute(SUMOVehicle &vehicle, const SUMOTime currentTime, const std::string &info, const bool onInit=false, const bool silent=false, const MSEdgeVector &prohibited=MSEdgeVector())
initiate the rerouting, create router / thread pool on first use
A class that stores and controls tls and switching of their programs.
The parent class for traffic light logics.
virtual void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
std::vector< const SUMOVehicle * > VehicleVector
list of vehicles
SUMOTime myDefaultCycleTime
The cycle time (without changes)
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
int myNumLinks
number of controlled links
bool isActive() const
whether this logic is the active program
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
virtual void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
LinkVectorVector myLinks
The list of LinkVectors; each vector contains the links that belong to the same link index.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
Builds detectors for microsim.
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
void lf()
writes a line feed if applicable
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
std::map< std::string, std::string > Map
parameters map
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual int getRoutePosition() const =0
return index of edge within route
Representation of a vehicle.
Definition SUMOVehicle.h:62
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
virtual const MSRoute & getRoute() const =0
Returns the current route.
Definition of vehicle stop (position and duration)
std::string join
the id of the vehicle (train portion) to which this vehicle shall be joined
int departEdge
(optional) The initial edge within the route of the vehicle
int arrivalEdge
(optional) The final edge within the route of the vehicle
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
#define DEBUG_COND
Definition json.hpp:4471
std::vector< const MSLane * > myForward
void writeBlocks(OutputDevice &od) const
Write block items for this driveway.
void buildRoute(MSLink *origin, double length, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap &visited)
void checkFlanks(const MSLink *originLink, const std::vector< const MSLane * > &lanes, const LaneVisitedMap &visited, bool allFoes, std::vector< MSLink * > &flankSwitches) const
std::vector< MSLink * > myFlankSwitches
int myCoreSize
number of edges in myRoute where overlap with other driveways is forbidden
bool deadlockLaneOccupied(bool store=true) const
whether any of myBidiExtended is occupied by a vehicle that targets myBidi
const MSEdge * myProtectedBidi
switch assumed safe from bidi-traffic
void findFlankProtection(MSLink *link, double length, LaneVisitedMap &visited, MSLink *origLink, std::vector< const MSLane * > &flank)
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
bool overlap(const DriveWay &other) const
Wether this driveway (route) overlaps with the given one.
int myNumericalID
global driveway index
std::vector< MSLink * > myConflictLinks
std::vector< const MSLane * > myBidi
std::vector< const MSLane * > myBidiExtended
bool conflictLaneOccupied(const std::string &joinVehicle="", bool store=true, const SUMOVehicle *ego=nullptr) const
whether any of myConflictLanes is occupied (vehicles that are the target of a join must be ignored)
std::vector< const MSLane * > myFlank
std::vector< const MSEdge * > myRoute
list of edges for matching against train routes
void checkCrossingFlanks(MSLink *dwLink, const LaneVisitedMap &visited, std::vector< MSLink * > &flankSwitches) const
bool hasLinkConflict(const Approaching &closest, MSLink *foeLink) const
Whether the approaching vehicle is prevent from driving by another vehicle approaching the given link...
bool findProtection(const Approaching &veh, MSLink *link) const
find protection for the given vehicle starting at a switch
std::vector< MSLink * > myProtectingSwitches
bool myFoundSignal
whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
bool conflictLinkApproached() const
Whether any of the conflict links have approaching vehicles.
bool reserve(const Approaching &closest, MSEdgeVector &occupied)
attempt reserve this driveway for the given vehicle
bool flankConflict(const DriveWay &other) const
Wether there is a flank conflict with the given driveway.
static bool mustYield(const Approaching &veh, const Approaching &foe)
Whether veh must yield to the foe train.