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.dev/sumo
3 // Copyright (C) 2011-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
20 // A 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 >= myTLLogic->getNumLinks()) {
97  throw ProcessError("Invalid linkIndex " + toString(linkIndex) + " in connection from edge '" + from->getID() +
98  "' to edge '" + to->getID() + "' for traffic light '" + getID() +
99  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
100  }
101  if (linkIndex2 >= myTLLogic->getNumLinks()) {
102  throw ProcessError("Invalid linkIndex2 " + toString(linkIndex2) + " in connection from edge '" + from->getID() +
103  "' to edge '" + to->getID() + "' for traffic light '" + getID() +
104  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
105  }
106  NBConnection conn(from, fromLane, to, toLane, linkIndex, linkIndex2);
107  // avoid duplicates
108  auto newEnd = remove_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(conn));
109  // remove_if does not remove, only re-order
110  myControlledLinks.erase(newEnd, myControlledLinks.end());
111  myControlledLinks.push_back(conn);
112  addNode(from->getToNode());
113  addNode(to->getFromNode());
114  // added connections are definitely controlled. make sure none are removed because they lie within the tl
115  // myControlledInnerEdges.insert(from->getID()); // @todo recheck: this appears to be obsolete
116  // set this information now so that it can be used while loading diffs
117  from->setControllingTLInformation(conn, getID());
118  myReconstructAddedConnections |= reconstruct;
119 }
120 
121 void
122 NBLoadedSUMOTLDef::setID(const std::string& newID) {
123  Named::setID(newID);
124  myTLLogic->setID(newID);
125 }
126 
127 void
128 NBLoadedSUMOTLDef::setProgramID(const std::string& programID) {
130  myTLLogic->setProgramID(programID);
131 }
132 
133 
134 void
140  for (NBNode* const n : myControlledNodes) {
141  n->removeTrafficLight(&dummy);
142  }
143  }
145  return; // will be called again in reconstructLogic()
146  }
147  // if nodes have been removed our links may have been invalidated as well
148  // since no logic will be built anyway there is no reason to inform any edges
149  if (amInvalid()) {
150  return;
151  }
152  // set the information about the link's positions within the tl into the
153  // edges the links are starting at, respectively
154  for (const NBConnection& c : myControlledLinks) {
155  if (c.getTLIndex() >= myTLLogic->getNumLinks()) {
156  throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
157  "' with " + toString(myTLLogic->getNumLinks()) + " links.");
158  }
159  NBEdge* edge = c.getFrom();
160  if (edge != nullptr && edge->getNumLanes() > c.getFromLane()) {
161  // logic may have yet to be reconstructed
163  }
164  }
165 }
166 
167 
168 void
170 
171 
172 void
173 NBLoadedSUMOTLDef::replaceRemoved(NBEdge* removed, int removedLane, NBEdge* by, int byLane, bool incoming) {
174  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
175  if (incoming) {
176  (*it).replaceFrom(removed, removedLane, by, byLane);
177  } else {
178  (*it).replaceTo(removed, removedLane, by, byLane);
179  }
180  }
181 }
182 
183 
184 void
185 NBLoadedSUMOTLDef::addPhase(const SUMOTime duration, const std::string& state, const SUMOTime minDur, const SUMOTime maxDur,
186  const SUMOTime earliestEnd, const SUMOTime latestEnd, const SUMOTime vehExt, const SUMOTime yellow,
187  const SUMOTime red, const std::vector<int>& next, const std::string& name) {
188  myTLLogic->addStep(duration, state, minDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, name, next);
189 }
190 
191 
192 bool
194  if (myControlledLinks.size() == 0) {
195  return true;
196  }
197  if (myIncomingEdges.size() == 0) {
198  return true;
199  }
200  return false;
201 }
202 
203 
204 void
205 NBLoadedSUMOTLDef::removeConnection(const NBConnection& conn, bool reconstruct) {
206  for (auto it = myControlledLinks.begin(); it != myControlledLinks.end();) {
207  if ((it->getFrom() == conn.getFrom() &&
208  it->getTo() == conn.getTo() &&
209  it->getFromLane() == conn.getFromLane() &&
210  it->getToLane() == conn.getToLane())
211  || (it->getTLIndex() == conn.getTLIndex() &&
212  conn.getTLIndex() != conn.InvalidTlIndex &&
213  (it->getFrom() == nullptr || it->getTo() == nullptr))) {
214  if (reconstruct) {
216  it++;
217  } else {
218  it = myControlledLinks.erase(it);
219  }
220  } else {
221  it++;
222  }
223  }
224 }
225 
226 
227 void
229  myOffset = offset;
230  myTLLogic->setOffset(offset);
231 }
232 
233 
234 void
236  myType = type;
237  myTLLogic->setType(type);
238 }
239 
240 
241 void
243  if (myControlledLinks.size() == 0) {
245  }
246  myIncomingEdges.clear();
247  EdgeVector myOutgoing;
248  // collect the edges from the participating nodes
249  for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
250  const EdgeVector& incoming = (*i)->getIncomingEdges();
251  copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
252  const EdgeVector& outgoing = (*i)->getOutgoingEdges();
253  copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
254  }
255  // check which of the edges are completely within the junction
256  // and which are uncontrolled as well (we already know myControlledLinks)
257  for (EdgeVector::iterator j = myIncomingEdges.begin(); j != myIncomingEdges.end();) {
258  NBEdge* edge = *j;
259  edge->setInsideTLS(false); // reset
260  // an edge lies within the logic if it is outgoing as well as incoming
261  EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
262  if (k != myOutgoing.end()) {
263  if (myControlledInnerEdges.count(edge->getID()) == 0) {
264  bool controlled = false;
265  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
266  if ((*it).getFrom() == edge) {
267  controlled = true;
268  break;
269  }
270  }
271  if (controlled) {
272  myControlledInnerEdges.insert(edge->getID());
273  } else {
274  myEdgesWithin.push_back(edge);
275  edge->setInsideTLS(true);
276  ++j; //j = myIncomingEdges.erase(j);
277  continue;
278  }
279  }
280  }
281  ++j;
282  }
283 }
284 
285 
286 void
288  if (myControlledLinks.size() == 0) {
289  // maybe we only loaded a different program for a default traffic light.
290  // Try to build links now.
292  }
293 }
294 
295 
297 void
298 NBLoadedSUMOTLDef::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
299  // avoid shifting twice if the edge is incoming and outgoing to a joined TLS
300  if (myShifted.count(edge) == 0) {
302  myShifted.insert(edge);
303  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
304  (*it).shiftLaneIndex(edge, offset, threshold);
305  }
306  }
307 }
308 
309 void
311  const int size = myTLLogic->getNumLinks();
312  int noLinksAll = 0;
313  for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
314  const NBConnection& c = *it;
316  noLinksAll = MAX2(noLinksAll, (int)c.getTLIndex() + 1);
317  }
318  }
319  const int numNormalLinks = noLinksAll;
320  int oldCrossings = 0;
321  // collect crossings
322  bool customIndex = false;
323  std::vector<NBNode::Crossing*> crossings;
324  for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
325  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
326  // set tl indices for crossings
327  customIndex |= (*i)->setCrossingTLIndices(getID(), noLinksAll);
328  copy(c.begin(), c.end(), std::back_inserter(crossings));
329  noLinksAll += (int)c.size();
330  oldCrossings += (*i)->numCrossingsFromSumoNet();
331  }
332  if ((int)crossings.size() != oldCrossings) {
333  std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
334  // do not rebuilt crossing states there are custom indices and the state string is long enough
335  if (phases.size() > 0 && (
336  (int)(phases.front().state.size()) < noLinksAll ||
337  ((int)(phases.front().state.size()) > noLinksAll && !customIndex))) {
338  // collect edges
339  EdgeVector fromEdges(size, (NBEdge*)nullptr);
340  EdgeVector toEdges(size, (NBEdge*)nullptr);
341  std::vector<int> fromLanes(size, 0);
342  collectEdgeVectors(fromEdges, toEdges, fromLanes);
343  const std::string crossingDefaultState(crossings.size(), 'r');
344 
345  // rebuild the logic (see NBOwnTLDef.cpp::myCompute)
347  SUMOTime brakingTime = TIME2STEPS(computeBrakingTime(OptionsCont::getOptions().getFloat("tls.yellow.min-decel")));
348  //std::cout << "patchIfCrossingsAdded for " << getID() << " numPhases=" << phases.size() << "\n";
349  for (const auto& phase : phases) {
350  const std::string state = phase.state.substr(0, numNormalLinks) + crossingDefaultState;
351  NBOwnTLDef::addPedestrianPhases(newLogic, phase.duration, phase.minDur, phase.maxDur, phase.earliestEnd, phase.latestEnd,
352  state, crossings, fromEdges, toEdges);
353  }
354  NBOwnTLDef::addPedestrianScramble(newLogic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
355 
356  delete myTLLogic;
357  myTLLogic = newLogic;
358  } else if (phases.size() == 0) {
359  WRITE_WARNINGF(TL("Could not patch tlLogic '%' for changed crossings"), getID());
360  }
361  }
362 }
363 
364 
365 void
366 NBLoadedSUMOTLDef::collectEdgeVectors(EdgeVector& fromEdges, EdgeVector& toEdges, std::vector<int>& fromLanes) const {
367  assert(fromEdges.size() > 0);
368  assert(fromEdges.size() == toEdges.size());
369  const int size = (int)fromEdges.size();
370 
371  for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
372  const NBConnection& c = *it;
374  if (c.getTLIndex() >= size) {
375  throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
376  "' with " + toString(size) + " links.");
377  }
378  fromEdges[c.getTLIndex()] = c.getFrom();
379  toEdges[c.getTLIndex()] = c.getTo();
380  fromLanes[c.getTLIndex()] = c.getFromLane();
381  }
382  }
383 }
384 
385 
386 void
388  if (!amInvalid() && !myNeedsContRelationReady) {
389  myNeedsContRelation.clear();
390  myRightOnRedConflicts.clear();
394  } else {
395  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
396  const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
397  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
398  const std::string state = (*it).state;
399  for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
400  const NBConnection& c1 = *it1;
401  const int i1 = c1.getTLIndex();
402  if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
403  continue;
404  }
405  for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
406  const NBConnection& c2 = *it2;
407  const int i2 = c2.getTLIndex();
409  && i2 != i1
410  && (state[i2] == 'G' || state[i2] == 'g')
411  && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
412  const bool rightTurnConflict = NBNode::rightTurnConflict(
413  c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
414  const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
415  const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
416  if (forbidden || rightTurnConflict) {
417  myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
418  }
419  if (isFoes && state[i1] == 's') {
420  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
421  //std::cout << getID() << " prog=" << getProgramID() << " phase=" << (it - phases.begin()) << " rightOnRedConflict i1=" << i1 << " i2=" << i2 << "\n";
422  }
423  //std::cout << getID() << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
424  }
425  }
426  }
427  }
428  }
429  }
432 }
433 
434 
435 bool
436 NBLoadedSUMOTLDef::rightOnRedConflict(int index, int foeIndex) const {
437  if (amInvalid()) {
438  return false;
439  }
443  }
444  return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
445 }
446 
447 
448 void
449 NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
450  myReconstructAddedConnections |= addedConnections;
451  myReconstructRemovedConnections |= removedConnections;
452 }
453 
454 void
456  const bool netedit = NBNetBuilder::runningNetedit();
457 #ifdef DEBUG_RECONSTRUCTION
459  std::cout << getID() << " reconstructLogic added=" << myReconstructAddedConnections
460  << " removed=" << myReconstructRemovedConnections
461  << " valid=" << hasValidIndices()
462  << " phasesLoaded=" << myPhasesLoaded
463  << " oldLinks:\n";
464  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
465  std::cout << " " << *it << "\n";
466  }
467 #endif
470  // do not rebuild the logic when running netedit and all links are already covered by the program
471  if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
472  // rebuild the logic from scratch
473  // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
476  dummy.setProgramID(getProgramID());
481  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
482  (*i)->removeTrafficLight(&dummy);
483  }
484  delete myTLLogic;
485  myTLLogic = newLogic;
486  if (newLogic != nullptr) {
487  newLogic->setID(getID());
488  newLogic->setType(getType());
489  newLogic->setOffset(getOffset());
491  // reset crossing custom indices
492  for (NBNode* n : myControlledNodes) {
493  for (NBNode::Crossing* c : n->getCrossings()) {
494  c->customTLIndex = NBConnection::InvalidTlIndex;
495  }
496  }
497 
498  }
499  } else {
501  }
502  }
505  // for each connection, check whether it is still valid
506  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
507  const NBConnection con = (*it);
508  if (// edge still exists
509  std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
510  // connection still exists
511  && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
512  // connection is still set to be controlled
513  && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane())) {
514  it++;
515  } else {
516  // remove connection
517  const int removed = con.getTLIndex();
518  it = myControlledLinks.erase(it);
519  // no automatic modificaions when running netedit
520  if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
521  // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
522  bool exclusive = true;
523  for (NBConnection& other : myControlledLinks) {
524  if (other != con && other.getTLIndex() == removed) {
525  exclusive = false;
526  break;
527  }
528  }
529  if (exclusive) {
530  // shift indices above the removed index downward
531  for (NBConnection& other : myControlledLinks) {
532  if (other.getTLIndex() > removed) {
533  other.setTLIndex(other.getTLIndex() - 1);
534  }
535  }
536  // shift crossing custom indices above the removed index downward
537  for (NBNode* n : myControlledNodes) {
538  for (NBNode::Crossing* c : n->getCrossings()) {
539  if (c->customTLIndex > removed) {
540  c->customTLIndex--;
541  }
542  }
543  }
544  // rebuild the logic
547  std::string newState = phase.state;
548  newState.erase(newState.begin() + removed);
549  newLogic->addStep(phase.duration, newState);
550  }
551  delete myTLLogic;
552  myTLLogic = newLogic;
553  }
554  }
555  }
556  }
558  }
559 #ifdef DEBUG_RECONSTRUCTION
560  if (debugPrintModified) {
561  std::cout << " newLinks:\n";
562  for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
563  std::cout << " " << *it << "\n";
564  }
565  }
566 #endif
567 }
568 
569 
570 int
572  int maxIndex = -1;
573  for (const NBConnection& c : myControlledLinks) {
574  maxIndex = MAX2(maxIndex, c.getTLIndex());
575  maxIndex = MAX2(maxIndex, c.getTLIndex2());
576  }
577  for (NBNode* n : myControlledNodes) {
578  for (NBNode::Crossing* c : n->getCrossings()) {
579  maxIndex = MAX2(maxIndex, c->tlLinkIndex);
580  maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
581  }
582  }
583  return maxIndex;
584 }
585 
586 
587 int
589  return myTLLogic->getNumLinks() - 1;
590 }
591 
592 
593 bool
595  for (const NBConnection& c : myControlledLinks) {
596  if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
597  return false;
598  }
599  }
600  for (NBNode* n : myControlledNodes) {
601  for (NBNode::Crossing* c : n->getCrossings()) {
602  if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
603  return false;
604  }
605  }
606  }
607  // method getMaxIndex() is const but cannot be declare as such due to inheritance
608  return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
609 }
610 
611 
612 std::string
614  assert(index >= 0);
615  assert(index <= getMaxValidIndex());
616  std::string result;
617  for (auto& pd : myTLLogic->getPhases()) {
618  result += pd.state[index];
619  }
620  return result;
621 }
622 
623 bool
624 NBLoadedSUMOTLDef::isUsed(int index) const {
625  for (const NBConnection& c : myControlledLinks) {
626  if (c.getTLIndex() == index || c.getTLIndex2() == index) {
627  return true;
628  }
629  }
630  for (NBNode* n : myControlledNodes) {
631  for (NBNode::Crossing* c : n->getCrossings()) {
632  if (c->tlLinkIndex == index || c->tlLinkIndex2 == index) {
633  return true;
634  }
635  }
636  }
637  return false;
638 }
639 
640 std::set<const NBEdge*>
642  std::set<const NBEdge*> result;
643  for (const NBConnection& c : myControlledLinks) {
644  if (c.getTLIndex() == index || c.getTLIndex2() == index) {
645  result.insert(c.getFrom());
646  }
647  }
648  return result;
649 }
650 
651 
652 void
653 NBLoadedSUMOTLDef::replaceIndex(int oldIndex, int newIndex) {
654  if (oldIndex == newIndex) {
655  return;
656  }
657  for (NBConnection& c : myControlledLinks) {
658  if (c.getTLIndex() == oldIndex) {
659  c.setTLIndex(newIndex);
660  }
661  if (c.getTLIndex2() == oldIndex) {
662  c.setTLIndex2(newIndex);
663  }
664  }
665  for (NBNode* n : myControlledNodes) {
666  for (NBNode::Crossing* c : n->getCrossings()) {
667  if (c->tlLinkIndex == oldIndex) {
668  c->tlLinkIndex = newIndex;
669  }
670  if (c->tlLinkIndex2 == oldIndex) {
671  c->tlLinkIndex2 = newIndex;
672  }
673  }
674  }
675 }
676 
677 void
679  const int maxIndex = getMaxIndex();
680  std::vector<int> unusedIndices;
681  for (int i = 0; i <= maxIndex; i++) {
682  if (isUsed(i)) {
683  std::set<const NBEdge*> edges = getEdgesUsingIndex(i);
684  // compactify
685  replaceIndex(i, i - (int)unusedIndices.size());
686  if (edges.size() == 0) {
687  // do not group pedestrian crossing signals
688  continue;
689  }
690  std::string states = getStates(i);
691  for (int j = i + 1; j <= maxIndex; j++) {
692  // only group signals from the same edges as is commonly done by
693  // traffic engineers
694  if (states == getStates(j) && edges == getEdgesUsingIndex(j)) {
695  replaceIndex(j, i - (int)unusedIndices.size());
696  }
697  }
698  } else {
699  unusedIndices.push_back(i);
700  }
701  }
702  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
703  myTLLogic->deleteStateIndex(unusedIndices[i]);
704  }
705  cleanupStates();
706  //std::cout << "oldMaxIndex=" << maxIndex << " newMaxIndex=" << getMaxIndex() << " unused=" << toString(unusedIndices) << "\n";
708  // patch crossing indices
709  for (NBNode* n : myControlledNodes) {
710  for (NBNode::Crossing* c : n->getCrossings()) {
711  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
712  if (c->customTLIndex > i) {
713  c->customTLIndex--;
714  }
715  if (c->customTLIndex2 > i) {
716  c->customTLIndex2--;
717  }
718  }
719  }
720  }
721 }
722 
723 void
725  NBConnectionVector defaultOrdering;
726  collectAllLinks(defaultOrdering);
727  std::vector<std::string> states; // organized per link rather than phase
728  int index = 0;
729  for (NBConnection& c : defaultOrdering) {
730  NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
731  states.push_back(getStates(c2.getTLIndex()));
732  c2.setTLIndex(index++);
733  }
734  for (NBNode* n : myControlledNodes) {
735  for (NBNode::Crossing* c : n->getCrossings()) {
736  states.push_back(getStates(c->tlLinkIndex));
737  c->customTLIndex = index++;
738  if (c->tlLinkIndex2 != NBConnection::InvalidTlIndex) {
739  states.push_back(getStates(c->tlLinkIndex2));
740  c->customTLIndex2 = index++;
741  }
742  }
743  }
744  myTLLogic->setStateLength(index);
745  for (int i = 0; i < (int)states.size(); i++) {
746  for (int p = 0; p < (int)states[i].size(); p++) {
747  myTLLogic->setPhaseState(p, i, (LinkState)states[i][p]);
748  }
749  }
751 }
752 
753 
754 void
756  std::map<int, std::string> oldStates; // organized per link index rather than phase
757  std::map<int, std::string> newStates; // organized per link index rather than phase
758  for (NBConnection& c : def->getControlledLinks()) {
759  NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
760  const int oldIndex = c2.getTLIndex();
761  const int newIndex = c.getTLIndex();
762  std::string states = getStates(oldIndex);
763  oldStates[oldIndex] = states;
764  if (newStates.count(newIndex) != 0 && newStates[newIndex] != states) {
765  WRITE_WARNING("Signal groups from program '" + def->getProgramID() + "' are incompatible with the states of program '" + getProgramID() + "' at tlLogic '" + getID()
766  + "'. Possibly unsafe program.");
767  } else {
768  newStates[newIndex] = states;
769  }
770  c2.setTLIndex(newIndex);
771  }
772  const int maxIndex = getMaxIndex();
773  myTLLogic->setStateLength(maxIndex + 1);
774  for (int i = 0; i < (int)newStates.size(); i++) {
775  for (int p = 0; p < (int)newStates[i].size(); p++) {
776  myTLLogic->setPhaseState(p, i, (LinkState)newStates[i][p]);
777  }
778  }
780 }
781 
782 
783 bool
785  const int maxIndex = getMaxValidIndex();
786  std::vector<int> unusedIndices;
787  for (int i = 0; i <= maxIndex; i++) {
788  if (isUsed(i)) {
789  if (unusedIndices.size() > 0) {
790  replaceIndex(i, i - (int)unusedIndices.size());
791  }
792  } else {
793  unusedIndices.push_back(i);
794  }
795  }
796  for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
797  myTLLogic->deleteStateIndex(unusedIndices[i]);
798  }
799  if (unusedIndices.size() > 0) {
800  myTLLogic->setStateLength(maxIndex + 1 - (int)unusedIndices.size());
802  return true;
803  } else {
804  return false;
805  }
806 }
807 
808 
809 void
813  const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
814  myTLLogic->setStateLength(maxIndex + 1);
815  myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
816 }
817 
818 bool
820  // count how often each index is used
821  std::map<int, int> indexUsage;
822  for (const NBConnection& c : myControlledLinks) {
823  indexUsage[c.getTLIndex()]++;
824  }
825  for (NBNode* n : myControlledNodes) {
826  for (NBNode::Crossing* c : n->getCrossings()) {
827  indexUsage[c->tlLinkIndex]++;
828  indexUsage[c->tlLinkIndex2]++;
829  }
830  }
831  for (auto it : indexUsage) {
832  if (it.first >= 0 && it.second > 1) {
833  return true;
834  }
835  }
836  return false;
837 }
838 
839 void
841  bool hasMinMaxDur = false;
842  for (auto phase : myTLLogic->getPhases()) {
843  if (phase.maxDur != UNSPECIFIED_DURATION) {
844  //std::cout << " phase=" << phase.state << " maxDur=" << phase.maxDur << "\n";
845  hasMinMaxDur = true;
846  }
847  }
848  if (!hasMinMaxDur) {
849  const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
850  const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
851  std::set<int> yellowIndices;
852  for (auto phase : myTLLogic->getPhases()) {
853  for (int i = 0; i < (int)phase.state.size(); i++) {
854  if (phase.state[i] == 'y' || phase.state[i] == 'Y') {
855  yellowIndices.insert(i);
856  }
857  }
858  }
859  for (int ip = 0; ip < (int)myTLLogic->getPhases().size(); ip++) {
860  bool needMinMaxDur = false;
861  auto phase = myTLLogic->getPhases()[ip];
862  std::set<int> greenIndices;
863  if (phase.state.find_first_of("yY") != std::string::npos) {
864  continue;
865  }
866  for (int i = 0; i < (int)phase.state.size(); i++) {
867  if (yellowIndices.count(i) != 0 && phase.state[i] == 'G') {
868  needMinMaxDur = true;
869  greenIndices.insert(i);
870  }
871  }
872  if (needMinMaxDur) {
873  double maxSpeed = 0;
874  for (NBConnection& c : myControlledLinks) {
875  if (greenIndices.count(c.getTLIndex()) != 0) {
876  maxSpeed = MAX2(maxSpeed, c.getFrom()->getLaneSpeed(c.getFromLane()));
877  }
878  }
879  // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
880  const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
881  SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
882  myTLLogic->setPhaseMinDuration(ip, minDur);
883  myTLLogic->setPhaseMaxDuration(ip, maxDur);
884  }
885  }
886  }
887 }
888 
889 
890 void
892  for (int i = 0; i < myTLLogic->getNumLinks(); i++) {
893  if (!isUsed(i)) {
894  WRITE_WARNINGF(TL("Unused state in tlLogic '%', program '%' at tl-index %"), getID(), getProgramID(), i);
895  break;
896  }
897  }
898 }
899 
900 
901 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
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:57
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:82
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:92
void setInsideTLS(bool inside)
Marks this edge being within an intersection.
Definition: NBEdge.h:1135
const std::string & getID() const
Definition: NBEdge.h:1522
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:542
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3656
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3594
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:516
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:3645
bool hasConnectionTo(const NBEdge *destEdge, int destLane, int fromLane=-1) const
Retrieves info about a connection to a certain lane of a certain edge.
Definition: NBEdge.cpp:1290
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:535
class for identifying connections
A loaded (complete) traffic light logic.
bool isUsed(int index) const
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.
void setID(const std::string &newID)
resets the id
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.
void addPhase(const SUMOTime duration, const std::string &state, const SUMOTime minDur, const SUMOTime maxDur, const SUMOTime earliestEnd, const SUMOTime latestEnd, const SUMOTime vehExt, const SUMOTime yellow, const SUMOTime red, 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.
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 occurrences 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 finalChecks() const
perform optional final checks (on writing)
~NBLoadedSUMOTLDef()
Destructor.
void initNeedsContRelation() const
initialize myNeedsContRelation and set myNeedsContRelationReady to true
static bool runningNetedit()
whether netbuilding takes place in the context of netedit
A definition of a pedestrian crossing.
Definition: NBNode.h:135
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:2034
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
static void addPedestrianScramble(NBTrafficLightLogic *logic, int totalNumLinks, 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
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur, const SUMOTime earliestEnd, const SUMOTime latestEnd, 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:893
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
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.
virtual void initRightOnRedConflicts() const
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.
NBTrafficLightLogic * compute(const OptionsCont &oc)
Computes 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.
NBConnectionVector myControlledLinks
The list of controlled links.
virtual void initNeedsContRelation() const
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)
Modifies the min duration for an existing phase (used by netedit)
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)
Modifies the max duration for an existing phase (used by netedit)
int getNumLinks()
Returns the number of participating links.
void setType(TrafficLightType type)
set the algorithm type (static etc..)
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 addStep(const SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", const int index=-1)
Adds a phase to the logic (static)
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:60
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
void updateParameters(const Parameterised::Map &mapArg)
Adds or updates all given parameters from the map.
data structure for caching needsCont information