Eclipse SUMO - Simulation of Urban MObility
NBLoadedSUMOTLDef.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2011-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 complete traffic light logic loaded from a sumo-net. (opted to reimplement
21 // since NBLoadedTLDef is quite vissim specific)
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <vector>
26 #include <set>
27 #include <cassert>
28 #include <iterator>
30 #include <utils/common/ToString.h>
32 #include "NBTrafficLightLogic.h"
33 #include "NBOwnTLDef.h"
35 #include "NBLoadedSUMOTLDef.h"
36 #include "NBNetBuilder.h"
37 #include "NBOwnTLDef.h"
38 #include "NBNode.h"
39 
40 //#define DEBUG_RECONSTRUCTION
41 
42 // ===========================================================================
43 // method definitions
44 // ===========================================================================
45 
46 NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(const std::string& id, const std::string& programID,
47  SUMOTime offset, TrafficLightType type) :
48  NBTrafficLightDefinition(id, programID, offset, type),
49  myTLLogic(nullptr),
50  myReconstructAddedConnections(false),
51  myReconstructRemovedConnections(false),
52  myPhasesLoaded(false) {
53  myTLLogic = new NBTrafficLightLogic(id, programID, 0, offset, type);
54 }
55 
56 
58  // allow for adding a new program for the same def: take the offset and programID from the new logic
59  NBTrafficLightDefinition(def.getID(), logic.getProgramID(), logic.getOffset(), def.getType()),
60  myTLLogic(new NBTrafficLightLogic(logic)),
61  myReconstructAddedConnections(false),
62  myReconstructRemovedConnections(false),
63  myPhasesLoaded(false) {
64  assert(def.getType() == logic.getType());
67  const NBLoadedSUMOTLDef* sumoDef = dynamic_cast<const NBLoadedSUMOTLDef*>(&def);
69  if (sumoDef != nullptr) {
72  }
73 }
74 
75 
77  delete myTLLogic;
78 }
79 
80 
82 NBLoadedSUMOTLDef::myCompute(int brakingTimeSeconds) {
83  // @todo what to do with those parameters?
84  UNUSED_PARAMETER(brakingTimeSeconds);
86  myTLLogic->closeBuilding(false);
89  return new NBTrafficLightLogic(myTLLogic);
90 }
91 
92 
93 void
94 NBLoadedSUMOTLDef::addConnection(NBEdge* from, NBEdge* to, int fromLane, int toLane, int linkIndex, int linkIndex2, bool reconstruct) {
95  assert(myTLLogic->getNumLinks() > 0); // logic should be loaded by now
96  if (linkIndex >= (int)myTLLogic->getNumLinks()) {
97  throw ProcessError("Invalid linkIndex " + toString(linkIndex) + " for traffic light '" + getID() +
98  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
99  }
100  if (linkIndex2 >= (int)myTLLogic->getNumLinks()) {
101  throw ProcessError("Invalid linkIndex2 " + toString(linkIndex2) + " for traffic light '" + getID() +
102  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
103  }
104  NBConnection conn(from, fromLane, to, toLane, linkIndex, linkIndex2);
105  // avoid duplicates
106  auto newEnd = remove_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(conn));
107  // remove_if does not remove, only re-order
108  myControlledLinks.erase(newEnd, myControlledLinks.end());
109  myControlledLinks.push_back(conn);
110  addNode(from->getToNode());
111  addNode(to->getFromNode());
112  // added connections are definitely controlled. make sure none are removed because they lie within the tl
113  // myControlledInnerEdges.insert(from->getID()); // @todo recheck: this appears to be obsolete
114  // set this information now so that it can be used while loading diffs
115  from->setControllingTLInformation(conn, getID());
116  myReconstructAddedConnections |= reconstruct;
117 }
118 
119 void
120 NBLoadedSUMOTLDef::setProgramID(const std::string& programID) {
122  myTLLogic->setProgramID(programID);
123 }
124 
125 void
131  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
132  (*i)->removeTrafficLight(&dummy);
133  }
134  }
136  return; // will be called again in reconstructLogic()
137  }
138  // if nodes have been removed our links may have been invalidated as well
139  // since no logic will be built anyway there is no reason to inform any edges
140  if (amInvalid()) {
141  return;
142  }
143  // set the information about the link's positions within the tl into the
144  // edges the links are starting at, respectively
145  for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
146  const NBConnection& c = *it;
147  if (c.getTLIndex() >= (int)myTLLogic->getNumLinks()) {
148  throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
149  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
150  }
151  NBEdge* edge = c.getFrom();
152  if (edge != nullptr && edge->getNumLanes() > c.getFromLane()) {
153  // logic may have yet to be reconstructed
155  }
156  }
157 }
158 
159 
160 void
162 
163 
164 void
165 NBLoadedSUMOTLDef::replaceRemoved(NBEdge* removed, int removedLane, NBEdge* by, int byLane, bool incoming) {
166  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
167  if (incoming) {
168  (*it).replaceFrom(removed, removedLane, by, byLane);
169  } else {
170  (*it).replaceTo(removed, removedLane, by, byLane);
171  }
172  }
173 }
174 
175 
176 void
177 NBLoadedSUMOTLDef::addPhase(SUMOTime duration, const std::string& state, SUMOTime minDur, SUMOTime maxDur, const std::vector<int>& next, const std::string& name) {
178  myTLLogic->addStep(duration, state, minDur, maxDur, next, name);
179 }
180 
181 
182 bool
184  if (myControlledLinks.size() == 0) {
185  return true;
186  }
187  if (myIncomingEdges.size() == 0) {
188  return true;
189  }
190  return false;
191 }
192 
193 
194 void
195 NBLoadedSUMOTLDef::removeConnection(const NBConnection& conn, bool reconstruct) {
196  for (auto it = myControlledLinks.begin(); it != myControlledLinks.end();) {
197  if ((it->getFrom() == conn.getFrom() &&
198  it->getTo() == conn.getTo() &&
199  it->getFromLane() == conn.getFromLane() &&
200  it->getToLane() == conn.getToLane())
201  || (it->getTLIndex() == conn.getTLIndex() &&
202  conn.getTLIndex() != conn.InvalidTlIndex &&
203  (it->getFrom() == nullptr || it->getTo() == nullptr))) {
204  if (reconstruct) {
206  it++;
207  } else {
208  it = myControlledLinks.erase(it);
209  }
210  } else {
211  it++;
212  }
213  }
214 }
215 
216 
217 void
219  myOffset = offset;
220  myTLLogic->setOffset(offset);
221 }
222 
223 
224 void
226  myType = type;
227  myTLLogic->setType(type);
228 }
229 
230 
231 void
233  if (myControlledLinks.size() == 0) {
235  }
236  myIncomingEdges.clear();
237  EdgeVector myOutgoing;
238  // collect the edges from the participating nodes
239  for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
240  const EdgeVector& incoming = (*i)->getIncomingEdges();
241  copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
242  const EdgeVector& outgoing = (*i)->getOutgoingEdges();
243  copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
244  }
245  // check which of the edges are completely within the junction
246  // and which are uncontrolled as well (we already know myControlledLinks)
247  for (EdgeVector::iterator j = myIncomingEdges.begin(); j != myIncomingEdges.end();) {
248  NBEdge* edge = *j;
249  edge->setInsideTLS(false); // reset
250  // an edge lies within the logic if it is outgoing as well as incoming
251  EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
252  if (k != myOutgoing.end()) {
253  if (myControlledInnerEdges.count(edge->getID()) == 0) {
254  bool controlled = false;
255  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
256  if ((*it).getFrom() == edge) {
257  controlled = true;
258  break;
259  }
260  }
261  if (controlled) {
262  myControlledInnerEdges.insert(edge->getID());
263  } else {
264  myEdgesWithin.push_back(edge);
265  edge->setInsideTLS(true);
266  ++j; //j = myIncomingEdges.erase(j);
267  continue;
268  }
269  }
270  }
271  ++j;
272  }
273 }
274 
275 
276 void
278  if (myControlledLinks.size() == 0) {
279  // maybe we only loaded a different program for a default traffic light.
280  // Try to build links now.
282  }
283 }
284 
285 
287 void
288 NBLoadedSUMOTLDef::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
289  // avoid shifting twice if the edge is incoming and outgoing to a joined TLS
290  if (myShifted.count(edge) == 0) {
292  myShifted.insert(edge);
293  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
294  (*it).shiftLaneIndex(edge, offset, threshold);
295  }
296  }
297 }
298 
299 void
301  const int size = myTLLogic->getNumLinks();
302  int noLinksAll = 0;
303  for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
304  const NBConnection& c = *it;
306  noLinksAll = MAX2(noLinksAll, (int)c.getTLIndex() + 1);
307  }
308  }
309  const int numNormalLinks = noLinksAll;
310  int oldCrossings = 0;
311  // collect crossings
312  bool customIndex = false;
313  std::vector<NBNode::Crossing*> crossings;
314  for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
315  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
316  // set tl indices for crossings
317  customIndex |= (*i)->setCrossingTLIndices(getID(), noLinksAll);
318  copy(c.begin(), c.end(), std::back_inserter(crossings));
319  noLinksAll += (int)c.size();
320  oldCrossings += (*i)->numCrossingsFromSumoNet();
321  }
322  if ((int)crossings.size() != oldCrossings) {
323  std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
324  // do not rebuilt crossing states there are custom indices and the state string is long enough
325  if (phases.size() > 0 && (
326  (int)(phases.front().state.size()) < noLinksAll ||
327  ((int)(phases.front().state.size()) > noLinksAll && !customIndex))) {
328  // collect edges
329  EdgeVector fromEdges(size, (NBEdge*)nullptr);
330  EdgeVector toEdges(size, (NBEdge*)nullptr);
331  std::vector<int> fromLanes(size, 0);
332  collectEdgeVectors(fromEdges, toEdges, fromLanes);
333  const std::string crossingDefaultState(crossings.size(), 'r');
334 
335  // rebuild the logic (see NBOwnTLDef.cpp::myCompute)
337  SUMOTime brakingTime = TIME2STEPS(computeBrakingTime(OptionsCont::getOptions().getFloat("tls.yellow.min-decel")));
338  //std::cout << "patchIfCrossingsAdded for " << getID() << " numPhases=" << phases.size() << "\n";
339  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
340  const std::string state = it->state.substr(0, numNormalLinks) + crossingDefaultState;
341  NBOwnTLDef::addPedestrianPhases(newLogic, it->duration, it->minDur, it->maxDur, state, crossings, fromEdges, toEdges);
342  }
343  NBOwnTLDef::addPedestrianScramble(newLogic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
344 
345  delete myTLLogic;
346  myTLLogic = newLogic;
347  } else if (phases.size() == 0) {
348  WRITE_WARNING("Could not patch tlLogic '" + getID() + "' for changed crossings");
349  }
350  }
351 }
352 
353 
354 void
355 NBLoadedSUMOTLDef::collectEdgeVectors(EdgeVector& fromEdges, EdgeVector& toEdges, std::vector<int>& fromLanes) const {
356  assert(fromEdges.size() > 0);
357  assert(fromEdges.size() == toEdges.size());
358  const int size = (int)fromEdges.size();
359 
360  for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
361  const NBConnection& c = *it;
363  if (c.getTLIndex() >= size) {
364  throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
365  "' with " + toString(size) + " links.");
366  }
367  fromEdges[c.getTLIndex()] = c.getFrom();
368  toEdges[c.getTLIndex()] = c.getTo();
369  fromLanes[c.getTLIndex()] = c.getFromLane();
370  }
371  }
372 }
373 
374 
375 void
377  if (!amInvalid() && !myNeedsContRelationReady) {
378  myNeedsContRelation.clear();
379  myRightOnRedConflicts.clear();
380  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
381  const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
382  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
383  const std::string state = (*it).state;
384  for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
385  const NBConnection& c1 = *it1;
386  const int i1 = c1.getTLIndex();
387  if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
388  continue;
389  }
390  for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
391  const NBConnection& c2 = *it2;
392  const int i2 = c2.getTLIndex();
394  && i2 != i1
395  && (state[i2] == 'G' || state[i2] == 'g')
396  && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
397  const bool rightTurnConflict = NBNode::rightTurnConflict(
398  c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
399  const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
400  const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
401  if (forbidden || rightTurnConflict) {
402  myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
403  }
404  if (isFoes && state[i1] == 's') {
405  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
406  //std::cout << getID() << " prog=" << getProgramID() << " phase=" << (it - phases.begin()) << " rightOnRedConflict i1=" << i1 << " i2=" << i2 << "\n";
407  }
408  //std::cout << getID() << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
409  }
410  }
411  }
412  }
413  }
416 }
417 
418 
419 bool
420 NBLoadedSUMOTLDef::rightOnRedConflict(int index, int foeIndex) const {
421  if (amInvalid()) {
422  return false;
423  }
427  }
428  return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
429 }
430 
431 
432 void
433 NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
434  myReconstructAddedConnections |= addedConnections;
435  myReconstructRemovedConnections |= removedConnections;
436 }
437 
438 void
440  const bool netedit = NBNetBuilder::runningNetedit();
441 #ifdef DEBUG_RECONSTRUCTION
443  std::cout << getID() << " reconstructLogic added=" << myReconstructAddedConnections
444  << " removed=" << myReconstructRemovedConnections
445  << " valid=" << hasValidIndices()
446  << " phasesLoaded=" << myPhasesLoaded
447  << " oldLinks:\n";
448  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
449  std::cout << " " << *it << "\n";
450  }
451 #endif
454  // do not rebuild the logic when running netedit and all links are already covered by the program
455  if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
456  // rebuild the logic from scratch
457  // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
460  dummy.setProgramID(getProgramID());
465  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
466  (*i)->removeTrafficLight(&dummy);
467  }
468  delete myTLLogic;
469  myTLLogic = newLogic;
470  if (newLogic != nullptr) {
471  newLogic->setID(getID());
472  newLogic->setType(getType());
473  newLogic->setOffset(getOffset());
475  // reset crossing custom indices
476  for (NBNode* n : myControlledNodes) {
477  for (NBNode::Crossing* c : n->getCrossings()) {
478  c->customTLIndex = NBConnection::InvalidTlIndex;
479  }
480  }
481 
482  }
483  } else {
485  }
486  }
489  // for each connection, check whether it is still valid
490  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
491  const NBConnection con = (*it);
492  if (// edge still exists
493  std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
494  // connection still exists
495  && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
496  // connection is still set to be controlled
497  && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane())) {
498  it++;
499  } else {
500  // remove connection
501  const int removed = con.getTLIndex();
502  it = myControlledLinks.erase(it);
503  // no automatic modificaions when running netedit
504  if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
505  // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
506  bool exclusive = true;
507  for (NBConnection& other : myControlledLinks) {
508  if (other != con && other.getTLIndex() == removed) {
509  exclusive = false;
510  break;
511  }
512  }
513  if (exclusive) {
514  // shift indices above the removed index downward
515  for (NBConnection& other : myControlledLinks) {
516  if (other.getTLIndex() > removed) {
517  other.setTLIndex(other.getTLIndex() - 1);
518  }
519  }
520  // shift crossing custom indices above the removed index downward
521  for (NBNode* n : myControlledNodes) {
522  for (NBNode::Crossing* c : n->getCrossings()) {
523  if (c->customTLIndex > removed) {
524  c->customTLIndex--;
525  }
526  }
527  }
528  // rebuild the logic
531  std::string newState = phase.state;
532  newState.erase(newState.begin() + removed);
533  newLogic->addStep(phase.duration, newState);
534  }
535  delete myTLLogic;
536  myTLLogic = newLogic;
537  }
538  }
539  }
540  }
542  }
543 #ifdef DEBUG_RECONSTRUCTION
544  if (debugPrintModified) {
545  std::cout << " newLinks:\n";
546  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
547  std::cout << " " << *it << "\n";
548  }
549  }
550 #endif
551 }
552 
553 
554 int
556  int maxIndex = -1;
557  for (const NBConnection& c : myControlledLinks) {
558  maxIndex = MAX2(maxIndex, c.getTLIndex());
559  maxIndex = MAX2(maxIndex, c.getTLIndex2());
560  }
561  for (NBNode* n : myControlledNodes) {
562  for (NBNode::Crossing* c : n->getCrossings()) {
563  maxIndex = MAX2(maxIndex, c->tlLinkIndex);
564  maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
565  }
566  }
567  return maxIndex;
568 }
569 
570 
571 int
573  return myTLLogic->getNumLinks() - 1;
574 }
575 
576 
577 bool
579  for (const NBConnection& c : myControlledLinks) {
580  if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
581  return false;
582  }
583  }
584  for (NBNode* n : myControlledNodes) {
585  for (NBNode::Crossing* c : n->getCrossings()) {
586  if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
587  return false;
588  }
589  }
590  }
591  // method getMaxIndex() is const but cannot be declare as such due to inheritance
592  return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
593 }
594 
595 
596 std::string
598  assert(index >= 0);
599  assert(index <= getMaxIndex());
600  std::string result;
601  for (auto& pd : myTLLogic->getPhases()) {
602  result += pd.state[index];
603  }
604  return result;
605 }
606 
607 bool
609  for (const NBConnection& c : myControlledLinks) {
610  if (c.getTLIndex() == index || c.getTLIndex2() == index) {
611  return true;
612  }
613  }
614  for (NBNode* n : myControlledNodes) {
615  for (NBNode::Crossing* c : n->getCrossings()) {
616  if (c->tlLinkIndex == index || c->tlLinkIndex2 == index) {
617  return true;
618  }
619  }
620  }
621  return false;
622 }
623 
624 std::set<const NBEdge*>
626  std::set<const NBEdge*> result;
627  for (const NBConnection& c : myControlledLinks) {
628  if (c.getTLIndex() == index || c.getTLIndex2() == index) {
629  result.insert(c.getFrom());
630  }
631  }
632  return result;
633 }
634 
635 
636 void
637 NBLoadedSUMOTLDef::replaceIndex(int oldIndex, int newIndex) {
638  if (oldIndex == newIndex) {
639  return;
640  }
641  for (NBConnection& c : myControlledLinks) {
642  if (c.getTLIndex() == oldIndex) {
643  c.setTLIndex(newIndex);
644  }
645  if (c.getTLIndex2() == oldIndex) {
646  c.setTLIndex2(newIndex);
647  }
648  }
649  for (NBNode* n : myControlledNodes) {
650  for (NBNode::Crossing* c : n->getCrossings()) {
651  if (c->tlLinkIndex == oldIndex) {
652  c->tlLinkIndex = newIndex;
653  }
654  if (c->tlLinkIndex2 == oldIndex) {
655  c->tlLinkIndex2 = newIndex;
656  }
657  }
658  }
659 }
660 
661 void
663  const int maxIndex = getMaxIndex();
664  std::vector<int> unusedIndices;
665  for (int i = 0; i <= maxIndex; i++) {
666  if (isUsed(i)) {
667  std::set<const NBEdge*> edges = getEdgesUsingIndex(i);
668  // compactify
669  replaceIndex(i, i - (int)unusedIndices.size());
670  if (edges.size() == 0) {
671  // do not group pedestrian crossing signals
672  continue;
673  }
674  std::string states = getStates(i);
675  for (int j = i + 1; j <= maxIndex; j++) {
676  // only group signals from the same edges as is commonly done by
677  // traffic engineers
678  if (states == getStates(j) && edges == getEdgesUsingIndex(j)) {
679  replaceIndex(j, i - (int)unusedIndices.size());
680  }
681  }
682  } else {
683  unusedIndices.push_back(i);
684  }
685  }
686  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
687  myTLLogic->deleteStateIndex(unusedIndices[i]);
688  }
689  cleanupStates();
690  //std::cout << "oldMaxIndex=" << maxIndex << " newMaxIndex=" << getMaxIndex() << " unused=" << toString(unusedIndices) << "\n";
692  // patch crossing indices
693  for (NBNode* n : myControlledNodes) {
694  for (NBNode::Crossing* c : n->getCrossings()) {
695  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
696  if (c->customTLIndex > i) {
697  c->customTLIndex--;
698  }
699  if (c->customTLIndex2 > i) {
700  c->customTLIndex2--;
701  }
702  }
703  }
704  }
705 }
706 
707 void
709  NBConnectionVector defaultOrdering;
710  collectAllLinks(defaultOrdering);
711  std::vector<std::string> states; // organized per link rather than phase
712  int index = 0;
713  for (NBConnection& c : defaultOrdering) {
714  NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
715  states.push_back(getStates(c2.getTLIndex()));
716  c2.setTLIndex(index++);
717  }
718  for (NBNode* n : myControlledNodes) {
719  for (NBNode::Crossing* c : n->getCrossings()) {
720  states.push_back(getStates(c->tlLinkIndex));
721  c->customTLIndex = index++;
722  if (c->tlLinkIndex2 != NBConnection::InvalidTlIndex) {
723  states.push_back(getStates(c->tlLinkIndex2));
724  c->customTLIndex2 = index++;
725  }
726  }
727  }
728  myTLLogic->setStateLength(index);
729  for (int i = 0; i < (int)states.size(); i++) {
730  for (int p = 0; p < (int)states[i].size(); p++) {
731  myTLLogic->setPhaseState(p, i, (LinkState)states[i][p]);
732  }
733  }
735 }
736 
737 
738 void
740  std::map<int, std::string> oldStates; // organized per link index rather than phase
741  std::map<int, std::string> newStates; // organized per link index rather than phase
742  for (NBConnection& c : def->getControlledLinks()) {
743  NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
744  const int oldIndex = c2.getTLIndex();
745  const int newIndex = c.getTLIndex();
746  std::string states = getStates(oldIndex);
747  oldStates[oldIndex] = states;
748  if (newStates.count(newIndex) != 0 && newStates[newIndex] != states) {
749  WRITE_WARNING("Signal groups from program '" + def->getProgramID() + "' are incompatible with the states of program '" + getProgramID() + "' at tlLogic '" + getID()
750  + "'. Possibly unsafe program.");
751  } else {
752  newStates[newIndex] = states;
753  }
754  c2.setTLIndex(newIndex);
755  }
756  const int maxIndex = getMaxIndex();
757  myTLLogic->setStateLength(maxIndex + 1);
758  for (int i = 0; i < (int)newStates.size(); i++) {
759  for (int p = 0; p < (int)newStates[i].size(); p++) {
760  myTLLogic->setPhaseState(p, i, (LinkState)newStates[i][p]);
761  }
762  }
764 }
765 
766 
767 bool
769  const int maxIndex = getMaxValidIndex();
770  std::vector<int> unusedIndices;
771  for (int i = 0; i <= maxIndex; i++) {
772  if (isUsed(i)) {
773  if (unusedIndices.size() > 0) {
774  replaceIndex(i, i - (int)unusedIndices.size());
775  }
776  } else {
777  unusedIndices.push_back(i);
778  }
779  }
780  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
781  myTLLogic->deleteStateIndex(unusedIndices[i]);
782  }
783  if (unusedIndices.size() > 0) {
784  myTLLogic->setStateLength(maxIndex + 1 - (int)unusedIndices.size());
786  return true;
787  } else {
788  return false;
789  }
790 }
791 
792 
793 void
797  const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
798  myTLLogic->setStateLength(maxIndex + 1);
799  myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
800 }
801 
802 bool
804  // count how often each index is used
805  std::map<int, int> indexUsage;
806  for (const NBConnection& c : myControlledLinks) {
807  indexUsage[c.getTLIndex()]++;
808  }
809  for (NBNode* n : myControlledNodes) {
810  for (NBNode::Crossing* c : n->getCrossings()) {
811  indexUsage[c->tlLinkIndex]++;
812  indexUsage[c->tlLinkIndex2]++;
813  }
814  }
815  for (auto it : indexUsage) {
816  if (it.first >= 0 && it.second > 1) {
817  return true;
818  }
819  }
820  return false;
821 }
822 
823 void
825  bool hasMinMaxDur = false;
826  for (auto phase : myTLLogic->getPhases()) {
827  if (phase.maxDur != UNSPECIFIED_DURATION) {
828  //std::cout << " phase=" << phase.state << " maxDur=" << phase.maxDur << "\n";
829  hasMinMaxDur = true;
830  }
831  }
832  if (!hasMinMaxDur) {
833  const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
834  const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
835  std::set<int> yellowIndices;
836  for (auto phase : myTLLogic->getPhases()) {
837  for (int i = 0; i < (int)phase.state.size(); i++) {
838  if (phase.state[i] == 'y' || phase.state[i] == 'Y') {
839  yellowIndices.insert(i);
840  }
841  }
842  }
843  for (int ip = 0; ip < (int)myTLLogic->getPhases().size(); ip++) {
844  bool needMinMaxDur = false;
845  auto phase = myTLLogic->getPhases()[ip];
846  std::set<int> greenIndices;
847  if (phase.state.find_first_of("yY") != std::string::npos) {
848  continue;
849  }
850  for (int i = 0; i < (int)phase.state.size(); i++) {
851  if (yellowIndices.count(i) != 0 && phase.state[i] == 'G') {
852  needMinMaxDur = true;
853  greenIndices.insert(i);
854  }
855  }
856  if (needMinMaxDur) {
857  double maxSpeed = 0;
858  for (NBConnection& c : myControlledLinks) {
859  if (greenIndices.count(c.getTLIndex()) != 0) {
860  maxSpeed = MAX2(maxSpeed, c.getFrom()->getLaneSpeed(c.getFromLane()));
861  }
862  }
863  // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
864  const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
865  SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
866  myTLLogic->setPhaseMinDuration(ip, minDur);
867  myTLLogic->setPhaseMaxDuration(ip, maxDur);
868  }
869  }
870  }
871 }
872 
873 
874 /****************************************************************************/
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
TrafficLightType
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MAX2(T a, T b)
Definition: StdDefs.h:80
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
NBEdge * getFrom() const
returns the from-edge (start of the connection)
int getFromLane() const
returns the from-lane
int getTLIndex() const
returns the index within the controlling tls or InvalidTLIndex if this link is unontrolled
Definition: NBConnection.h:91
static const int InvalidTlIndex
Definition: NBConnection.h:123
void setTLIndex(int tlIndex)
Definition: NBConnection.h:99
int getToLane() const
returns the to-lane
NBEdge * getTo() const
returns the to-edge (end of the connection)
The representation of a single edge during network building.
Definition: NBEdge.h:91
void setInsideTLS(bool inside)
Marks this edge being within an intersection.
Definition: NBEdge.h:1106
const std::string & getID() const
Definition: NBEdge.h:1465
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:541
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3420
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3356
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:515
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:3409
bool hasConnectionTo(NBEdge *destEdge, int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1249
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:534
class for identifying connections
A loaded (complete) traffic light logic.
bool isUsed(int index)
return whether the given link index is used by any connectons
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
int getMaxIndex()
return the highest known tls link index used by any controlled connection or crossing
bool hasValidIndices() const
return whether all tls link indices are valid
bool usingSignalGroups() const
whether this definition uses signal group (multiple connections with the same link index)
std::string getStates(int index)
get all states for the given link index
void ungroupSignals()
let all connections use a distinct link index
NBLoadedSUMOTLDef(const std::string &id, const std::string &programID, SUMOTime offset, TrafficLightType type)
Constructor.
bool myReconstructAddedConnections
whether the logic must be reconstructed
bool rightOnRedConflict(int index, int foeIndex) const
whether the given index must yield to the foeIndex while turing right on a red light
void copyIndices(NBTrafficLightDefinition *def)
copy the assignment of link indices to connections from the given definition and rebuilt the states t...
void groupSignals()
let connections with the same state use the same link index
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurences of the removed edge in incoming/outgoing edges of all definitions.
void collectEdges()
Build the list of participating edges.
void setProgramID(const std::string &programID)
Sets the programID.
void shiftTLConnectionLaneIndex(NBEdge *edge, int offset, int threshold=-1)
patches signal plans by modifying lane indices with the given offset, only indices with a value above...
NBTrafficLightLogic * myTLLogic
phases are added directly to myTLLogic which is then returned in myCompute()
std::set< NBEdge * > myShifted
set of edges with shifted lane indices (to avoid shifting twice)
void patchIfCrossingsAdded()
repair the plan if controlled nodes received pedestrian crossings
void removeConnection(const NBConnection &conn, bool reconstruct=true)
removes the given connection from the traffic light if recontruct=true, reconstructs the logic and in...
int getMaxValidIndex()
Returns the maximum index controlled by this traffic light.
void replaceIndex(int oldIndex, int newIndex)
replace the given link index in all connections
void collectLinks()
Collects the links participating in this traffic light (only if not previously loaded)
void registerModifications(bool addedConnections, bool removedConnections)
register changes that necessitate recomputation
void joinLogic(NBTrafficLightDefinition *def)
join nodes and states from the given logic (append red state)
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
void setType(TrafficLightType type)
Sets the algorithm type of this tls.
void collectEdgeVectors(EdgeVector &fromEdges, EdgeVector &toEdges, std::vector< int > &fromLanes) const
Collects the edges for each tlIndex.
void reconstructLogic()
adapt to removal or addition of connections
void addConnection(NBEdge *from, NBEdge *to, int fromLane, int toLane, int linkIndex, int linkIndex2, bool reconstruct=true)
Adds a connection and immediately informs the edges.
void guessMinMaxDuration()
heuristically add minDur and maxDur when switching from tlType fixed to actuated
std::set< const NBEdge * > getEdgesUsingIndex(int index) const
brief retrieve all edges with connections that use the given traffic light index
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces a removed edge/lane.
void setOffset(SUMOTime offset)
Sets the offset of this tls.
void addPhase(SUMOTime duration, const std::string &state, SUMOTime minDur, SUMOTime maxDur, const std::vector< int > &next, const std::string &name)
Adds a phase to the logic the new phase is inserted at the end of the list of already added phases.
~NBLoadedSUMOTLDef()
Destructor.
void initNeedsContRelation() const
static bool runningNetedit()
whether netbuilding takes place in the context of NETEDIT
A definition of a pedestrian crossing.
Definition: NBNode.h:129
Represents a single node (junction) during network building.
Definition: NBNode.h:66
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBNode.cpp:1925
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, SUMOTime greenTime, SUMOTime minDur, SUMOTime maxDur, std::string state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add 1 or 2 phases depending on the presence of pedestrian crossings
Definition: NBOwnTLDef.cpp:743
static void addPedestrianScramble(NBTrafficLightLogic *logic, int noLinksAll, SUMOTime greenTime, SUMOTime yellowTime, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add an additional pedestrian phase if there are crossings that did not get green yet
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
Definition: NBOwnTLDef.cpp:829
The base class for traffic light logic definitions.
const NBConnectionVector & getControlledLinks() const
returns the controlled links (depends on previous call to collectLinks)
const std::string & getProgramID() const
Returns the ProgramID.
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
TrafficLightType getType() const
get the algorithm type (static etc..)
virtual void setProgramID(const std::string &programID)
Sets the programID.
EdgeVector myIncomingEdges
The list of incoming edges.
virtual void addNode(NBNode *node)
Adds a node to the traffic light logic.
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
SUMOTime getOffset()
Returns the offset.
RightOnRedConflicts myRightOnRedConflicts
TrafficLightType myType
The algorithm type for the traffic light.
EdgeVector myEdgesWithin
The list of edges within the area controlled by the tls.
static const std::string DummyID
id for temporary definitions
int computeBrakingTime(double minDecel) const
Computes the time vehicles may need to brake.
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority, bool sameNodeOnly=false) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
NBTrafficLightLogic * compute(OptionsCont &oc)
Computes the traffic light logic.
NBConnectionVector myControlledLinks
The list of controlled links.
virtual void setParticipantsInformation()
Builds the list of participating nodes/edges/links.
virtual int getMaxIndex()=0
Returns the maximum index controlled by this traffic light and assigned to a connection.
void collectAllLinks(NBConnectionVector &into)
helper method for use in NBOwnTLDef and NBLoadedSUMOTLDef
SUMOTime myOffset
The offset in the program.
static const SUMOTime UNSPECIFIED_DURATION
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
virtual void collectEdges()
Build the list of participating edges.
std::set< std::string > myControlledInnerEdges
Set of inner edges that shall be controlled, though.
The definition of a single phase of the logic.
A SUMO-compliant built logic for a traffic light.
void deleteStateIndex(int index)
remove the index from all phase states
void setPhaseMinDuration(int phaseIndex, SUMOTime duration)
void closeBuilding(bool checkVarDurations=true)
closes the building process
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
void setPhaseState(int phaseIndex, int tlIndex, LinkState linkState)
Modifies the state for an existing phase (used by NETEDIT)
void setPhaseMaxDuration(int phaseIndex, SUMOTime duration)
int getNumLinks()
Returns the number of participating links.
void setType(TrafficLightType type)
set the algorithm type (static etc..)
void addStep(SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", int index=-1)
Adds a phase to the logic.
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
TrafficLightType getType() const
get the algorithm type (static etc..)
void setOffset(SUMOTime offset)
Sets the offset of this tls.
void setProgramID(const std::string &programID)
Sets the programID.
virtual void setID(const std::string &newID)
resets the id
Definition: Named.h:82
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
void updateParameters(const std::map< std::string, std::string > &mapArg)
Adds or updates all given parameters from the map.
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
data structure for caching needsCont information