Eclipse SUMO - Simulation of Urban MObility
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-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 /****************************************************************************/
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>
35 #include <microsim/MSEdgeControl.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"
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 // ===========================================================================
80 
82 
88 
89 // ===========================================================================
90 // method definitions
91 // ===========================================================================
93  const std::string& id, const std::string& programID, SUMOTime delay,
94  const Parameterised::Map& parameters) :
95  MSTrafficLightLogic(tlcontrol, id, programID, 0, TrafficLightType::RAIL_SIGNAL, delay, parameters),
96  myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X')), // dummy phase
97  myPhaseIndex(0) {
99  myMovingBlock = OptionsCont::getOptions().getBool("railsignal-moving-block");
101 }
102 
103 void
105  if (myLanes.size() == 0) {
106  WRITE_WARNINGF(TL("Rail signal at junction '%' does not control any links"), getID());
107  }
108  for (LinkVector& links : myLinks) { //for every link index
109  if (links.size() != 1) {
110  throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
111  + " links controlled by index " + toString(links[0]->getTLIndex()));
112  }
113  myLinkInfos.push_back(LinkInfo(links[0]));
114  }
116  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
117  myNumLinks = (int)myLinks.size();
118 }
119 
120 
123 }
124 
125 
126 // ----------- Handling of controlled links
127 void
131 }
132 
133 
134 // ------------ Switching and setting current rows
135 SUMOTime
138  return DELTA_T;
139 }
140 
141 
142 
143 void
145 #ifdef DEBUG_SIGNALSTATE
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  for (LinkInfo& li : myLinkInfos) {
151  if (li.myLink->getApproaching().size() > 0) {
152  Approaching closest = getClosest(li.myLink);
153  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  const bool mustWait = !constraintsAllow(closest.first);
157  MSEdgeVector occupied;
158  if (mustWait || !driveway.reserve(closest, occupied)) {
159  state[li.myLink->getTLIndex()] = 'r';
160  if (occupied.size() > 0) {
161  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  state[li.myLink->getTLIndex()] = 'G';
170  if (driveway.myFlank.size() > 0 && myCurrentPhase.getState()[li.myLink->getTLIndex()] != 'G') {
171  // schedule recheck
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  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  state[li.myLink->getTLIndex()] = 'r';
188  } else {
189  DriveWay& driveway = li.myDriveways.front();
190  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  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  if (myCurrentPhase.getState() != state) {
208  myCurrentPhase.setState(state);
210  }
211 #ifdef DEBUG_SIGNALSTATE
212  gDebugFlag4 = false;
213 #endif
214 }
215 
216 
217 bool
219  if (myConstraints.size() == 0) {
220  return true;
221  } else {
222  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
223  auto it = myConstraints.find(tripID);
224  if (it != myConstraints.end()) {
225  for (MSRailSignalConstraint* c : it->second) {
226  // ignore insertion constraints here
227  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  if (myStoreVehicles) {
235  }
236  return false;
237  }
238  }
239  }
240  return true;
241  }
242 }
243 
244 
245 void
246 MSRailSignal::addConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
247  myConstraints[tripId].push_back(constraint);
248 }
249 
250 
251 bool
252 MSRailSignal::removeConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
253  if (myConstraints.count(tripId) != 0) {
254  auto& constraints = myConstraints[tripId];
255  auto it = std::find(constraints.begin(), constraints.end(), constraint);
256  if (it != constraints.end()) {
257  delete *it;
258  constraints.erase(it);
259  return true;
260  }
261  }
262  return false;
263 }
264 
265 void
267  for (auto item : myConstraints) {
268  for (MSRailSignalConstraint* c : item.second) {
269  delete c;
270  }
271  }
272  myConstraints.clear();
273 }
274 
275 
276 // ------------ Static Information Retrieval
277 int
279  return 0;
280 }
281 
284  return myPhases;
285 }
286 
287 const MSPhaseDefinition&
289  return myCurrentPhase;
290 }
291 
292 // ------------ Dynamic Information Retrieval
293 int
295  return myPhaseIndex;
296 }
297 
298 const MSPhaseDefinition&
300  return myCurrentPhase;
301 }
302 
303 // ------------ Conversion between time and phase
304 SUMOTime
306  return 0;
307 }
308 
309 SUMOTime
311  return 0;
312 }
313 
314 int
316  return 0;
317 }
318 
319 
320 void
321 MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
322  if (pos >= 0) {
323  MSTrafficLightLogic::addLink(link, lane, pos);
324  } // ignore uncontrolled link
325 }
326 
327 
328 std::string
330  return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
331 }
332 
333 std::string
335  return link->getJunction()->getID() + "_" + toString(link->getIndex());
336 }
337 
338 std::string
340  return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
341 }
342 
343 std::string
344 MSRailSignal::describeLinks(std::vector<MSLink*> links) {
345  std::string result;
346  for (MSLink* link : links) {
347  result += link->getDescription() + " ";
348  }
349  return result;
350 }
351 
352 std::string
354  std::vector<const MSLane*> lanes(visited.size(), nullptr);
355  for (auto item : visited) {
356  lanes[item.second] = item.first;
357  }
358  return toString(lanes);
359 }
360 
361 
362 void
364  // avoid undefined behavior from evaluation order
365  const int tmp = (int)map.size();
366  map[lane] = tmp;
367 }
368 
369 
372  assert(link->getApproaching().size() > 0);
373  double minDist = std::numeric_limits<double>::max();
374  auto closestIt = link->getApproaching().begin();
375  for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
376  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  return *closestIt;
395 }
396 
397 
398 void
400  od.openTag("railSignal");
402  for (const LinkInfo& li : myLinkInfos) {
403  MSLink* link = li.myLink;
404  od.openTag("link");
408  for (const DriveWay& dw : li.myDriveways) {
409  dw.writeBlocks(od);
410  }
411  od.closeTag(); // link
412  }
413  od.closeTag(); // railSignal
414 }
415 
416 
417 void
419  const ConstMSEdgeVector& edges = ego->getRoute().getEdges();
420  int endIndex = ego->getParameter().arrivalEdge;
421  if (endIndex < 0) {
422  endIndex = (int)edges.size() - 1;
423  }
424  for (int i = ego->getParameter().departEdge; i <= endIndex - 1; i++) {
425  const MSEdge* e = edges[i];
427  const MSEdge* e2 = edges[i + 1];
428  for (MSLane* lane : e->getLanes()) {
429  for (MSLink* link : lane->getLinkCont()) {
430  if (&link->getLane()->getEdge() == e2) {
431  MSRailSignal* rs = const_cast<MSRailSignal*>(dynamic_cast<const MSRailSignal*>(link->getTLLogic()));
432  if (rs != nullptr) {
433  LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
434  if (li.myDriveways.empty()) {
435  // init driveway
436  li.getDriveWay(ego);
437  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  rs->trySwitch();
444  }
445  }
446  }
447  }
448  }
449  }
450  }
451  }
452 }
453 
454 
455 bool
456 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;
461  const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
462  if (bidi == nullptr) {
463  brakeBeforeSignal = false;
464  return false;
465  }
466  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
467  if (rs != nullptr) {
468  const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
469  for (const DriveWay& dw : li.myDriveways) {
470  //std::cout << SIMTIME << " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
471  for (const MSLane* lane : dw.myBidi) {
472  if (!lane->isEmpty()) {
473  MSVehicle* veh = lane->getFirstAnyVehicle();
474  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  for (const MSLane* lane : dw.myFlank) {
485  if (!lane->isEmpty()) {
486  MSVehicle* veh = lane->getFirstAnyVehicle();
487  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  if (dw.myProtectingSwitchesBidi.size() > 0) {
498 #ifdef DEBUG_SIGNALSTATE
500 #endif
501  // yield to all foeLinks beyond switch
502  Approaching approaching(ego,
503  MSLink::ApproachingVehicleInformation(SIMSTEP, 0, 0, 0, false, 0, 0, std::numeric_limits<double>::max(), 0, 0));
504  for (MSLink* const switchLink : dw.myProtectingSwitchesBidi) {
505  myBlockingVehicles.clear();
506  myRivalVehicles.clear();
507  myPriorityVehicles.clear();
508  myConstraintInfo = "";
509  myStoreVehicles = true;
510  const bool hasProtection = dw.findProtection(approaching, switchLink);
511  myStoreVehicles = false;
512  if (!hasProtection) {
513  for (const SUMOVehicle* veh : myBlockingVehicles) {
514  hadOncoming = true;
515  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  for (const SUMOVehicle* veh : myRivalVehicles) {
526  hadOncoming = true;
527  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  for (MSLink* foeLink : dw.myConflictLinks) {
544  if (foeLink->getApproaching().size() != 0) {
545  Approaching closest = getClosest(foeLink);
546  const SUMOVehicle* veh = closest.first;
547  if (veh->getSpeed() > 0 && closest.second.arrivalSpeedBraking > 0
548  && 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  return true;
555  }
556  }
557  }
558  }
559  }
560  }
561  brakeBeforeSignal = hadOncoming;
562  return false;
563 }
564 
565 bool
566 MSRailSignal::hasInsertionConstraint(MSLink* link, const MSVehicle* veh, std::string& info, bool& isInsertionOrder) {
567  if (link->getJunction() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
568  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
569  if (rs != nullptr && rs->myConstraints.size() > 0) {
570  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
571  auto it = rs->myConstraints.find(tripID);
572  if (it != rs->myConstraints.end()) {
573  for (MSRailSignalConstraint* c : it->second) {
574  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  info = c->getDescription();
581  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 
596  myLink(link) {
597  reset();
598 }
599 
600 
601 void
603  myLastRerouteTime = -1;
604  myLastRerouteVehicle = nullptr;
605  myDriveways.clear();
606 }
607 
608 
609 std::string
611  return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
612 }
613 
614 
617  MSEdge* first = &myLink->getLane()->getEdge();
618  MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
619  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  double lookBack = SPEED2DIST(veh->getSpeed() + 10);
625  int routeIndex = veh->getRoutePosition() - 1;
626  while (lookBack > 0 && routeIndex > 0) {
627  const MSEdge* prevEdge = veh->getRoute().getEdges()[routeIndex];
628  if (prevEdge == first) {
629  firstIt = veh->getRoute().begin() + routeIndex;
630  break;
631  }
632  lookBack -= prevEdge->getLength();
633  routeIndex--;
634  }
635  }
636  if (firstIt == veh->getRoute().end()) {
637  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  if (myDriveways.empty()) {
640  ConstMSEdgeVector dummyRoute;
641  dummyRoute.push_back(&myLink->getLane()->getEdge());
642  DriveWay dw = buildDriveWay(dummyRoute.begin(), dummyRoute.end());
643  myDriveways.push_back(dw);
644  }
645  return myDriveways.front();
646  }
647  //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
648  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  while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
654  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  if (match && itDwRoute == dw.myRoute.end()
665  && (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  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  myDriveways.push_back(dw);
678  return myDriveways.back();
679 }
680 
681 
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  DriveWay dw;
708  LaneVisitedMap visited;
709  std::vector<const MSLane*> before;
710  appendMapIndex(visited, myLink->getLaneBefore());
711  MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
712  if (fromBidi != nullptr) {
713  // do not extend to forward block beyond the entering track (in case of a loop)
714  appendMapIndex(visited, fromBidi);
715  before.push_back(fromBidi);
716  }
717  dw.buildRoute(myLink, 0., first, end, visited);
718  if (dw.myProtectedBidi == nullptr) {
719  dw.myCoreSize = (int)dw.myRoute.size();
720  }
721  dw.checkFlanks(myLink, dw.myForward, visited, true, dw.myFlankSwitches);
722  dw.checkFlanks(myLink, dw.myBidi, visited, false, dw.myFlankSwitches);
723  dw.checkFlanks(myLink, before, visited, true, dw.myFlankSwitches);
724  for (MSLink* link : dw.myFlankSwitches) {
725  //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
726  dw.findFlankProtection(link, 0, visited, link, dw.myFlank);
727  }
728  std::vector<MSLink*> flankSwitchesBidiExtended;
729  dw.checkFlanks(myLink, dw.myBidiExtended, visited, false, flankSwitchesBidiExtended);
730  for (MSLink* link : flankSwitchesBidiExtended) {
731  //std::cout << getID() << " flankSwitchBEx=" << link->getDescription() << "\n";
732  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  MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(myLink->getTLLogic()));
749  if (!rs->myMovingBlock) {
750  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
751  }
752  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
753  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
754  if (dw.myProtectedBidi != nullptr) {
756  }
757 
758  return dw;
759 }
760 
761 
762 void
764  MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
766  if (rDev != nullptr
767  && rDev->mayRerouteRailSignal()
768  && (myLastRerouteVehicle != veh
769  // reroute each vehicle only once if no periodic routing is allowed,
770  // otherwise with the specified period
771  || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
772  myLastRerouteVehicle = veh;
773  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  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 }
792 
793 
794 // ===========================================================================
795 // DriveWay method definitions
796 // ===========================================================================
797 
798 bool
800  std::string joinVehicle = "";
801  if (!MSGlobals::gUseMesoSim) {
802  const SUMOVehicleParameter::Stop* stop = closest.first->getNextStopParameter();
803  if (stop != nullptr) {
804  joinVehicle = stop->join;
805  }
806  }
807  if (conflictLaneOccupied(joinVehicle, true, closest.first)) {
808  for (const MSLane* bidi : myBidi) {
809  if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
810  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  for (MSLink* link : myProtectingSwitches) {
821  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  for (MSLink* foeLink : myConflictLinks) {
831  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  if (deadlockLaneOccupied()) {
841  return false;
842  }
843  myActive = closest.first;
844  return true;
845 }
846 
847 
848 bool
850  for (MSLink* foeLink : myConflictLinks) {
851  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
866 #ifdef DEBUG_SIGNALSTATE_PRIORITY
867  if (gDebugFlag4) {
868  std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
869  }
870 #endif
871  if (foeLink->getApproaching().size() > 0) {
872  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  const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
881  MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
882  if (foeRS != nullptr) {
883  const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
884  if (foeDriveWay.conflictLaneOccupied("", false, foe.first) ||
885  foeDriveWay.deadlockLaneOccupied(false) ||
886  !foeRS->constraintsAllow(foe.first) ||
887  !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  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  const bool yield = mustYield(veh, foe);
914  if (myStoreVehicles) {
915  myRivalVehicles.push_back(foe.first);
916  if (yield) {
917  myPriorityVehicles.push_back(foe.first);
918  }
919  }
920  return yield;
921  }
922  }
923  return false;
924 }
925 
926 
927 bool
929  if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
930  if (foe.second.arrivalTime == veh.second.arrivalTime) {
931  if (foe.first->getSpeed() == veh.first->getSpeed()) {
932  if (foe.second.dist == veh.second.dist) {
933  if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
934  return foe.first->getNumericalID() < veh.first->getNumericalID();
935  } else {
936  return foe.first->getWaitingTime() > veh.first->getWaitingTime();
937  }
938  } else {
939  return foe.second.dist < veh.second.dist;
940  }
941  } else {
942  return foe.first->getSpeed() > veh.first->getSpeed();
943  }
944  } else {
945  return foe.second.arrivalTime < veh.second.arrivalTime;
946  }
947  } else {
948  return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
949  }
950 }
951 
952 
953 bool
954 MSRailSignal::DriveWay::conflictLaneOccupied(const std::string& joinVehicle, bool store, const SUMOVehicle* ego) const {
955  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  if (lane->getVehicleNumberWithPartials() == 1) {
967  MSVehicle* foe = lane->getLastAnyVehicle();
968  if (joinVehicle != "") {
969  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  continue;
976  }
977  }
978  if (ego != nullptr) {
979  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  continue;
986  }
987  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  continue;
994  }
995  }
996  }
997  if (myStoreVehicles && store) {
998  myBlockingVehicles.push_back(lane->getLastAnyVehicle());
999  }
1000  return true;
1001  }
1002  }
1003  return false;
1004 }
1005 
1006 bool
1008  for (const MSLane* lane : myBidiExtended) {
1009  if (!lane->empty()) {
1010  assert(myBidi.size() != 0);
1011  const MSEdge* lastBidi = myBidi.back()->getNextNormal();
1012  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  const int minEdges = (int)myBidiExtended.size();
1021  auto foeIt = foe->getCurrentRouteEdge() + 1;
1022  auto foeEnd = foe->getRoute().end();
1023  bool conflict = false;
1024  for (int i = 0; i < minEdges && foeIt != foeEnd; i++) {
1025  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  lane->releaseVehicles();
1037  if (conflict) {
1038  if (myStoreVehicles && store) {
1039  myBlockingVehicles.push_back(foe);
1040  }
1041  return true;
1042  }
1043  }
1044  }
1045  return false;
1046 }
1047 
1048 
1049 bool
1051  double flankApproachingDist = std::numeric_limits<double>::max();
1052  if (link->getApproaching().size() > 0) {
1053  Approaching closest = getClosest(link);
1054  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  for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
1062  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  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  if (l2->getApproaching().size() > 0) {
1078  Approaching closest2 = getClosest(l2);
1079  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  return true;
1086  }
1087  }
1088  }
1089  }
1090  if (link->getApproaching().size() == 0) {
1091  return true;
1092  } else {
1093  // find protection further upstream
1094  DriveWay tmp(true);
1095  const MSLane* before = link->getLaneBefore();
1096  tmp.myFlank.push_back(before);
1097  LaneVisitedMap visited;
1098  for (auto ili : before->getIncomingLanes()) {
1099  tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink, tmp.myFlank);
1100  }
1101  tmp.myConflictLanes = tmp.myFlank;
1102  tmp.myRoute = myRoute;
1103  tmp.myCoreSize = myCoreSize;
1104  MSEdgeVector occupied;
1105  if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
1106  << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
1107  return tmp.reserve(veh, occupied);
1108  }
1109 }
1110 
1111 
1112 bool
1114  for (int i = 0; i < myCoreSize; i++) {
1115  for (int j = 0; j < other.myCoreSize; j++) {
1116  const MSEdge* edge = myRoute[i];
1117  const MSEdge* edge2 = other.myRoute[j];
1118  if (edge->getToJunction() == edge2->getToJunction()
1119  || 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
1130  for (const MSLane* lane : myForward) {
1131  for (const MSLane* lane2 : other.myForward) {
1132  if (lane == lane2) {
1133  return true;
1134  }
1135  }
1136  for (const MSLane* lane2 : other.myBidi) {
1137  if (lane == lane2) {
1138  return true;
1139  }
1140  }
1141  }
1142  return false;
1143 }
1144 
1145 void
1147  od.openTag("driveWay");
1148  od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
1149  if (myCoreSize != (int)myRoute.size()) {
1150  od.writeAttr("core", myCoreSize);
1151  }
1152  od.openTag("forward");
1153  od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
1154  od.closeTag();
1155  od.openTag("bidi");
1156  od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
1157  if (myBidiExtended.size() > 0) {
1158  od.lf();
1159  od << " ";
1160  od.writeAttr("deadlockCheck", toString(myBidiExtended));
1161  }
1162  od.closeTag();
1163  od.openTag("flank");
1164  od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
1165  od.closeTag();
1166 
1167  od.openTag("protectingSwitches");
1168  std::vector<std::string> links;
1169  for (MSLink* link : myProtectingSwitches) {
1170  links.push_back(getJunctionLinkID(link));
1171  }
1172  od.writeAttr("links", joinToString(links, " "));
1173  od.closeTag();
1174 
1175  od.openTag("conflictLinks");
1176  std::vector<std::string> signals;
1177  for (MSLink* link : myConflictLinks) {
1178  signals.push_back(getTLLinkID(link));
1179  }
1180  od.writeAttr("signals", joinToString(signals, " "));
1181  od.closeTag();
1182  od.closeTag(); // driveWay
1183 }
1184 
1185 
1186 void
1188  MSRouteIterator next, MSRouteIterator end,
1189  LaneVisitedMap& visited) {
1190  bool seekForwardSignal = true;
1191  bool seekBidiSwitch = true;
1192  bool foundUnsafeSwitch = false;
1193  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  while ((seekForwardSignal || seekBidiSwitch)) {
1200  if (length > MAX_BLOCK_LENGTH) {
1202  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  myNumWarnings++;
1206  // length exceeded
1207  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  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  return;
1218  }
1219  if (toLane->getEdge().isNormal()) {
1220  myRoute.push_back(&toLane->getEdge());
1221  if (next != end) {
1222  next++;
1223  }
1224  }
1225  appendMapIndex(visited, toLane);
1226  length += toLane->getLength();
1227  MSLane* bidi = toLane->getBidiLane();
1228  if (seekForwardSignal) {
1229  if (!foundUnsafeSwitch) {
1230  myForward.push_back(toLane);
1231  }
1232  } 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  if (bidi != nullptr) {
1241  if (foundUnsafeSwitch) {
1242  myBidiExtended.push_back(bidi);
1243  } else {
1244  myBidi.push_back(bidi);
1245  }
1246  appendMapIndex(visited, bidi);
1247  if (!seekForwardSignal) {
1248  // look for switch that could protect from oncoming vehicles
1249  for (const auto& ili : bidi->getIncomingLanes()) {
1250  if (ili.viaLink->getDirection() == LinkDirection::TURN) {
1251  continue;
1252  }
1253  for (const MSLink* const link : ili.lane->getLinkCont()) {
1254  if (link->getDirection() == LinkDirection::TURN) {
1255  continue;
1256  }
1257  if (link->getViaLaneOrLane() != bidi) {
1258  // this switch is special beause it still lies on the current route
1259  //myProtectingSwitches.push_back(ili.viaLink);
1260  const MSEdge* const bidiNext = bidi->getNextNormal();
1261  myCoreSize = (int)myRoute.size();
1262  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  myProtectedBidi = bidiNext;
1271  std::set<const MSEdge*> visitedEdges;
1272  for (auto item : visited) {
1273  visitedEdges.insert(&item.first->getEdge());
1274  }
1275  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  const MSEdge* nextBidi = (*next)->getBidiEdge();
1279  if (nextBidi != nullptr) {
1280  visitedEdges.insert(nextBidi);
1281  }
1282  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  for (const auto& ili2 : bidi->getIncomingLanes()) {
1297  if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
1298  myFlankSwitches.push_back(ili.viaLink);
1299  }
1300  }
1301  }
1302  }
1303  }
1304  }
1305  }
1306  }
1307  const std::vector<MSLink*>& links = toLane->getLinkCont();
1308  const MSEdge* current = &toLane->getEdge();
1309  toLane = nullptr;
1310  for (const MSLink* const link : links) {
1311  if ((next != end && &link->getLane()->getEdge() == *next)
1312  && isRailway(link->getViaLaneOrLane()->getPermissions())) {
1313  toLane = link->getViaLaneOrLane();
1314  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  myFoundReversal = true;
1322  return;
1323  }
1324  if (link->getTLLogic() != nullptr) {
1325  if (link->getTLLogic() == origin->getTLLogic()) {
1326  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  return;
1329  }
1330  seekForwardSignal = false;
1331  myFoundSignal = true;
1332  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  if (toLane == nullptr) {
1343  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  myFoundReversal = true;
1352  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 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  const MSLink* reverseOriginLink = originLink->getLane()->getBidiLane() != nullptr && originLink->getLaneBefore()->getBidiLane() != nullptr
1372  ? originLink->getLane()->getBidiLane()->getLinkTo(originLink->getLaneBefore()->getBidiLane())
1373  : nullptr;
1374  //std::cout << " originLink=" << originLink->getDescription() << "\n";
1375  if (reverseOriginLink != nullptr) {
1376  reverseOriginLink = reverseOriginLink->getCorrespondingExitLink();
1377  //std::cout << " reverseOriginLink=" << reverseOriginLink->getDescription() << "\n";
1378  }
1379  for (int i = 0; i < (int)lanes.size(); i++) {
1380  const MSLane* lane = lanes[i];
1381  const MSLane* prev = i > 0 ? lanes[i - 1] : nullptr;
1382  const MSLane* next = i + 1 < (int)lanes.size() ? lanes[i + 1] : nullptr;
1383  if (lane->isInternal()) {
1384  continue;
1385  }
1386  for (auto ili : lane->getIncomingLanes()) {
1387  if (ili.viaLink == originLink
1388  || ili.viaLink == reverseOriginLink
1389  || ili.viaLink->getDirection() == LinkDirection::TURN
1390  || ili.viaLink->getDirection() == LinkDirection::TURN_LEFTHAND) {
1391  continue;
1392  }
1393  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  flankSwitches.push_back(ili.viaLink);
1398  } else if (allFoes) {
1399  // link is part of the driveway, find foes that cross the driveway without entering
1400  checkCrossingFlanks(ili.viaLink, visited, flankSwitches);
1401  }
1402  }
1403  }
1404 }
1405 
1406 
1407 void
1408 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  if (junction == nullptr) {
1414  return; // unregulated junction;
1415  }
1416  const MSJunctionLogic* logic = junction->getLogic();
1417  if (logic == nullptr) {
1418  return; // unregulated junction;
1419  }
1420  for (const MSEdge* in : junction->getIncoming()) {
1421  if (in->isInternal()) {
1422  continue;
1423  }
1424  for (MSLane* inLane : in->getLanes()) {
1425  if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
1426  for (MSLink* link : inLane->getLinkCont()) {
1427  if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1428  && 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  if (link->getViaLane() == nullptr) {
1433  flankSwitches.push_back(link);
1434  } else {
1435  flankSwitches.push_back(link->getViaLane()->getLinkCont().front());
1436  }
1437  }
1438  }
1439  }
1440  }
1441  }
1442 }
1443 
1444 void
1445 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  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  myConflictLinks.push_back(link);
1455  } else if (length > MAX_BLOCK_LENGTH) {
1456  // length exceeded
1458  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  myNumWarnings++;
1461  } else {
1462  // find normal lane before this link
1463  const MSLane* lane = link->getLaneBefore();
1464  const bool isNew = visited.count(lane) == 0;
1465  if (isNew || (visited[lane] > visited[origLink->getLane()] && std::find(myForward.begin(), myForward.end(), lane) == myForward.end())) {
1466  if (isNew) {
1467  appendMapIndex(visited, lane);
1468  }
1469  length += lane->getLength();
1470  if (lane->isInternal()) {
1471  flank.push_back(lane);
1472  findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink, flank);
1473  } else {
1474  bool foundPSwitch = false;
1475  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  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  myProtectingSwitches.push_back(link);
1486  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  myProtectingSwitchesBidi.push_back(link);
1491  }
1492  }
1493  }
1494  if (!foundPSwitch) {
1495  flank.push_back(lane);
1496  // continue search for protection upstream recursively
1497  for (auto ili : lane->getIncomingLanes()) {
1498  if (ili.viaLink->getDirection() != LinkDirection::TURN) {
1499  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  myMaxFlankLength = MAX2(myMaxFlankLength, length);
1511 }
1512 
1513 void
1515  myBlockingVehicles.clear();
1516  myRivalVehicles.clear();
1517  myPriorityVehicles.clear();
1518  myConstraintInfo = "";
1519  myStoreVehicles = true;
1520  LinkInfo& li = myLinkInfos[linkIndex];
1521  if (li.myLink->getApproaching().size() > 0) {
1522  Approaching closest = getClosest(li.myLink);
1523  DriveWay& driveway = li.getDriveWay(closest.first);
1524  MSEdgeVector occupied;
1525  // call for side effects
1526  driveway.reserve(closest, occupied);
1527  constraintsAllow(closest.first);
1528  } else if (li.myDriveways.size() > 0) {
1529  li.myDriveways.front().conflictLaneOccupied();
1530  li.myDriveways.front().conflictLinkApproached();
1531  }
1532  myStoreVehicles = false;
1533 }
1534 
1537  storeTraCIVehicles(linkIndex);
1538  return myBlockingVehicles;
1539 }
1540 
1543  storeTraCIVehicles(linkIndex);
1544  return myRivalVehicles;
1545 }
1546 
1549  storeTraCIVehicles(linkIndex);
1550  return myPriorityVehicles;
1551 }
1552 
1553 std::string
1555  storeTraCIVehicles(linkIndex);
1556  return myConstraintInfo;
1557 }
1558 
1560 MSRailSignal::retrieveDriveWay(int numericalID) const {
1561  for (const LinkInfo& li : myLinkInfos) {
1562  for (const DriveWay& dw : li.myDriveways) {
1563  if (dw.myNumericalID == numericalID) {
1564  return dw;
1565  }
1566  }
1567  }
1568  throw ProcessError("Invalid driveway id " + toString(numericalID) + " at railSignal '" + getID() + "'");
1569 }
1570 
1571 
1572 void
1574  for (LinkInfo& li : myLinkInfos) {
1575  for (auto it = li.myDriveways.begin(); it != li.myDriveways.end(); it++) {
1576  const DriveWay& dw = *it;
1577  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  std::vector<const MSEdge*> route = dw.myRoute;
1582  li.myDriveways.erase(it);
1583  if (li.myDriveways.size() == 0) {
1584  // rebuild default driveway
1585  li.myDriveways.push_back(li.buildDriveWay(route.begin(), route.end()));
1586  }
1587  return;
1588  }
1589  }
1590  }
1591 }
1592 
1593 std::string
1595  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1596  if (myLinkInfos.size() == 1) {
1597  return toString(rs->getBlockingVehicles(0));
1598  } else {
1599  std::string result;
1600  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1601  result += toString(i) + ": " + toString(rs->getBlockingVehicles(i)) + ";";
1602  }
1603  return result;
1604  }
1605 }
1606 std::string
1608  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1609  if (myLinkInfos.size() == 1) {
1610  return toString(rs->getRivalVehicles(0));
1611  } else {
1612  std::string result;
1613  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1614  result += toString(i) + ": " + toString(rs->getRivalVehicles(i)) + ";";
1615  }
1616  return result;
1617  }
1618 }
1619 std::string
1621  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1622  if (myLinkInfos.size() == 1) {
1623  return toString(rs->getPriorityVehicles(0));
1624  } else {
1625  std::string result;
1626  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1627  result += toString(i) + ": " + toString(rs->getPriorityVehicles(i)) + ";";
1628  }
1629  return result;
1630  }
1631 }
1632 std::string
1634  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1635  if (myLinkInfos.size() == 1) {
1636  return rs->getConstraintInfo(0);
1637  } else {
1638  std::string result;
1639  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1640  result += toString(i) + ": " + rs->getConstraintInfo(i);
1641  }
1642  return result;
1643  }
1644 }
1645 
1646 void
1647 MSRailSignal::setParameter(const std::string& key, const std::string& value) {
1648  // some pre-defined parameters can be updated at runtime
1649  if (key == "moving-block") {
1650  bool movingBlock = StringUtils::toBool(value);
1651  if (movingBlock != myMovingBlock) {
1652  // recompute driveways
1653  myMovingBlock = movingBlock;
1654  for (LinkInfo& li : myLinkInfos) {
1655  li.reset();
1656  }
1658  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1659  }
1660  }
1661  Parameterised::setParameter(key, value);
1662 }
1663 
1664 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
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 DEBUG_COND
#define MAX_BLOCK_LENGTH
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition: MSRoute.h:56
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
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.
TrafficLightType
@ 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 SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
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
bool isNormal() const
return whether this edge is an internal edge
Definition: MSEdge.h:260
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
const MSJunction * getFromJunction() const
Definition: MSEdge.h:411
double getLength() const
return the length of the edge
Definition: MSEdge.h:662
const MSJunction * getToJunction() const
Definition: MSEdge.h:415
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition: MSEdge.h:279
static bool gUseMesoSim
Definition: MSGlobals.h:103
The base class for an intersection.
Definition: MSJunction.h:58
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:108
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:133
virtual const MSJunctionLogic * getLogic() const
Definition: MSJunction.h:141
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 std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:716
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2566
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition: MSLane.cpp:2629
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition: MSLane.cpp:2351
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:942
bool isInternal() const
Definition: MSLane.cpp:2506
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:756
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:4514
bool isEmpty() const
Definition: MSLane.h:857
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:182
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
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.
virtual std::string getDescription() const
ConstraintType getType() const
virtual bool cleared() const =0
whether the constraint has been met
void addSignal(MSRailSignal *signal)
const std::set< const MSEdge * > & getUsedEdges() const
void addGreenFlankSwitch(MSLink *link, int dwID)
static MSRailSignalControl & getInstance()
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.
Definition: MSRailSignal.h:46
bool constraintsAllow(const SUMOVehicle *veh) const
whether the given vehicle is free to drive
static VehicleVector myRivalVehicles
Definition: MSRailSignal.h:491
std::string getBlockingVehicleIDs() const
Phases myPhases
The list of phases this logic uses.
Definition: MSRailSignal.h:465
std::string getConstraintInfo(int linkIndex)
return information regarding active rail signal constraints for the closest approaching vehicle
static VehicleVector myPriorityVehicles
Definition: MSRailSignal.h:492
int myPhaseIndex
MSTrafficLightLogic requires that the phase index changes whenever signals change their state.
Definition: MSRailSignal.h:471
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
Definition: MSRailSignal.h:493
MSPhaseDefinition myCurrentPhase
The current phase.
Definition: MSRailSignal.h:468
void addConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register constraint 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)
Definition: MSRailSignal.h:439
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
Definition: MSRailSignal.h:481
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
Definition: MSRailSignal.h:490
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
Definition: MSRailSignal.h:477
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
Definition: MSRailSignal.h:254
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 std::string getJunctionLinkID(MSLink *link)
return junctionID_junctionLinkIndex
static int myNumWarnings
Definition: MSRailSignal.h:479
SUMOTime trySwitch() override
Switches to the next phase.
const DriveWay & retrieveDriveWay(int numericalID) const
static bool myStoreVehicles
Definition: MSRailSignal.h:489
std::map< const MSLane *, int, ComparatorNumericalIdLess > LaneVisitedMap
Definition: MSRailSignal.h:256
bool myMovingBlock
whether the signal is in moving block mode (only protects from oncoming and flanking trains)
Definition: MSRailSignal.h:474
bool removeConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
remove constraint for signal switching
static bool hasOncomingRailTraffic(MSLink *link, const MSVehicle *ego, bool &brakeBeforeSignal)
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.
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
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
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.
Definition: OptionsCont.cpp:60
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
void lf()
writes a line feed if applicable
Definition: OutputDevice.h:242
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
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
Definition: Parameterised.h:45
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 MSDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or nullptr if not.
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:60
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles 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
Definition: json.hpp:4471
std::vector< const MSLane * > myForward
Definition: MSRailSignal.h:302
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
Definition: MSRailSignal.h:322
int myCoreSize
number of edges in myRoute where overlap with other driveways is forbidden
Definition: MSRailSignal.h:294
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
Definition: MSRailSignal.h:288
void findFlankProtection(MSLink *link, double length, LaneVisitedMap &visited, MSLink *origLink, std::vector< const MSLane * > &flank)
std::vector< MSLink * > myProtectingSwitchesBidi
subset of myProtectingSwitches that protects from oncoming trains
Definition: MSRailSignal.h:330
std::vector< const MSLane * > myConflictLanes
the lanes that must be clear of trains before this signal can switch to green
Definition: MSRailSignal.h:318
bool overlap(const DriveWay &other) const
Wether this driveway (route) overlaps with the given one.
int myNumericalID
global driveway index
Definition: MSRailSignal.h:279
std::vector< MSLink * > myConflictLinks
Definition: MSRailSignal.h:335
std::vector< const MSLane * > myBidi
Definition: MSRailSignal.h:307
std::vector< const MSLane * > myBidiExtended
Definition: MSRailSignal.h:311
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
Definition: MSRailSignal.h:315
std::vector< const MSEdge * > myRoute
list of edges for matching against train routes
Definition: MSRailSignal.h:291
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
Definition: MSRailSignal.h:328
bool myFoundSignal
whether this driveway ends its forward section with a rail signal (and thus comprises a full block)
Definition: MSRailSignal.h:297
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.