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.org/sumo
3 // Copyright (C) 2001-2022 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_BUILD_DRIVEWAY
60 //#define DEBUG_CHECK_FLANKS
61 //#define DEBUG_DRIVEWAY_BUILDROUTE
62 //#define DEBUG_DRIVEWAY_UPDATE
63 
64 #define DEBUG_SIGNALSTATE
65 #define DEBUG_SIGNALSTATE_PRIORITY
66 #define DEBUG_FIND_PROTECTION
67 //#define DEBUG_RECHECKGREEN
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() == "w2")
74 //#define DEBUG_HELPER(obj) (true)
75 
76 // ===========================================================================
77 // static value definitions
78 // ===========================================================================
80 
81 std::vector<std::pair<MSLink*, int> > MSRailSignal::mySwitchedGreenFlanks;
82 std::map<std::pair<int, int>, bool> MSRailSignal::myDriveWayCompatibility;
84 
90 
91 // ===========================================================================
92 // method definitions
93 // ===========================================================================
95  const std::string& id, const std::string& programID, SUMOTime delay,
96  const std::map<std::string, std::string>& parameters) :
97  MSTrafficLightLogic(tlcontrol, id, programID, 0, TrafficLightType::RAIL_SIGNAL, delay, parameters),
98  myCurrentPhase(DELTA_T, std::string(SUMO_MAX_CONNECTIONS, 'X')), // dummy phase
99  myPhaseIndex(0) {
101  myMovingBlock = OptionsCont::getOptions().getBool("railsignal-moving-block");
103 }
104 
105 void
107  if (myLanes.size() == 0) {
108  WRITE_WARNINGF("Rail signal at junction '%' does not control any links", getID());
109  }
110  for (LinkVector& links : myLinks) { //for every link index
111  if (links.size() != 1) {
112  throw ProcessError("At railSignal '" + getID() + "' found " + toString(links.size())
113  + " links controlled by index " + toString(links[0]->getTLIndex()));
114  }
115  myLinkInfos.push_back(LinkInfo(links[0]));
116  }
118  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
119  myNumLinks = (int)myLinks.size();
120 }
121 
122 
124  for (auto item : myConstraints) {
125  for (MSRailSignalConstraint* c : item.second) {
126  delete c;
127  }
128  }
129  myConstraints.clear();
130 }
131 
132 
133 // ----------- Handling of controlled links
134 void
138 }
139 
140 
141 // ------------ Switching and setting current rows
142 SUMOTime
145  return DELTA_T;
146 }
147 
148 
149 
150 void
152 #ifdef DEBUG_SIGNALSTATE
154 #endif
155  // green by default so vehicles can be inserted at the borders of the network
156  std::string state(myLinks.size(), 'G');
157  for (LinkInfo& li : myLinkInfos) {
158  if (li.myLink->getApproaching().size() > 0) {
159  Approaching closest = getClosest(li.myLink);
160  DriveWay& driveway = li.getDriveWay(closest.first);
161  //std::cout << SIMTIME << " signal=" << getTLLinkID(li.myLink) << " veh=" << closest.first->getID() << " dw:\n";
162  //driveway.writeBlocks(*OutputDevice_COUT::getDevice());
163  const bool mustWait = !constraintsAllow(closest.first);
164  MSEdgeVector occupied;
165  if (mustWait || !driveway.reserve(closest, occupied)) {
166  state[li.myLink->getTLIndex()] = 'r';
167  if (occupied.size() > 0) {
168  li.reroute(const_cast<SUMOVehicle*>(closest.first), occupied);
169  }
170 #ifdef DEBUG_SIGNALSTATE
171  if (gDebugFlag4) {
172  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " notReserved\n";
173  }
174 #endif
175  } else {
176  state[li.myLink->getTLIndex()] = 'G';
177  if (driveway.myFlank.size() > 0 && myCurrentPhase.getState()[li.myLink->getTLIndex()] != 'G') {
178  // schedule recheck
179  mySwitchedGreenFlanks.push_back(std::make_pair(li.myLink, driveway.myNumericalID));
180  }
181 #ifdef DEBUG_SIGNALSTATE
182  if (gDebugFlag4) {
183  std::cout << SIMTIME << " rsl=" << li.getID() << " veh=" << closest.first->getID() << " reserved\n";
184  }
185 #endif
186  }
187  } else {
188  DriveWay& driveway = li.myDriveways.front();
189  if (driveway.conflictLaneOccupied() || driveway.conflictLinkApproached()) {
190 #ifdef DEBUG_SIGNALSTATE
191  if (gDebugFlag4) {
192  std::cout << SIMTIME << " rsl=" << li.getID() << " red for default driveway (" << toString(driveway.myRoute) << " conflictLinkApproached=" << driveway.conflictLinkApproached() << "\n";
193  }
194 #endif
195  state[li.myLink->getTLIndex()] = 'r';
196  } else {
197 #ifdef DEBUG_SIGNALSTATE
198  if (gDebugFlag4) {
199  std::cout << SIMTIME << " rsl=" << li.getID() << " green for default driveway (" << toString(driveway.myRoute) << ")\n";
200  }
201 #endif
202  }
203  }
204  }
205  if (myCurrentPhase.getState() != state) {
206  myCurrentPhase.setState(state);
208  }
209 #ifdef DEBUG_SIGNALSTATE
210  gDebugFlag4 = false;
211 #endif
212 }
213 
214 
215 bool
217  if (myConstraints.size() == 0) {
218  return true;
219  } else {
220  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
221  auto it = myConstraints.find(tripID);
222  if (it != myConstraints.end()) {
223  for (MSRailSignalConstraint* c : it->second) {
224  if (!c->cleared()) {
225 #ifdef DEBUG_SIGNALSTATE
226  if (gDebugFlag4) {
227  std::cout << " constraint '" << c->getDescription() << "' not cleared\n";
228  }
229 #endif
230  if (myStoreVehicles) {
232  }
233  return false;
234  }
235  }
236  }
237  return true;
238  }
239 }
240 
241 
242 void
243 MSRailSignal::addConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
244  myConstraints[tripId].push_back(constraint);
245 }
246 
247 
248 bool
249 MSRailSignal::removeConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
250  if (myConstraints.count(tripId) != 0) {
251  auto& constraints = myConstraints[tripId];
252  auto it = std::find(constraints.begin(), constraints.end(), constraint);
253  if (it != constraints.end()) {
254  delete *it;
255  constraints.erase(it);
256  return true;
257  }
258  }
259  if (myInsertionConstraints.count(tripId) != 0) {
260  auto& constraints = myInsertionConstraints[tripId];
261  auto it = std::find(constraints.begin(), constraints.end(), constraint);
262  if (it != constraints.end()) {
263  delete *it;
264  constraints.erase(it);
265  return true;
266  }
267  }
268  return false;
269 }
270 
271 void
273  for (auto item : myConstraints) {
274  for (MSRailSignalConstraint* c : item.second) {
275  delete c;
276  }
277  }
278  myConstraints.clear();
279  for (auto item : myInsertionConstraints) {
280  for (MSRailSignalConstraint* c : item.second) {
281  delete c;
282  }
283  }
284  myInsertionConstraints.clear();
285 }
286 
287 void
288 MSRailSignal::addInsertionConstraint(const std::string& tripId, MSRailSignalConstraint* constraint) {
289  myInsertionConstraints[tripId].push_back(constraint);
290 }
291 
292 // ------------ Static Information Retrieval
293 int
295  return 0;
296 }
297 
300  return myPhases;
301 }
302 
303 const MSPhaseDefinition&
305  return myCurrentPhase;
306 }
307 
308 // ------------ Dynamic Information Retrieval
309 int
311  return myPhaseIndex;
312 }
313 
314 const MSPhaseDefinition&
316  return myCurrentPhase;
317 }
318 
319 // ------------ Conversion between time and phase
320 SUMOTime
322  return 0;
323 }
324 
325 SUMOTime
327  return 0;
328 }
329 
330 int
332  return 0;
333 }
334 
335 
336 void
337 MSRailSignal::addLink(MSLink* link, MSLane* lane, int pos) {
338  if (pos >= 0) {
339  MSTrafficLightLogic::addLink(link, lane, pos);
340  } // ignore uncontrolled link
341 }
342 
343 
344 std::string
346  return link->getTLLogic()->getID() + "_" + toString(link->getTLIndex());
347 }
348 
349 std::string
351  return link->getJunction()->getID() + "_" + toString(link->getIndex());
352 }
353 
354 std::string
356  return "junction '" + link->getTLLogic()->getID() + "', link " + toString(link->getTLIndex());
357 }
358 
359 std::string
360 MSRailSignal::describeLinks(std::vector<MSLink*> links) {
361  std::string result;
362  for (MSLink* link : links) {
363  result += link->getDescription() + " ";
364  }
365  return result;
366 }
367 
368 std::string
370  std::vector<const MSLane*> lanes(visited.size(), nullptr);
371  for (auto item : visited) {
372  lanes[item.second] = item.first;
373  }
374  return toString(lanes);
375 }
376 
379  assert(link->getApproaching().size() > 0);
380  double minDist = std::numeric_limits<double>::max();
381  auto closestIt = link->getApproaching().begin();
382  for (auto apprIt = link->getApproaching().begin(); apprIt != link->getApproaching().end(); apprIt++) {
383  if (apprIt->second.dist < minDist) {
384  minDist = apprIt->second.dist;
385  closestIt = apprIt;
386  }
387  }
388  // maybe a parallel link has a closer vehicle
389  /*
390  for (MSLink* link2 : link->getLaneBefore()->getLinkCont()) {
391  if (link2 != link) {
392  for (auto apprIt2 = link2->getApproaching().begin(); apprIt2 != link2->getApproaching().end(); apprIt2++) {
393  if (apprIt2->second.dist < minDist) {
394  minDist = apprIt2->second.dist;
395  closestIt = apprIt2;
396  }
397  }
398  }
399  }
400  */
401  return *closestIt;
402 }
403 
404 void
406  od.openTag("railSignal");
408  for (const LinkInfo& li : myLinkInfos) {
409  MSLink* link = li.myLink;
410  od.openTag("link");
414  for (const DriveWay& dw : li.myDriveways) {
415  dw.writeBlocks(od);
416  }
417  od.closeTag(); // link
418  }
419  od.closeTag(); // railSignal
420 }
421 
422 
423 bool
426  const MSEdge* bidi = link->getLaneBefore()->getEdge().getBidiEdge();
427  if (bidi == nullptr) {
428  return false;
429  }
430  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
431  if (rs != nullptr) {
432  const LinkInfo& li = rs->myLinkInfos[link->getTLIndex()];
433  for (const DriveWay& dw : li.myDriveways) {
434  //std::cout << SIMTIME <<< " hasOncomingRailTraffic link=" << getTLLinkID(link) << " dwRoute=" << toString(dw.myRoute) << " bidi=" << toString(dw.myBidi) << "\n";
435  for (MSLane* lane : dw.myBidi) {
436  if (!lane->isEmpty()) {
437 #ifdef DEBUG_SIGNALSTATE
438  if (DEBUG_HELPER(rs)) {
439  std::cout << " oncoming vehicle on bidi-lane " << lane->getID() << "\n";
440  };
441 #endif
442  return true;
443  }
444  }
445  for (const MSLane* lane : dw.myFlank) {
446  if (!lane->isEmpty()) {
447  MSVehicle* veh = lane->getFirstAnyVehicle();
448  if (std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
449 #ifdef DEBUG_SIGNALSTATE
450  if (DEBUG_HELPER(rs)) {
451  std::cout << " oncoming vehicle on flank-lane " << lane->getID() << "\n";
452  };
453 #endif
454  return true;
455  }
456  }
457  }
458  for (MSLink* foeLink : dw.myConflictLinks) {
459  if (foeLink->getApproaching().size() != 0) {
460  Approaching closest = getClosest(foeLink);
461  const SUMOVehicle* veh = closest.first;
462  if (veh->getSpeed() > 0 && closest.second.arrivalSpeedBraking > 0
463  && std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), bidi) != veh->getRoute().end()) {
464 #ifdef DEBUG_SIGNALSTATE
465  if (DEBUG_HELPER(rs)) {
466  std::cout << " oncoming vehicle approaching foe link " << foeLink->getDescription() << "\n";
467  }
468 #endif
469  return true;
470  }
471  }
472  }
473  }
474  }
475  }
476  return false;
477 }
478 
479 bool
480 MSRailSignal::hasInsertionConstraint(MSLink* link, const MSVehicle* veh, std::string& info) {
481  if (link->getJunction() != nullptr && link->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
482  const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
483  if (rs != nullptr && rs->myInsertionConstraints.size() > 0) {
484  const std::string tripID = veh->getParameter().getParameter("tripId", veh->getID());
485  auto it = rs->myInsertionConstraints.find(tripID);
486  if (it != rs->myInsertionConstraints.end()) {
487  for (MSRailSignalConstraint* c : it->second) {
488  if (!c->cleared()) {
489 #ifdef DEBUG_SIGNALSTATE
490  if (DEBUG_HELPER(rs)) {
491  std::cout << SIMTIME << " rsl=" << rs->getID() << " insertion constraint '" << c->getDescription() << "' for vehicle '" << veh->getID() << "' not cleared\n";
492  }
493 #endif
494  info = c->getDescription();
495  return true;
496  }
497  }
498  }
499  }
500  }
501  return false;
502 }
503 
504 // ===========================================================================
505 // LinkInfo method definitions
506 // ===========================================================================
507 
509  myLink(link) {
510  reset();
511 }
512 
513 
514 void
516  myUniqueDriveWay = false;
517  myLastRerouteTime = -1;
518  myLastRerouteVehicle = nullptr;
519  myDriveways.clear();
520  ConstMSEdgeVector dummyRoute;
521  dummyRoute.push_back(&myLink->getLane()->getEdge());
522  DriveWay dw = buildDriveWay(dummyRoute.begin(), dummyRoute.end());
523  myDriveways.push_back(dw);
524 }
525 
526 
527 std::string
529  return myLink->getTLLogic()->getID() + "_" + toString(myLink->getTLIndex());
530 }
531 
532 
535  if (myUniqueDriveWay) {
536  return myDriveways.front();
537  }
538  MSEdge* first = &myLink->getLane()->getEdge();
539  MSRouteIterator firstIt = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), first);
540  if (firstIt == veh->getRoute().end()) {
541  // possibly the vehicle has already gone past the first edge (i.e.
542  // because first is short or the step-length is high)
543  // lets look backward along the route
544  // give some slack because the vehicle might have been braking from a higher speed and using ballistic integration
545  double lookBack = SPEED2DIST(veh->getSpeed() + 10);
546  int routeIndex = veh->getRoutePosition() - 1;
547  while (lookBack > 0 && routeIndex > 0) {
548  const MSEdge* prevEdge = veh->getRoute().getEdges()[routeIndex];
549  if (prevEdge == first) {
550  firstIt = veh->getRoute().begin() + routeIndex;
551  break;
552  }
553  lookBack -= prevEdge->getLength();
554  routeIndex--;
555  }
556  }
557  if (firstIt == veh->getRoute().end()) {
558  WRITE_WARNING("Invalid approach information to rail signal '" + getClickableTLLinkID(myLink) + "' after rerouting for vehicle '" + veh->getID()
559  + "' first driveway edge '" + first->getID() + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
560  return myDriveways.front();
561  }
562  //std::cout << SIMTIME << " veh=" << veh->getID() << " rsl=" << getID() << " dws=" << myDriveways.size() << "\n";
563  for (DriveWay& dw : myDriveways) {
564  // @todo optimize: it is sufficient to check for specific edges (after each switch)
565  auto itRoute = firstIt;
566  auto itDwRoute = dw.myRoute.begin();
567  bool match = true;
568  while (itRoute != veh->getRoute().end() && itDwRoute != dw.myRoute.end()) {
569  if (*itRoute != *itDwRoute) {
570  match = false;
571  //std::cout << " check dw=" << " match failed at vehEdge=" << (*itRoute)->getID() << " dwEdge=" << (*itDwRoute)->getID() << "\n";
572  break;
573  }
574  itRoute++;
575  itDwRoute++;
576  }
577  if (match) {
578  //std::cout << " using dw=" << "\n";
579  return dw;
580  }
581  }
582  DriveWay dw = buildDriveWay(firstIt, veh->getRoute().end());
583  myDriveways.push_back(dw);
584  return myDriveways.back();
585 }
586 
587 
590  // collect lanes and links that are relevant for setting this signal for the current driveWay
591  // For each driveway we collect
592  // - conflictLanes (signal must be red if any conflict lane is occupied)
593  // - conflictLinks (signal must be red if any conflict link is approached by a vehicle
594  // - that cannot break in time (arrivalSpeedBraking > 0)
595  // - approached by a vehicle with higher switching priority (see #3941)
596  // These objects are construct in steps:
597  //
598  // forwardBlock
599  // - search forward recursive from outgoing lane until controlled railSignal link found
600  // -> add all found lanes to conflictLanes
601  //
602  // bidiBlock (if any forwardBlock edge has bidi edge)
603  // - search bidi backward recursive until first switch
604  // - from switch search backward recursive all other incoming until controlled rail signal link
605  // -> add final links to conflictLinks
606  //
607  // flanks
608  // - search backward recursive from flanking switches
609  // until controlled railSignal link or protecting switch is found
610  // -> add all found lanes to conflictLanes
611  // -> add final links to conflictLinks
612 
613  DriveWay dw;
614  LaneVisitedMap visited;
615  std::vector<MSLane*> before;
616  visited[myLink->getLaneBefore()] = (int)visited.size();
617  MSLane* fromBidi = myLink->getLaneBefore()->getBidiLane();
618  if (fromBidi != nullptr) {
619  // do not extend to forward block beyond the entering track (in case of a loop)
620  visited[fromBidi] = (int)visited.size();
621  before.push_back(fromBidi);
622  }
623  dw.buildRoute(myLink, 0., first, end, visited);
624  if (dw.myProtectedBidi == nullptr) {
625  dw.myCoreSize = (int)dw.myRoute.size();
626  }
627  dw.checkFlanks(dw.myForward, visited, true);
628  dw.checkFlanks(dw.myBidi, visited, false);
629  dw.checkFlanks(before, visited, true);
630 
631  for (MSLink* link : dw.myFlankSwitches) {
632  //std::cout << getID() << " flankSwitch=" << link->getDescription() << "\n";
633  dw.findFlankProtection(link, 0, visited, link);
634  }
635 
636 #ifdef DEBUG_BUILD_DRIVEWAY
637  if (DEBUG_COND_LINKINFO || true) {
638  std::cout << " buildDriveWay railSignal=" << getID()
639  << "\n route=" << toString(dw.myRoute)
640  << "\n forward=" << toString(dw.myForward)
641  << "\n bidi=" << toString(dw.myBidi)
642  << "\n flank=" << toString(dw.myFlank)
643  << "\n flankSwitch=" << describeLinks(dw.myFlankSwitches)
644  << "\n protSwitch=" << describeLinks(dw.myProtectingSwitches)
645  << "\n coreSize=" << dw.myCoreSize
646  << "\n";
647  }
648 #endif
649  MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(myLink->getTLLogic()));
650  if (!rs->myMovingBlock) {
651  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myForward.begin(), dw.myForward.end());
652  }
653  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myBidi.begin(), dw.myBidi.end());
654  dw.myConflictLanes.insert(dw.myConflictLanes.end(), dw.myFlank.begin(), dw.myFlank.end());
655  if (dw.myProtectedBidi != nullptr) {
657  }
658 
659  return dw;
660 }
661 
662 
663 void
665  MSDevice_Routing* rDev = static_cast<MSDevice_Routing*>(veh->getDevice(typeid(MSDevice_Routing)));
667  if (rDev != nullptr
668  && rDev->mayRerouteRailSignal()
669  && (myLastRerouteVehicle != veh
670  // reroute each vehicle only once if no periodic routing is allowed,
671  // otherwise with the specified period
672  || (rDev->getPeriod() > 0 && myLastRerouteTime + rDev->getPeriod() <= now))) {
673  myLastRerouteVehicle = veh;
674  myLastRerouteTime = now;
675 
676 #ifdef DEBUG_REROUTE
677  ConstMSEdgeVector oldRoute = veh->getRoute().getEdges();
678  if (DEBUG_COND_LINKINFO) {
679  std::cout << SIMTIME << " reroute veh=" << veh->getID() << " rs=" << getID() << " occupied=" << toString(occupied) << "\n";
680  }
681 #endif
682  MSRoutingEngine::reroute(*veh, now, "railSignal:" + getID(), false, true, occupied);
683 #ifdef DEBUG_REROUTE
684  // attention this works only if we are not parallel!
685  if (DEBUG_COND_LINKINFO) {
686  if (veh->getRoute().getEdges() != oldRoute) {
687  std::cout << " rerouting successful\n";
688  }
689  }
690 #endif
691  }
692 }
693 
694 
695 // ===========================================================================
696 // DriveWay method definitions
697 // ===========================================================================
698 
699 bool
701  std::string joinVehicle = "";
702  if (!MSGlobals::gUseMesoSim) {
703  const SUMOVehicleParameter::Stop* stop = closest.first->getNextStopParameter();
704  if (stop != nullptr) {
705  joinVehicle = stop->join;
706  }
707  }
708  if (conflictLaneOccupied(joinVehicle)) {
709  for (MSLane* bidi : myBidi) {
710  if (!bidi->empty() && bidi->getBidiLane() != nullptr) {
711  occupied.push_back(&bidi->getBidiLane()->getEdge());
712  }
713  }
714 #ifdef DEBUG_SIGNALSTATE
715  if (gDebugFlag4) {
716  std::cout << " conflictLaneOccupied\n";
717  }
718 #endif
719  return false;
720  }
721  for (MSLink* link : myProtectingSwitches) {
722  if (!findProtection(closest, link)) {
723 #ifdef DEBUG_SIGNALSTATE
724  if (gDebugFlag4) {
725  std::cout << " no protection at switch " << link->getDescription() << "\n";
726  }
727 #endif
728  return false;
729  }
730  }
731  for (MSLink* foeLink : myConflictLinks) {
732  if (hasLinkConflict(closest, foeLink)) {
733 #ifdef DEBUG_SIGNALSTATE
734  if (gDebugFlag4) {
735  std::cout << " linkConflict with " << getTLLinkID(foeLink) << "\n";
736  }
737 #endif
738  return false;
739  }
740  }
741  if (deadlockLaneOccupied()) {
742  return false;
743  }
744  myActive = closest.first;
745  return true;
746 }
747 
748 
749 bool
751  for (MSLink* foeLink : myConflictLinks) {
752  if (foeLink->getApproaching().size() > 0) {
753  return true;
754  }
755  }
756  return false;
757 }
758 
759 
760 bool
762 #ifdef DEBUG_SIGNALSTATE_PRIORITY
763  if (gDebugFlag4) {
764  std::cout << " checkLinkConflict foeLink=" << getTLLinkID(foeLink) << "\n";
765  }
766 #endif
767  if (foeLink->getApproaching().size() > 0) {
768  Approaching foe = getClosest(foeLink);
769 #ifdef DEBUG_SIGNALSTATE_PRIORITY
770  if (gDebugFlag4) {
771  std::cout << " approaching foe=" << foe.first->getID() << "\n";
772  }
773 #endif
774  const MSTrafficLightLogic* foeTLL = foeLink->getTLLogic();
775  assert(foeTLL != nullptr);
776  const MSRailSignal* constFoeRS = dynamic_cast<const MSRailSignal*>(foeTLL);
777  MSRailSignal* foeRS = const_cast<MSRailSignal*>(constFoeRS);
778  if (foeRS != nullptr) {
779  const DriveWay& foeDriveWay = foeRS->myLinkInfos[foeLink->getTLIndex()].getDriveWay(foe.first);
780  if (foeDriveWay.conflictLaneOccupied("", false) ||
781  foeDriveWay.deadlockLaneOccupied(false) ||
782  !foeRS->constraintsAllow(foe.first) ||
783  !overlap(foeDriveWay)) {
784 #ifdef DEBUG_SIGNALSTATE_PRIORITY
785  if (gDebugFlag4) {
786  if (foeDriveWay.conflictLaneOccupied("", false)) {
787  std::cout << " foe blocked\n";
788  } else if (!foeRS->constraintsAllow(foe.first)) {
789  std::cout << " foe constrained\n";
790  } else {
791  std::cout << " no overlap\n";
792  }
793  }
794 #endif
795  return false;
796  }
797 #ifdef DEBUG_SIGNALSTATE_PRIORITY
798  if (gDebugFlag4) {
799  std::cout
800  << " aSB=" << veh.second.arrivalSpeedBraking << " foeASB=" << foe.second.arrivalSpeedBraking
801  << " aT=" << veh.second.arrivalTime << " foeAT=" << foe.second.arrivalTime
802  << " aS=" << veh.first->getSpeed() << " foeS=" << foe.first->getSpeed()
803  << " aD=" << veh.second.dist << " foeD=" << foe.second.dist
804  << " aW=" << veh.first->getWaitingTime() << " foeW=" << foe.first->getWaitingTime()
805  << " aN=" << veh.first->getNumericalID() << " foeN=" << foe.first->getNumericalID()
806  << "\n";
807  }
808 #endif
809  const bool yield = mustYield(veh, foe);
810  if (myStoreVehicles) {
811  myRivalVehicles.push_back(foe.first);
812  if (yield) {
813  myPriorityVehicles.push_back(foe.first);
814  }
815  }
816  return yield;
817  }
818  }
819  return false;
820 }
821 
822 
823 bool
825  if (foe.second.arrivalSpeedBraking == veh.second.arrivalSpeedBraking) {
826  if (foe.second.arrivalTime == veh.second.arrivalTime) {
827  if (foe.first->getSpeed() == veh.first->getSpeed()) {
828  if (foe.second.dist == veh.second.dist) {
829  if (foe.first->getWaitingTime() == veh.first->getWaitingTime()) {
830  return foe.first->getNumericalID() < veh.first->getNumericalID();
831  } else {
832  return foe.first->getWaitingTime() > veh.first->getWaitingTime();
833  }
834  } else {
835  return foe.second.dist < veh.second.dist;
836  }
837  } else {
838  return foe.first->getSpeed() > veh.first->getSpeed();
839  }
840  } else {
841  return foe.second.arrivalTime < veh.second.arrivalTime;
842  }
843  } else {
844  return foe.second.arrivalSpeedBraking > veh.second.arrivalSpeedBraking;
845  }
846 }
847 
848 
849 bool
850 MSRailSignal::DriveWay::conflictLaneOccupied(const std::string& joinVehicle, bool store) const {
851  for (const MSLane* lane : myConflictLanes) {
852  if (!lane->isEmpty()) {
853 #ifdef DEBUG_SIGNALSTATE
854  if (gDebugFlag4) {
855  std::cout << SIMTIME << " conflictLane " << lane->getID() << " occupied\n";
856  if (joinVehicle != "") {
857  std::cout << " joinVehicle=" << joinVehicle << " occupant=" << toString(lane->getVehiclesSecure()) << "\n";
858  lane->releaseVehicles();
859  }
860  }
861 #endif
862  if (lane->getVehicleNumber() == 1 && joinVehicle != "") {
863  std::vector<MSVehicle*> vehs = lane->getVehiclesSecure();
864  const bool ignoreJoinTarget = vehs.front()->getID() == joinVehicle && vehs.front()->isStopped();
865  lane->releaseVehicles();
866  if (ignoreJoinTarget) {
867 #ifdef DEBUG_SIGNALSTATE
868  if (gDebugFlag4) {
869  std::cout << " ignore join-target '" << joinVehicle << ";\n";
870  }
871 #endif
872  continue;
873  }
874  }
875  if (myStoreVehicles && store) {
876  myBlockingVehicles.push_back(lane->getLastAnyVehicle());
877  }
878  return true;
879  }
880  }
881  return false;
882 }
883 
884 bool
886  for (MSLane* lane : myBidiExtended) {
887  if (!lane->empty()) {
888  assert(myBidi.size() != 0);
889  const MSEdge* lastBidi = myBidi.back()->getNextNormal();
890  MSVehicle* foe = lane->getVehiclesSecure().front();
891 #ifdef DEBUG_SIGNALSTATE
892  if (gDebugFlag4) {
893  std::cout << " check for deadlock with " << foe->getID() << "\n";
894  }
895 #endif
896  // check of foe will enter myBidi (need to check at most
897  // myBidiExtended.size edges)
898  const int minEdges = (int)myBidiExtended.size();
899  auto foeIt = foe->getCurrentRouteEdge() + 1;
900  auto foeEnd = foe->getRoute().end();
901  bool conflict = false;
902  for (int i = 0; i < minEdges && foeIt != foeEnd; i++) {
903  if ((*foeIt) == lastBidi) {
904 #ifdef DEBUG_SIGNALSTATE
905  if (gDebugFlag4) {
906  std::cout << " vehicle will enter " << lastBidi->getID() << "\n";
907  }
908 #endif
909  conflict = true;
910  break;
911  }
912  foeIt++;
913  }
914  lane->releaseVehicles();
915  if (conflict) {
916  if (myStoreVehicles && store) {
917  myBlockingVehicles.push_back(foe);
918  }
919  return true;
920  }
921  }
922  }
923  return false;
924 }
925 
926 
927 bool
929  double flankApproachingDist = std::numeric_limits<double>::max();
930  if (link->getApproaching().size() > 0) {
931  Approaching closest = getClosest(link);
932  flankApproachingDist = closest.second.dist;
933  }
934 #ifdef DEBUG_FIND_PROTECTION
935  if (gDebugFlag4) {
936  std::cout << SIMTIME << " findProtection for link=" << link->getDescription() << " flankApproachingDist=" << flankApproachingDist << "\n";
937  }
938 #endif
939  for (MSLink* l2 : link->getLaneBefore()->getLinkCont()) {
940  if (l2->getLane() != link->getLane()) {
941 #ifdef DEBUG_FIND_PROTECTION
942  if (gDebugFlag4) {
943  std::cout << " protectionCandidate=" << l2->getDescription() << " l2Via=" << Named::getIDSecure(l2->getViaLane())
944  << " occupied=" << (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) << "\n";
945  }
946 #endif
947  if (l2->getViaLane() != nullptr && !l2->getViaLane()->isEmpty()) {
948 #ifdef DEBUG_FIND_PROTECTION
949  if (gDebugFlag4) {
950  std::cout << " protection from internal=" << l2->getViaLane()->getID() << "\n";
951  }
952 #endif
953  return true;
954  }
955  if (l2->getApproaching().size() > 0) {
956  Approaching closest2 = getClosest(l2);
957  if (closest2.second.dist < flankApproachingDist) {
958 #ifdef DEBUG_FIND_PROTECTION
959  if (gDebugFlag4) {
960  std::cout << " protection from veh=" << closest2.first->getID() << "\n";
961  }
962 #endif
963  return true;
964  }
965  }
966  }
967  }
968  if (link->getApproaching().size() == 0) {
969  return true;
970  } else {
971  // find protection further upstream
972  DriveWay tmp(true);
973  const MSLane* before = link->getLaneBefore();
974  tmp.myFlank.push_back(before);
975  LaneVisitedMap visited;
976  for (auto ili : before->getIncomingLanes()) {
977  tmp.findFlankProtection(ili.viaLink, myMaxFlankLength, visited, ili.viaLink);
978  }
979  tmp.myConflictLanes = tmp.myFlank;
980  tmp.myRoute = myRoute;
981  tmp.myCoreSize = myCoreSize;
982  MSEdgeVector occupied;
983  if (gDebugFlag4) std::cout << SIMTIME << " tmpDW flank=" << toString(tmp.myFlank)
984  << " protSwitch=" << describeLinks(tmp.myProtectingSwitches) << " cLinks=" << describeLinks(tmp.myConflictLinks) << "\n";
985  return tmp.reserve(veh, occupied);
986  }
987 }
988 
989 
990 bool
992  for (int i = 0; i < myCoreSize; i++) {
993  for (int j = 0; j < other.myCoreSize; j++) {
994  const MSEdge* edge = myRoute[i];
995  const MSEdge* edge2 = other.myRoute[j];
996  if (edge->getToJunction() == edge2->getToJunction()
997  || edge->getToJunction() == edge2->getFromJunction()) {
998  // XXX might be rail_crossing with parallel tracks
999  return true;
1000  }
1001  }
1002  }
1003  return false;
1004 }
1005 
1006 bool
1008  for (const MSLane* lane : myForward) {
1009  for (const MSLane* lane2 : other.myForward) {
1010  if (lane == lane2) {
1011  return true;
1012  }
1013  }
1014  for (const MSLane* lane2 : other.myBidi) {
1015  if (lane == lane2) {
1016  return true;
1017  }
1018  }
1019  }
1020  return false;
1021 }
1022 
1023 void
1025  od.openTag("driveWay");
1026  od.writeAttr(SUMO_ATTR_EDGES, toString(myRoute));
1027  if (myCoreSize != (int)myRoute.size()) {
1028  od.writeAttr("core", myCoreSize);
1029  }
1030  od.openTag("forward");
1031  od.writeAttr(SUMO_ATTR_LANES, toString(myForward));
1032  od.closeTag();
1033  od.openTag("bidi");
1034  od.writeAttr(SUMO_ATTR_LANES, toString(myBidi));
1035  if (myBidiExtended.size() > 0) {
1036  od.lf();
1037  od << " ";
1038  od.writeAttr("deadlockCheck", toString(myBidiExtended));
1039  }
1040  od.closeTag();
1041  od.openTag("flank");
1042  od.writeAttr(SUMO_ATTR_LANES, toString(myFlank));
1043  od.closeTag();
1044 
1045  od.openTag("protectingSwitches");
1046  std::vector<std::string> links;
1047  for (MSLink* link : myProtectingSwitches) {
1048  links.push_back(getJunctionLinkID(link));
1049  }
1050  od.writeAttr("links", joinToString(links, " "));
1051  od.closeTag();
1052 
1053  od.openTag("conflictLinks");
1054  std::vector<std::string> signals;
1055  for (MSLink* link : myConflictLinks) {
1056  signals.push_back(getTLLinkID(link));
1057  }
1058  od.writeAttr("signals", joinToString(signals, " "));
1059  od.closeTag();
1060  od.closeTag(); // driveWay
1061 }
1062 
1063 
1064 void
1066  MSRouteIterator next, MSRouteIterator end,
1067  LaneVisitedMap& visited) {
1068  bool seekForwardSignal = true;
1069  bool seekBidiSwitch = true;
1070  bool foundUnsafeSwitch = false;
1071  MSLane* toLane = origin->getViaLaneOrLane();
1072 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1073  gDebugFlag4 = true; //getClickableTLLinkID(origin) == "junction 's24', link 0";
1074  if (gDebugFlag4) std::cout << "buildRoute origin=" << getTLLinkID(origin) << " vehRoute=" << toString(ConstMSEdgeVector(next, end))
1075  << " visited=" << formatVisitedMap(visited) << "\n";
1076 #endif
1077  while ((seekForwardSignal || seekBidiSwitch)) {
1078  if (length > MAX_BLOCK_LENGTH) {
1080  WRITE_WARNING("Block after rail signal " + getClickableTLLinkID(origin) +
1081  " exceeds maximum length (stopped searching after edge '" + toLane->getEdge().getID() + "' (length=" + toString(length) + "m).");
1082  }
1083  myNumWarnings++;
1084  // length exceeded
1085  return;
1086  }
1087 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1088  if (gDebugFlag4) {
1089  std::cout << " toLane=" << toLane->getID() << " visited=" << formatVisitedMap(visited) << "\n";
1090  }
1091 #endif
1092  if (visited.count(toLane) != 0) {
1093  WRITE_WARNING("Found circular block after railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
1094  //std::cout << getClickableTLLinkID(origin) << " circularBlock1=" << toString(myRoute) << " visited=" << formatVisitedMap(visited) << "\n";
1095  return;
1096  }
1097  if (toLane->getEdge().isNormal()) {
1098  myRoute.push_back(&toLane->getEdge());
1099  if (next != end) {
1100  next++;
1101  }
1102  }
1103  visited[toLane] = (int)visited.size();
1104  length += toLane->getLength();
1105  MSLane* bidi = toLane->getBidiLane();
1106  if (seekForwardSignal) {
1107  if (!foundUnsafeSwitch) {
1108  myForward.push_back(toLane);
1109  }
1110  } else if (bidi == nullptr) {
1111  seekBidiSwitch = false;
1112 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1113  if (gDebugFlag4) {
1114  std::cout << " noBidi, abort search for bidiSwitch\n";
1115  }
1116 #endif
1117  }
1118  if (bidi != nullptr) {
1119  if (foundUnsafeSwitch) {
1120  myBidiExtended.push_back(bidi);
1121  } else {
1122  myBidi.push_back(bidi);
1123  }
1124  visited[bidi] = (int)visited.size();
1125  if (!seekForwardSignal) {
1126  // look for switch that could protect from oncoming vehicles
1127  for (const auto& ili : bidi->getIncomingLanes()) {
1128  if (ili.viaLink->getDirection() == LinkDirection::TURN) {
1129  continue;
1130  }
1131  for (const MSLink* const link : ili.lane->getLinkCont()) {
1132  if (link->getDirection() == LinkDirection::TURN) {
1133  continue;
1134  }
1135  if (link->getViaLaneOrLane() != bidi) {
1136  // this switch is special beause it still lies on the current route
1137  //myProtectingSwitches.push_back(ili.viaLink);
1138  const MSEdge* const bidiNext = bidi->getNextNormal();
1139  myCoreSize = (int)myRoute.size();
1140  if (MSRailSignalControl::getInstance().getUsedEdges().count(bidiNext) == 0) {
1141 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1142  if (gDebugFlag4) {
1143  std::cout << " abort: found protecting switch " << ili.viaLink->getDescription() << "\n";
1144  }
1145 #endif
1146  // if bidi is actually used by a train (rather than
1147  // the other route) we must later adapt this driveway for additional checks (myBidiExtended)
1148  myProtectedBidi = bidiNext;
1149  return;
1150  } else {
1151 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1152  if (gDebugFlag4) {
1153  std::cout << " found unsafe switch " << ili.viaLink->getDescription() << " (used=" << bidiNext->getID() << ")\n";
1154  }
1155 #endif
1156  // trains along our route beyond this switch
1157  // might create deadlock
1158  foundUnsafeSwitch = true;
1159  // the switch itself must still be guarded to ensure safety
1160  for (const auto& ili2 : bidi->getIncomingLanes()) {
1161  if (ili2.viaLink->getDirection() != LinkDirection::TURN) {
1162  myFlankSwitches.push_back(ili.viaLink);
1163  }
1164  }
1165  }
1166  }
1167  }
1168  }
1169  }
1170  }
1171  const std::vector<MSLink*>& links = toLane->getLinkCont();
1172  const MSEdge* current = &toLane->getEdge();
1173  toLane = nullptr;
1174  for (const MSLink* const link : links) {
1175  if (((next != end && &link->getLane()->getEdge() == *next) ||
1176  (next == end && link->getDirection() != LinkDirection::TURN))
1177  && isRailway(link->getViaLaneOrLane()->getPermissions())) {
1178  toLane = link->getViaLaneOrLane();
1179  if (link->getLane()->getBidiLane() != nullptr && &link->getLane()->getEdge() == current->getBidiEdge()) {
1180  // do not follow turn-arounds even if the route contains a reversal
1181 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1182  if (gDebugFlag4) {
1183  std::cout << " abort: turn-around\n";
1184  }
1185 #endif
1186  return;
1187  }
1188  if (link->getTLLogic() != nullptr) {
1189  if (link->getTLLogic() == origin->getTLLogic()) {
1190  WRITE_WARNING("Found circular block at railSignal " + getClickableTLLinkID(origin) + " (" + toString(myRoute.size()) + " edges, length " + toString(length) + ")");
1191  //std::cout << getClickableTLLinkID(origin) << " circularBlock2=" << toString(myRoute) << "\n";
1192  return;
1193  }
1194  seekForwardSignal = false;
1195  seekBidiSwitch = bidi != nullptr;
1196 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1197  if (gDebugFlag4) {
1198  std::cout << " found forwardSignal " << link->getTLLogic()->getID() << " seekBidiSwitch=" << seekBidiSwitch << "\n";
1199  }
1200 #endif
1201  }
1202  break;
1203  }
1204  }
1205  if (toLane == nullptr) {
1206  if (next != end) {
1207  // no connection found, jump to next route edge
1208  toLane = (*next)->getLanes()[0];
1209  } else {
1210 #ifdef DEBUG_DRIVEWAY_BUILDROUTE
1211  if (gDebugFlag4) {
1212  std::cout << " abort: no next lane available\n";
1213  }
1214 #endif
1215  return;
1216  }
1217  }
1218  }
1219 }
1220 
1221 
1222 void
1223 MSRailSignal::DriveWay::checkFlanks(const std::vector<MSLane*>& lanes, const LaneVisitedMap& visited, bool allFoes) {
1224 #ifdef DEBUG_CHECK_FLANKS
1225  std::cout << " checkFlanks lanes=" << toString(lanes) << "\n visited=" << formatVisitedMap(visited) << " allFoes=" << allFoes << "\n";
1226 #endif
1227  for (MSLane* lane : lanes) {
1228  if (lane->isInternal()) {
1229  continue;
1230  }
1231  for (auto ili : lane->getIncomingLanes()) {
1232  if (visited.count(ili.lane->getNormalPredecessorLane()) == 0) {
1233 #ifdef DEBUG_CHECK_FLANKS
1234  std::cout << " add flankSwitch junction=" << ili.viaLink->getJunction()->getID() << " index=" << ili.viaLink->getIndex() << "\n";
1235 #endif
1236  myFlankSwitches.push_back(ili.viaLink);
1237  } else if (allFoes) {
1238  // link is part of the driveway, find foes that cross the driveway without entering
1239  checkCrossingFlanks(ili.viaLink, visited);
1240  }
1241  }
1242  }
1243 }
1244 
1245 
1246 void
1248 #ifdef DEBUG_CHECK_FLANKS
1249  std::cout << " checkCrossingFlanks dwLink=" << dwLink->getDescription() << " visited=" << formatVisitedMap(visited) << "\n";
1250 #endif
1251  const MSJunction* junction = dwLink->getJunction();
1252  if (junction == nullptr) {
1253  return; // unregulated junction;
1254  }
1255  const MSJunctionLogic* logic = junction->getLogic();
1256  if (logic == nullptr) {
1257  return; // unregulated junction;
1258  }
1259  for (const MSEdge* in : junction->getIncoming()) {
1260  if (in->isInternal()) {
1261  continue;
1262  }
1263  for (MSLane* inLane : in->getLanes()) {
1264  if (isRailway(inLane->getPermissions()) && visited.count(inLane) == 0) {
1265  for (MSLink* link : inLane->getLinkCont()) {
1266  if (link->getIndex() >= 0 && logic->getFoesFor(dwLink->getIndex()).test(link->getIndex())
1267  && visited.count(link->getLane()) == 0) {
1268 #ifdef DEBUG_CHECK_FLANKS
1269  std::cout << " add crossing flankSwitch junction=" << junction->getID() << " index=" << link->getIndex() << "\n";
1270 #endif
1271  if (link->getViaLane() == nullptr) {
1272  myFlankSwitches.push_back(link);
1273  } else {
1274  myFlankSwitches.push_back(link->getViaLane()->getLinkCont().front());
1275  }
1276  }
1277  }
1278  }
1279  }
1280  }
1281 }
1282 
1283 void
1284 MSRailSignal::DriveWay::findFlankProtection(MSLink* link, double length, LaneVisitedMap& visited, MSLink* origLink) {
1285 #ifdef DEBUG_CHECK_FLANKS
1286  std::cout << " findFlankProtection link=" << link->getDescription() << " length=" << length << " origLink=" << origLink->getDescription() << "\n";
1287 #endif
1288  if (link->getTLLogic() != nullptr) {
1289  // guarded by signal
1290 #ifdef DEBUG_CHECK_FLANKS
1291  std::cout << " flank guarded by " << link->getTLLogic()->getID() << "\n";
1292 #endif
1293  myConflictLinks.push_back(link);
1294  } else if (length > MAX_BLOCK_LENGTH) {
1295  // length exceeded
1297  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).");
1298  }
1299  myNumWarnings++;
1300  } else {
1301  // find normal lane before this link
1302  const MSLane* lane = link->getLaneBefore();
1303  const bool isNew = visited.count(lane) == 0;
1304  if (isNew || (visited[lane] > visited[origLink->getLane()] && std::find(myForward.begin(), myForward.end(), lane) == myForward.end())) {
1305  if (isNew) {
1306  visited[lane] = (int)visited.size();
1307  }
1308  length += lane->getLength();
1309  if (lane->isInternal()) {
1310  myFlank.push_back(lane);
1311  findFlankProtection(lane->getIncomingLanes().front().viaLink, length, visited, origLink);
1312  } else {
1313  bool foundPSwitch = false;
1314  for (MSLink* l2 : lane->getLinkCont()) {
1315 #ifdef DEBUG_CHECK_FLANKS
1316  std::cout << " lane=" << lane->getID() << " visitedIndex=" << visited[lane] << " origIndex=" << visited[origLink->getLane()] << " cand=" << l2->getDescription() << "\n";
1317 #endif
1318  if (l2->getDirection() != LinkDirection::TURN && l2->getLane() != link->getLane()) {
1319  foundPSwitch = true;
1320  // found potential protection
1321 #ifdef DEBUG_CHECK_FLANKS
1322  std::cout << " protectingSwitch=" << l2->getDescription() << " for flank=" << link->getDescription() << "\n";
1323 #endif
1324  myProtectingSwitches.push_back(link);
1325  }
1326  }
1327  if (!foundPSwitch) {
1328  myFlank.push_back(lane);
1329  // continue search for protection upstream recursively
1330  for (auto ili : lane->getIncomingLanes()) {
1331  if (ili.viaLink->getDirection() != LinkDirection::TURN) {
1332  findFlankProtection(ili.viaLink, length, visited, origLink);
1333  }
1334  }
1335  }
1336  }
1337  } else {
1338 #ifdef DEBUG_CHECK_FLANKS
1339  std::cout << " laneBefore=" << lane->getID() << " already visited. index=" << visited[lane] << " origAfter=" << origLink->getLane()->getID() << " origIndex=" << visited[origLink->getLane()] << "\n";
1340 #endif
1341  }
1342  }
1343  myMaxFlankLength = MAX2(myMaxFlankLength, length);
1344 }
1345 
1346 void
1348  myBlockingVehicles.clear();
1349  myRivalVehicles.clear();
1350  myPriorityVehicles.clear();
1351  myConstraintInfo = "";
1352  myStoreVehicles = true;
1353  LinkInfo& li = myLinkInfos[linkIndex];
1354  if (li.myLink->getApproaching().size() > 0) {
1355  Approaching closest = getClosest(li.myLink);
1356  DriveWay& driveway = li.getDriveWay(closest.first);
1357  MSEdgeVector occupied;
1358  // call for side effects
1359  driveway.reserve(closest, occupied);
1360  constraintsAllow(closest.first);
1361  } else {
1362  li.myDriveways.front().conflictLaneOccupied();
1363  }
1364  myStoreVehicles = false;
1365 }
1366 
1369  storeTraCIVehicles(linkIndex);
1370  return myBlockingVehicles;
1371 }
1372 
1375  storeTraCIVehicles(linkIndex);
1376  return myRivalVehicles;
1377 }
1378 
1381  storeTraCIVehicles(linkIndex);
1382  return myPriorityVehicles;
1383 }
1384 
1385 std::string
1387  storeTraCIVehicles(linkIndex);
1388  return myConstraintInfo;
1389 }
1390 
1392 MSRailSignal::retrieveDriveWay(int numericalID) const {
1393  for (const LinkInfo& li : myLinkInfos) {
1394  for (const DriveWay& dw : li.myDriveways) {
1395  if (dw.myNumericalID == numericalID) {
1396  return dw;
1397  }
1398  }
1399  }
1400  throw ProcessError("Invalid driveway id " + toString(numericalID) + " at railSignal '" + getID() + "'");
1401 }
1402 
1403 
1404 void
1406  if (mySwitchedGreenFlanks.size() > 0) {
1407  for (const auto& item : mySwitchedGreenFlanks) {
1408  for (const auto& item2 : mySwitchedGreenFlanks) {
1409  if (item.second < item2.second) {
1410  bool conflict = false;
1411  std::pair<int, int> code(item.second, item2.second);
1412  auto it = myDriveWayCompatibility.find(code);
1413  if (it != myDriveWayCompatibility.end()) {
1414  conflict = it->second;
1415  } else {
1416  // new driveway pair
1417  const MSRailSignal* rs = static_cast<const MSRailSignal*>(item.first->getTLLogic());
1418  const MSRailSignal* rs2 = static_cast<const MSRailSignal*>(item2.first->getTLLogic());
1419  const DriveWay& dw = rs->retrieveDriveWay(item.second);
1420  const DriveWay& dw2 = rs2->retrieveDriveWay(item2.second);
1421  // overlap may return true if the driveways are consecutive forward sections
1422  conflict = dw.flankConflict(dw2) || dw2.flankConflict(dw);
1423  myDriveWayCompatibility[code] = conflict;
1424 #ifdef DEBUG_RECHECKGREEN
1425  std::cout << SIMTIME << " new code " << code.first << "," << code.second << " conflict=" << conflict << " dw=" << toString(dw.myRoute) << " dw2=" << toString(dw2.myRoute) << "\n";
1426 #endif
1427  }
1428  if (conflict) {
1429  MSRailSignal* rs = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item.first->getTLLogic()));
1430  MSRailSignal* rs2 = const_cast<MSRailSignal*>(static_cast<const MSRailSignal*>(item2.first->getTLLogic()));
1431  const Approaching& veh = rs->getClosest(item.first);
1432  const Approaching& veh2 = rs2->getClosest(item2.first);
1433  if (DriveWay::mustYield(veh, veh2)) {
1434  std::string state = rs->myCurrentPhase.getState();
1435  state[item.first->getTLIndex()] = 'r';
1436  rs->myCurrentPhase.setState(state);
1438 #ifdef DEBUG_RECHECKGREEN
1439  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1440  << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1441 #endif
1442 #ifdef DEBUG_SIGNALSTATE
1443  if (DEBUG_HELPER(rs)) {
1444  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item.first)
1445  << " (" << veh.first->getID() << " yields to " << veh2.first->getID() << "\n";
1446  }
1447 #endif
1448  } else {
1449  std::string state = rs2->myCurrentPhase.getState();
1450  state[item2.first->getTLIndex()] = 'r';
1451  rs2->myCurrentPhase.setState(state);
1452  rs2->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1453 #ifdef DEBUG_RECHECKGREEN
1454  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1455  << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1456 #endif
1457 #ifdef DEBUG_SIGNALSTATE
1458  if (DEBUG_HELPER(rs2)) {
1459  std::cout << SIMTIME << " reset to red " << getClickableTLLinkID(item2.first)
1460  << " (" << veh2.first->getID() << " yields to " << veh.first->getID() << "\n";
1461  }
1462 #endif
1463  }
1464  }
1465  }
1466  }
1467  }
1468  mySwitchedGreenFlanks.clear();
1469  }
1470 }
1471 
1472 void
1474  for (LinkInfo& li : myLinkInfos) {
1475  for (auto it = li.myDriveways.begin(); it != li.myDriveways.end(); it++) {
1476  const DriveWay& dw = *it;
1477  if (dw.myNumericalID == numericalID) {
1478 #ifdef DEBUG_DRIVEWAY_UPDATE
1479  std::cout << SIMTIME << " rail signal junction '" << getID() << "' requires update for driveway " << numericalID << "\n";
1480 #endif
1481  std::vector<const MSEdge*> route = dw.myRoute;
1482  li.myDriveways.erase(it);
1483  if (li.myDriveways.size() == 0) {
1484  // rebuild default driveway
1485  li.myDriveways.push_back(li.buildDriveWay(route.begin(), route.end()));
1486  }
1487  return;
1488  }
1489  }
1490  }
1491 }
1492 
1493 std::string
1495  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1496  if (myLinkInfos.size() == 1) {
1497  return toString(rs->getBlockingVehicles(0));
1498  } else {
1499  std::string result;
1500  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1501  result += toString(i) + ": " + toString(rs->getBlockingVehicles(i)) + ";";
1502  }
1503  return result;
1504  }
1505 }
1506 std::string
1508  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1509  if (myLinkInfos.size() == 1) {
1510  return toString(rs->getRivalVehicles(0));
1511  } else {
1512  std::string result;
1513  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1514  result += toString(i) + ": " + toString(rs->getRivalVehicles(i)) + ";";
1515  }
1516  return result;
1517  }
1518 }
1519 std::string
1521  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1522  if (myLinkInfos.size() == 1) {
1523  return toString(rs->getPriorityVehicles(0));
1524  } else {
1525  std::string result;
1526  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1527  result += toString(i) + ": " + toString(rs->getPriorityVehicles(i)) + ";";
1528  }
1529  return result;
1530  }
1531 }
1532 std::string
1534  MSRailSignal* rs = const_cast<MSRailSignal*>(this);
1535  if (myLinkInfos.size() == 1) {
1536  return rs->getConstraintInfo(0);
1537  } else {
1538  std::string result;
1539  for (int i = 0; i < (int)myLinkInfos.size(); i++) {
1540  result += toString(i) + ": " + rs->getConstraintInfo(i);
1541  }
1542  return result;
1543  }
1544 }
1545 
1546 void
1547 MSRailSignal::setParameter(const std::string& key, const std::string& value) {
1548  // some pre-defined parameters can be updated at runtime
1549  if (key == "moving-block") {
1550  bool movingBlock = StringUtils::toBool(value);
1551  if (movingBlock != myMovingBlock) {
1552  // recompute driveways
1553  myMovingBlock = movingBlock;
1554  for (LinkInfo& li : myLinkInfos) {
1555  li.reset();
1556  }
1558  setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
1559  }
1560  }
1561  Parameterised::setParameter(key, value);
1562 }
1563 
1564 /****************************************************************************/
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:54
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define SPEED2DIST(x)
Definition: SUMOTime.h:43
#define SIMTIME
Definition: SUMOTime.h:60
long long int SUMOTime
Definition: SUMOTime.h:32
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.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ 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:35
T MAX2(T a, T b)
Definition: StdDefs.h:80
#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:269
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.
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:257
const MSJunction * getFromJunction() const
Definition: MSEdge.h:397
double getLength() const
return the length of the edge
Definition: MSEdge.h:641
const MSJunction * getToJunction() const
Definition: MSEdge.h:401
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition: MSEdge.h:276
static bool gUseMesoSim
Definition: MSGlobals.h:94
The base class for an intersection.
Definition: MSJunction.h:58
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:105
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:130
virtual const MSJunctionLogic * getLogic() const
Definition: MSJunction.h:138
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:82
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:641
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2151
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition: MSLane.cpp:1967
double getLength() const
Returns the lane's length.
Definition: MSLane.h:541
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:837
bool isInternal() const
Definition: MSLane.cpp:2122
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:674
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:4051
bool isEmpty() const
Definition: MSLane.h:775
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:318
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
virtual bool cleared() const =0
whether the constraint has been met
void addSignal(MSRailSignal *signal)
const std::set< const MSEdge * > & getUsedEdges() const
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:481
std::string getBlockingVehicleIDs() const
int getIndexFromOffset(SUMOTime offset) const
Returns the step (the phasenumber) of a given position of the cycle.
Phases myPhases
The list of phases this logic uses.
Definition: MSRailSignal.h:451
std::string getConstraintInfo(int linkIndex)
return information regarding active rail signal constraints for the closest approaching vehicle
std::map< std::string, std::vector< MSRailSignalConstraint * > > myInsertionConstraints
Definition: MSRailSignal.h:464
static VehicleVector myPriorityVehicles
Definition: MSRailSignal.h:482
int myPhaseIndex
MSTrafficLightLogic requires that the phase index changes whenever signals change their state.
Definition: MSRailSignal.h:457
int getPhaseNumber() const
Returns the number of phases.
static std::string myConstraintInfo
Definition: MSRailSignal.h:483
MSPhaseDefinition myCurrentPhase
The current phase.
Definition: MSRailSignal.h:454
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)
Definition: MSRailSignal.h:421
std::string getPriorityVehicleIDs() const
static int myDriveWayIndex
Definition: MSRailSignal.h:471
static std::string describeLinks(std::vector< MSLink * > links)
print link descriptions
VehicleVector getRivalVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and are in conflict with vehicles that wis...
void writeBlocks(OutputDevice &od) const
write rail signal block output for all links and driveways
~MSRailSignal()
Destructor.
VehicleVector getPriorityVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and have priority over vehicles that wish ...
const Phases & getPhases() const
Returns the phases of this tls program.
static VehicleVector myBlockingVehicles
Definition: MSRailSignal.h:480
void removeConstraints()
void storeTraCIVehicles(int linkIndex)
update vehicle lists for traci calls
SUMOTime getOffsetFromIndex(int index) const
Returns the position (start of a phase during a cycle) from of a given step.
static Approaching getClosest(MSLink *link)
get the closest vehicle approaching the given link
void setParameter(const std::string &key, const std::string &value)
Sets a parameter and updates internal constants.
std::map< std::string, std::vector< MSRailSignalConstraint * > > myConstraints
map from tripId to constraint list
Definition: MSRailSignal.h:463
static std::map< std::pair< int, int >, bool > myDriveWayCompatibility
Definition: MSRailSignal.h:470
std::pair< const SUMOVehicle *const, const MSLink::ApproachingVehicleInformation > Approaching
Definition: MSRailSignal.h:260
SUMOTime trySwitch()
Switches to the next phase.
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
Definition: MSRailSignal.h:466
const DriveWay & retrieveDriveWay(int numericalID) const
static bool myStoreVehicles
Definition: MSRailSignal.h:479
void addInsertionConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for vehicle insertion
const MSPhaseDefinition & getPhase(int givenstep) const
Returns the definition of the phase from the given position within the plan.
std::map< const MSLane *, int, ComparatorNumericalIdLess > LaneVisitedMap
Definition: MSRailSignal.h:262
bool myMovingBlock
whether the signal is in moving block mode (only protects from oncoming and flanking trains)
Definition: MSRailSignal.h:460
bool removeConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
remove contraint for signal switching
static std::vector< std::pair< MSLink *, int > > mySwitchedGreenFlanks
list of signals that switched green along with driveway index
Definition: MSRailSignal.h:469
void addLink(MSLink *link, MSLane *lane, int pos)
Adds a link on building.
SUMOTime getPhaseIndexAtTime(SUMOTime simStep) const
Returns the index of the logic at the given simulation step.
MSRailSignal(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, SUMOTime delay, const std::map< std::string, std::string > &parameters)
Constructor.
void init(NLDetectorBuilder &nb)
Initialises the rail signal with information about adjacent rail signals.
void updateDriveway(int numericalID)
update driveway for extended deadlock protection
const MSPhaseDefinition & getCurrentPhaseDef() const
Returns the definition of the current phase.
std::string getConstraintInfo() const
static std::string formatVisitedMap(const LaneVisitedMap &visited)
print link descriptions
void adaptLinkInformationFrom(const MSTrafficLightLogic &logic)
Applies information about controlled links and lanes from the given logic.
VehicleVector getBlockingVehicles(int linkIndex)
return vehicles that block the intersection/rail signal for vehicles that wish to pass the given link...
void updateCurrentPhase()
returns the state of the signal that actually required
static bool hasOncomingRailTraffic(MSLink *link)
std::string getRivalVehicleIDs() const
int getCurrentPhaseIndex() const
Returns the current index within the program.
static bool hasInsertionConstraint(MSLink *link, const MSVehicle *veh, std::string &info)
static std::string getTLLinkID(MSLink *link)
return logicID_linkIndex
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition: MSRoute.cpp:75
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition: MSRoute.cpp:69
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:120
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 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:75
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:58
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:236
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:248
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
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)
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual const MSRoute & getRoute() const =0
Returns the current route.
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 int getRoutePosition() const =0
return index of edge within 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
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
void checkFlanks(const std::vector< MSLane * > &lanes, const LaneVisitedMap &visited, bool allFoes)
find switches that threathen this driveway
void writeBlocks(OutputDevice &od) const
Write block items for this driveway.
void buildRoute(MSLink *origin, double length, MSRouteIterator next, MSRouteIterator end, LaneVisitedMap &visited)
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:298
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:292
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:283
std::vector< MSLink * > myConflictLinks
Definition: MSRailSignal.h:333
void checkCrossingFlanks(MSLink *dwLink, const LaneVisitedMap &visited)
find links that cross the driveway without entering it
std::vector< MSLane * > myBidi
Definition: MSRailSignal.h:307
void findFlankProtection(MSLink *link, double length, LaneVisitedMap &visited, MSLink *origLink)
find upstream protection from the given link
bool conflictLaneOccupied(const std::string &joinVehicle="", bool store=true) 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:295
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
std::vector< MSLane * > myForward
Definition: MSRailSignal.h:302
bool conflictLinkApproached() const
Whether any of the conflict linkes 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.