Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2025 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>
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
46NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(const std::string& id, const std::string& programID,
47 SUMOTime offset, TrafficLightType type) :
48 NBTrafficLightDefinition(id, programID, offset, type),
49 myTLLogic(nullptr),
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()),
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
79
80
82NBLoadedSUMOTLDef::myCompute(int brakingTimeSeconds) {
83 // @todo what to do with those parameters?
84 UNUSED_PARAMETER(brakingTimeSeconds);
87 myTLLogic->closeBuilding(false);
89 myTLLogic->closeBuilding();
91}
92
93
94void
95NBLoadedSUMOTLDef::addConnection(NBEdge* from, NBEdge* to, int fromLane, int toLane, int linkIndex, int linkIndex2, bool reconstruct) {
96 assert(myTLLogic->getNumLinks() > 0); // logic should be loaded by now
97 if (linkIndex >= myTLLogic->getNumLinks()) {
98 throw ProcessError("Invalid linkIndex " + toString(linkIndex) + " in connection from edge '" + from->getID() +
99 "' to edge '" + to->getID() + "' for traffic light '" + getID() +
100 "' with " + toString(myTLLogic->getNumLinks()) + " links.");
101 }
102 if (linkIndex2 >= myTLLogic->getNumLinks()) {
103 throw ProcessError("Invalid linkIndex2 " + toString(linkIndex2) + " in connection from edge '" + from->getID() +
104 "' to edge '" + to->getID() + "' for traffic light '" + getID() +
105 "' with " + toString(myTLLogic->getNumLinks()) + " links.");
106 }
107 NBConnection conn(from, fromLane, to, toLane, linkIndex, linkIndex2);
108 // avoid duplicates
109 auto newEnd = remove_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(conn));
110 // remove_if does not remove, only re-order
111 myControlledLinks.erase(newEnd, myControlledLinks.end());
112 myControlledLinks.push_back(conn);
113 addNode(from->getToNode());
114 addNode(to->getFromNode());
115 // added connections are definitely controlled. make sure none are removed because they lie within the tl
116 // myControlledInnerEdges.insert(from->getID()); // @todo recheck: this appears to be obsolete
117 // set this information now so that it can be used while loading diffs
118 from->setControllingTLInformation(conn, getID());
119 myReconstructAddedConnections |= reconstruct;
120}
121
122void
123NBLoadedSUMOTLDef::setID(const std::string& newID) {
124 Named::setID(newID);
125 myTLLogic->setID(newID);
126}
127
128void
129NBLoadedSUMOTLDef::setProgramID(const std::string& programID) {
131 myTLLogic->setProgramID(programID);
132}
133
134
135void
141 for (NBNode* const n : myControlledNodes) {
142 n->removeTrafficLight(&dummy);
143 }
144 }
146 return; // will be called again in reconstructLogic()
147 }
148 // if nodes have been removed our links may have been invalidated as well
149 // since no logic will be built anyway there is no reason to inform any edges
150 if (amInvalid()) {
151 return;
152 }
153 // set the information about the link's positions within the tl into the
154 // edges the links are starting at, respectively
155 for (const NBConnection& c : myControlledLinks) {
156 if (c.getTLIndex() >= myTLLogic->getNumLinks()) {
157 throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
158 "' with " + toString(myTLLogic->getNumLinks()) + " links.");
159 }
160 NBEdge* edge = c.getFrom();
161 if (edge != nullptr && edge->getNumLanes() > c.getFromLane()) {
162 // logic may have yet to be reconstructed
164 }
165 }
166}
167
168
169void
171
172
173void
174NBLoadedSUMOTLDef::replaceRemoved(NBEdge* removed, int removedLane, NBEdge* by, int byLane, bool incoming) {
175 if (by == nullptr) {
177 }
178 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
179 if (incoming) {
180 (*it).replaceFrom(removed, removedLane, by, byLane);
181 } else {
182 (*it).replaceTo(removed, removedLane, by, byLane);
183 }
184 }
185}
186
187
188void
189NBLoadedSUMOTLDef::addPhase(const SUMOTime duration, const std::string& state, const SUMOTime minDur, const SUMOTime maxDur,
190 const SUMOTime earliestEnd, const SUMOTime latestEnd, const SUMOTime vehExt, const SUMOTime yellow,
191 const SUMOTime red, const std::vector<int>& next, const std::string& name) {
192 myTLLogic->addStep(duration, state, minDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, name, next);
193}
194
195
196bool
198 if (myControlledLinks.size() == 0) {
199 return true;
200 }
201 if (myIncomingEdges.size() == 0) {
202 return true;
203 }
205 // check whether at least one connection is valid
206 for (const NBConnection& con : myControlledLinks) {
207 if (isValid(con)) {
208 return false;
209 }
210 }
211 // all invalid
212 return true;
213 }
214 return false;
215}
216
217
218void
219NBLoadedSUMOTLDef::removeConnection(const NBConnection& conn, bool reconstruct) {
220 for (auto it = myControlledLinks.begin(); it != myControlledLinks.end();) {
221 if ((it->getFrom() == conn.getFrom() &&
222 it->getTo() == conn.getTo() &&
223 it->getFromLane() == conn.getFromLane() &&
224 it->getToLane() == conn.getToLane())
225 || (it->getTLIndex() == conn.getTLIndex() &&
226 conn.getTLIndex() != conn.InvalidTlIndex &&
227 (it->getFrom() == nullptr || it->getTo() == nullptr))) {
228 if (reconstruct) {
230 it++;
231 } else {
232 it = myControlledLinks.erase(it);
233 }
234 } else {
235 it++;
236 }
237 }
238}
239
240
241void
243 myOffset = offset;
244 myTLLogic->setOffset(offset);
245}
246
247
248void
250 myType = type;
251 myTLLogic->setType(type);
252}
253
254
255void
257 if (myControlledLinks.size() == 0) {
259 }
260 myIncomingEdges.clear();
261 EdgeVector myOutgoing;
262 // collect the edges from the participating nodes
263 for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
264 const EdgeVector& incoming = (*i)->getIncomingEdges();
265 copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
266 const EdgeVector& outgoing = (*i)->getOutgoingEdges();
267 copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
268 }
269 // check which of the edges are completely within the junction
270 // and which are uncontrolled as well (we already know myControlledLinks)
271 for (EdgeVector::iterator j = myIncomingEdges.begin(); j != myIncomingEdges.end();) {
272 NBEdge* edge = *j;
273 edge->setInsideTLS(false); // reset
274 // an edge lies within the logic if it is outgoing as well as incoming
275 EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
276 if (k != myOutgoing.end()) {
277 if (myControlledInnerEdges.count(edge->getID()) == 0) {
278 bool controlled = false;
279 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
280 if ((*it).getFrom() == edge) {
281 controlled = true;
282 break;
283 }
284 }
285 if (controlled) {
286 myControlledInnerEdges.insert(edge->getID());
287 } else {
288 myEdgesWithin.push_back(edge);
289 edge->setInsideTLS(true);
290 ++j; //j = myIncomingEdges.erase(j);
291 continue;
292 }
293 }
294 }
295 ++j;
296 }
297}
298
299
300void
302 if (myControlledLinks.size() == 0) {
303 // maybe we only loaded a different program for a default traffic light.
304 // Try to build links now.
306 }
307}
308
309
311void
312NBLoadedSUMOTLDef::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
313 // avoid shifting twice if the edge is incoming and outgoing to a joined TLS
314 if (myShifted.count(edge) == 0) {
316 myShifted.insert(edge);
317 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
318 (*it).shiftLaneIndex(edge, offset, threshold);
319 }
320 }
321}
322
323void
325 const int size = myTLLogic->getNumLinks();
326 int noLinksAll = 0;
327 for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
328 const NBConnection& c = *it;
330 noLinksAll = MAX2(noLinksAll, (int)c.getTLIndex() + 1);
331 }
332 }
333 const int numNormalLinks = noLinksAll;
334 int oldCrossings = 0;
335 // collect crossings
336 bool customIndex = false;
337 std::vector<NBNode::Crossing*> crossings;
338 for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
339 const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
340 // set tl indices for crossings
341 customIndex |= (*i)->setCrossingTLIndices(getID(), noLinksAll);
342 copy(c.begin(), c.end(), std::back_inserter(crossings));
343 noLinksAll += (int)c.size();
344 oldCrossings += (*i)->numCrossingsFromSumoNet();
345 }
346 if ((int)crossings.size() != oldCrossings) {
347 std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
348 // do not rebuilt crossing states there are custom indices and the state string is long enough
349 if (phases.size() > 0 && (
350 (int)(phases.front().state.size()) < noLinksAll ||
351 ((int)(phases.front().state.size()) > noLinksAll && !customIndex))) {
352 // collect edges
353 EdgeVector fromEdges(size, (NBEdge*)nullptr);
354 EdgeVector toEdges(size, (NBEdge*)nullptr);
355 std::vector<int> fromLanes(size, 0);
356 collectEdgeVectors(fromEdges, toEdges, fromLanes);
357 const std::string crossingDefaultState(crossings.size(), 'r');
358
359 // rebuild the logic (see NBOwnTLDef.cpp::myCompute)
361 SUMOTime brakingTime = TIME2STEPS(computeBrakingTime(OptionsCont::getOptions().getFloat("tls.yellow.min-decel")));
362 //std::cout << "patchIfCrossingsAdded for " << getID() << " numPhases=" << phases.size() << "\n";
363 for (const auto& phase : phases) {
364 const std::string state = phase.state.substr(0, numNormalLinks) + crossingDefaultState;
365 NBOwnTLDef::addPedestrianPhases(newLogic, phase.duration, phase.minDur, phase.maxDur, phase.earliestEnd, phase.latestEnd,
366 state, crossings, fromEdges, toEdges);
367 }
368 NBOwnTLDef::addPedestrianScramble(newLogic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
369
370 delete myTLLogic;
371 myTLLogic = newLogic;
372 } else if (phases.size() == 0) {
373 WRITE_WARNINGF(TL("Could not patch tlLogic '%' for changed crossings"), getID());
374 }
375 }
376}
377
378
379void
380NBLoadedSUMOTLDef::collectEdgeVectors(EdgeVector& fromEdges, EdgeVector& toEdges, std::vector<int>& fromLanes) const {
381 assert(fromEdges.size() > 0);
382 assert(fromEdges.size() == toEdges.size());
383 const int size = (int)fromEdges.size();
384
385 for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
386 const NBConnection& c = *it;
388 if (c.getTLIndex() >= size) {
389 throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
390 "' with " + toString(size) + " links.");
391 }
392 fromEdges[c.getTLIndex()] = c.getFrom();
393 toEdges[c.getTLIndex()] = c.getTo();
394 fromLanes[c.getTLIndex()] = c.getFromLane();
395 }
396 }
397}
398
399
400void
403 myNeedsContRelation.clear();
404 myExtraConflicts.clear();
408 } else {
409 const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
410 const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
411 for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
412 const std::string state = (*it).state;
413 for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
414 const NBConnection& c1 = *it1;
415 const int i1 = c1.getTLIndex();
416 if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
417 continue;
418 }
419 for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
420 const NBConnection& c2 = *it2;
421 const int i2 = c2.getTLIndex();
423 && i2 != i1
424 && (state[i2] == 'G' || state[i2] == 'g')
425 && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
426 const bool rightTurnConflict = NBNode::rightTurnConflict(
427 c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
428 const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
429 const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
430 const bool hasContRel = (forbidden && state[i1] != 's') || rightTurnConflict;
431 if (hasContRel) {
432 myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
433 }
434 const bool indirectLeft = c1.getFrom()->getConnection(c1.getFromLane(), c1.getTo(), c1.getToLane()).indirectLeft;
435 if (isFoes && (state[i1] == 's' || (!hasContRel && state[i2] == 'G' && !indirectLeft))) {
436 myExtraConflicts.insert(std::make_pair(i1, i2));
437 //std::cout << getID() << " prog=" << getProgramID() << " phase=" << (it - phases.begin()) << " extraConflict i1=" << i1 << " i2=" << i2
438 // << " c1=" << c1 << " c2=" << c2 << "\n";
439 }
440 //std::cout << getID() << " p=" << (it - phases.begin()) << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
441 }
442 }
443 }
444 }
445 }
446 }
449}
450
451
452bool
453NBLoadedSUMOTLDef::extraConflict(int index, int foeIndex) const {
454 if (amInvalid()) {
455 return false;
456 }
459 assert(myExtraConflictsReady);
460 }
461 return std::find(myExtraConflicts.begin(), myExtraConflicts.end(), std::make_pair(index, foeIndex)) != myExtraConflicts.end();
462}
463
464
465void
466NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
467 myReconstructAddedConnections |= addedConnections;
468 myReconstructRemovedConnections |= removedConnections;
469}
470
471bool
473 return (// edge still exists
474 std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
475 // connection still exists
476 && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
477 // connection is still set to be controlled
478 && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane()));
479}
480
481void
483 const bool netedit = NBNetBuilder::runningNetedit();
484#ifdef DEBUG_RECONSTRUCTION
486 std::cout << getID() << " reconstructLogic added=" << myReconstructAddedConnections
487 << " removed=" << myReconstructRemovedConnections
488 << " valid=" << hasValidIndices()
489 << " phasesLoaded=" << myPhasesLoaded
490 << " oldLinks:\n";
491 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
492 std::cout << " " << *it << "\n";
493 }
494#endif
497 // do not rebuild the logic when running netedit and all links are already covered by the program
498 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
499 // rebuild the logic from scratch
500 // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
503 dummy.setProgramID(getProgramID());
508 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
509 (*i)->removeTrafficLight(&dummy);
510 }
511 delete myTLLogic;
512 myTLLogic = newLogic;
513 if (newLogic != nullptr) {
514 newLogic->setID(getID());
515 newLogic->setType(getType());
516 newLogic->setOffset(getOffset());
518 // reset crossing custom indices
519 for (NBNode* n : myControlledNodes) {
520 for (NBNode::Crossing* c : n->getCrossings()) {
521 c->customTLIndex = NBConnection::InvalidTlIndex;
522 }
523 }
524
525 }
526 } else {
528 }
529 }
532 // for each connection, check whether it is still valid
533 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
534 const NBConnection con = (*it);
535 if (isValid(con)) {
536 it++;
537 } else {
538 // remove connection
539 const int removed = con.getTLIndex();
540 it = myControlledLinks.erase(it);
541 // no automatic modificaions when running netedit
542 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
543 // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
544 bool exclusive = true;
545 for (NBConnection& other : myControlledLinks) {
546 if (other != con && other.getTLIndex() == removed) {
547 exclusive = false;
548 break;
549 }
550 }
551 if (exclusive) {
552 // shift indices above the removed index downward
553 for (NBConnection& other : myControlledLinks) {
554 if (other.getTLIndex() > removed) {
555 other.setTLIndex(other.getTLIndex() - 1);
556 }
557 }
558 // shift crossing custom indices above the removed index downward
559 for (NBNode* n : myControlledNodes) {
560 for (NBNode::Crossing* c : n->getCrossings()) {
561 if (c->customTLIndex > removed) {
562 c->customTLIndex--;
563 }
564 }
565 }
566 // rebuild the logic
568 for (const NBTrafficLightLogic::PhaseDefinition& phase : myTLLogic->getPhases()) {
569 std::string newState = phase.state;
570 newState.erase(newState.begin() + removed);
571 newLogic->addStep(phase.duration, newState);
572 }
573 delete myTLLogic;
574 myTLLogic = newLogic;
575 }
576 }
577 }
578 }
580 }
581#ifdef DEBUG_RECONSTRUCTION
582 if (debugPrintModified) {
583 std::cout << " newLinks:\n";
584 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
585 std::cout << " " << *it << "\n";
586 }
587 }
588#endif
589}
590
591
592int
594 int maxIndex = -1;
595 for (const NBConnection& c : myControlledLinks) {
596 maxIndex = MAX2(maxIndex, c.getTLIndex());
597 maxIndex = MAX2(maxIndex, c.getTLIndex2());
598 }
599 for (NBNode* n : myControlledNodes) {
600 for (NBNode::Crossing* c : n->getCrossings()) {
601 maxIndex = MAX2(maxIndex, c->tlLinkIndex);
602 maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
603 }
604 }
605 return maxIndex;
606}
607
608
609int
611 return myTLLogic->getNumLinks() - 1;
612}
613
614
615bool
617 for (const NBConnection& c : myControlledLinks) {
618 if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
619 return false;
620 }
621 }
622 for (NBNode* n : myControlledNodes) {
623 for (NBNode::Crossing* c : n->getCrossings()) {
624 if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
625 return false;
626 }
627 }
628 }
629 // method getMaxIndex() is const but cannot be declare as such due to inheritance
630 return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
631}
632
633
634std::string
636 assert(index >= 0);
637 assert(index <= getMaxValidIndex());
638 std::string result;
639 for (auto& pd : myTLLogic->getPhases()) {
640 result += pd.state[index];
641 }
642 return result;
643}
644
645bool
647 for (const NBConnection& c : myControlledLinks) {
648 if (c.getTLIndex() == index || c.getTLIndex2() == index) {
649 return true;
650 }
651 }
652 for (NBNode* n : myControlledNodes) {
653 for (NBNode::Crossing* c : n->getCrossings()) {
654 if (c->tlLinkIndex == index || c->tlLinkIndex2 == index) {
655 return true;
656 }
657 }
658 }
659 return false;
660}
661
662std::set<const NBEdge*>
664 std::set<const NBEdge*> result;
665 for (const NBConnection& c : myControlledLinks) {
666 if (c.getTLIndex() == index || c.getTLIndex2() == index) {
667 result.insert(c.getFrom());
668 }
669 }
670 return result;
671}
672
673
674void
675NBLoadedSUMOTLDef::replaceIndex(int oldIndex, int newIndex) {
676 if (oldIndex == newIndex) {
677 return;
678 }
680 if (c.getTLIndex() == oldIndex) {
681 c.setTLIndex(newIndex);
682 }
683 if (c.getTLIndex2() == oldIndex) {
684 c.setTLIndex2(newIndex);
685 }
686 }
687 for (NBNode* n : myControlledNodes) {
688 for (NBNode::Crossing* c : n->getCrossings()) {
689 if (c->tlLinkIndex == oldIndex) {
690 c->tlLinkIndex = newIndex;
691 }
692 if (c->tlLinkIndex2 == oldIndex) {
693 c->tlLinkIndex2 = newIndex;
694 }
695 }
696 }
697}
698
699void
701 const int maxIndex = getMaxIndex();
702 std::vector<int> unusedIndices;
703 for (int i = 0; i <= maxIndex; i++) {
704 if (isUsed(i)) {
705 std::set<const NBEdge*> edges = getEdgesUsingIndex(i);
706 // compactify
707 replaceIndex(i, i - (int)unusedIndices.size());
708 if (edges.size() == 0) {
709 // do not group pedestrian crossing signals
710 continue;
711 }
712 std::string states = getStates(i);
713 for (int j = i + 1; j <= maxIndex; j++) {
714 // only group signals from the same edges as is commonly done by
715 // traffic engineers
716 if (states == getStates(j) && edges == getEdgesUsingIndex(j)) {
717 replaceIndex(j, i - (int)unusedIndices.size());
718 }
719 }
720 } else {
721 unusedIndices.push_back(i);
722 }
723 }
724 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
725 myTLLogic->deleteStateIndex(unusedIndices[i]);
726 }
728 //std::cout << "oldMaxIndex=" << maxIndex << " newMaxIndex=" << getMaxIndex() << " unused=" << toString(unusedIndices) << "\n";
730 // patch crossing indices
731 for (NBNode* n : myControlledNodes) {
732 for (NBNode::Crossing* c : n->getCrossings()) {
733 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
734 if (c->customTLIndex > i) {
735 c->customTLIndex--;
736 }
737 if (c->customTLIndex2 > i) {
738 c->customTLIndex2--;
739 }
740 }
741 }
742 }
743}
744
745void
747 NBConnectionVector defaultOrdering;
748 collectAllLinks(defaultOrdering);
749 std::vector<std::string> states; // organized per link rather than phase
750 int index = 0;
751 for (NBConnection& c : defaultOrdering) {
752 NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
753 states.push_back(getStates(c2.getTLIndex()));
754 c2.setTLIndex(index++);
755 }
756 for (NBNode* n : myControlledNodes) {
757 for (NBNode::Crossing* c : n->getCrossings()) {
758 states.push_back(getStates(c->tlLinkIndex));
759 c->customTLIndex = index++;
760 if (c->tlLinkIndex2 != NBConnection::InvalidTlIndex) {
761 states.push_back(getStates(c->tlLinkIndex2));
762 c->customTLIndex2 = index++;
763 }
764 }
765 }
766 myTLLogic->setStateLength(index);
767 for (int i = 0; i < (int)states.size(); i++) {
768 for (int p = 0; p < (int)states[i].size(); p++) {
769 myTLLogic->setPhaseState(p, i, (LinkState)states[i][p]);
770 }
771 }
773}
774
775
776void
778 std::map<int, std::string> oldStates; // organized per link index rather than phase
779 std::map<int, std::string> newStates; // organized per link index rather than phase
780 for (NBConnection& c : def->getControlledLinks()) {
781 NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
782 const int oldIndex = c2.getTLIndex();
783 const int newIndex = c.getTLIndex();
784 std::string states = getStates(oldIndex);
785 oldStates[oldIndex] = states;
786 if (newStates.count(newIndex) != 0 && newStates[newIndex] != states) {
787 WRITE_WARNING("Signal groups from program '" + def->getProgramID() + "' are incompatible with the states of program '" + getProgramID() + "' at tlLogic '" + getID()
788 + "'. Possibly unsafe program.");
789 } else {
790 newStates[newIndex] = states;
791 }
792 c2.setTLIndex(newIndex);
793 }
794 const int maxIndex = getMaxIndex();
795 myTLLogic->setStateLength(maxIndex + 1);
796 for (int i = 0; i < (int)newStates.size(); i++) {
797 for (int p = 0; p < (int)newStates[i].size(); p++) {
798 myTLLogic->setPhaseState(p, i, (LinkState)newStates[i][p]);
799 }
800 }
802}
803
804
805bool
807 const int maxIndex = getMaxValidIndex();
808 std::vector<int> unusedIndices;
809 for (int i = 0; i <= maxIndex; i++) {
810 if (isUsed(i)) {
811 if (unusedIndices.size() > 0) {
812 replaceIndex(i, i - (int)unusedIndices.size());
813 }
814 } else {
815 unusedIndices.push_back(i);
816 }
817 }
818 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
819 myTLLogic->deleteStateIndex(unusedIndices[i]);
820 }
821 if (unusedIndices.size() > 0) {
822 myTLLogic->setStateLength(maxIndex + 1 - (int)unusedIndices.size());
824 return true;
825 } else {
826 return false;
827 }
828}
829
830
831void
835 const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
836 myTLLogic->setStateLength(maxIndex + 1);
837 myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
838}
839
840bool
842 // count how often each index is used
843 std::map<int, int> indexUsage;
844 for (const NBConnection& c : myControlledLinks) {
845 indexUsage[c.getTLIndex()]++;
846 }
847 for (NBNode* n : myControlledNodes) {
848 for (NBNode::Crossing* c : n->getCrossings()) {
849 indexUsage[c->tlLinkIndex]++;
850 indexUsage[c->tlLinkIndex2]++;
851 }
852 }
853 for (auto it : indexUsage) {
854 if (it.first >= 0 && it.second > 1) {
855 return true;
856 }
857 }
858 return false;
859}
860
861void
863 bool hasMinMaxDur = false;
864 for (auto phase : myTLLogic->getPhases()) {
865 if (phase.maxDur != UNSPECIFIED_DURATION) {
866 //std::cout << " phase=" << phase.state << " maxDur=" << phase.maxDur << "\n";
867 hasMinMaxDur = true;
868 }
869 }
870 if (!hasMinMaxDur) {
871 const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
872 const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
873 std::set<int> yellowIndices;
874 for (auto phase : myTLLogic->getPhases()) {
875 for (int i = 0; i < (int)phase.state.size(); i++) {
876 if (phase.state[i] == 'y' || phase.state[i] == 'Y') {
877 yellowIndices.insert(i);
878 }
879 }
880 }
881 for (int ip = 0; ip < (int)myTLLogic->getPhases().size(); ip++) {
882 bool needMinMaxDur = false;
883 auto phase = myTLLogic->getPhases()[ip];
884 std::set<int> greenIndices;
885 if (phase.state.find_first_of("yY") != std::string::npos) {
886 continue;
887 }
888 for (int i = 0; i < (int)phase.state.size(); i++) {
889 if (yellowIndices.count(i) != 0 && phase.state[i] == 'G') {
890 needMinMaxDur = true;
891 greenIndices.insert(i);
892 }
893 }
894 if (needMinMaxDur) {
895 double maxSpeed = 0;
897 if (greenIndices.count(c.getTLIndex()) != 0) {
898 maxSpeed = MAX2(maxSpeed, c.getFrom()->getLaneSpeed(c.getFromLane()));
899 }
900 }
901 // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
902 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
903 SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
904 myTLLogic->setPhaseMinDuration(ip, minDur);
905 myTLLogic->setPhaseMaxDuration(ip, maxDur);
906 }
907 }
908 }
909}
910
911
912void
914 for (int i = 0; i < myTLLogic->getNumLinks(); i++) {
915 if (!isUsed(i)) {
916 WRITE_WARNINGF(TL("Unused state in tlLogic '%', program '%' at tl-index %"), getID(), getProgramID(), i);
917 break;
918 }
919 }
920}
921
922
923/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
std::vector< NBConnection > NBConnectionVector
Definition of a connection vector.
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition NBCont.h:42
#define TIME2STEPS(x)
Definition SUMOTime.h:57
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
T MAX2(T a, T b)
Definition StdDefs.h:86
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
static const int InvalidTlIndex
void setTLIndex(int tlIndex)
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
NBNode * getToNode() const
Returns the destination node of the edge.
Definition NBEdge.h:552
const Connection & getConnection(int fromLane, const NBEdge *to, int toLane) const
Returns the specified connection (unmodifiable) This method goes through "myConnections" and returns ...
Definition NBEdge.cpp:1324
void setInsideTLS(bool inside)
Marks this edge being within an intersection.
Definition NBEdge.h:1147
const std::string & getID() const
Definition NBEdge.h:1551
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition NBEdge.cpp:3869
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition NBEdge.cpp:3807
int getNumLanes() const
Returns the number of lanes.
Definition NBEdge.h:526
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition NBEdge.cpp:3858
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition NBEdge.h:545
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:1348
class for identifying connections
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 extraConflict(int index, int foeIndex) const
whether the given index must yield to the foeIndex while turing right on a red light
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
bool isValid(const NBConnection &con) const
return whether the given connection is still valid
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
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:2183
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
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
const std::vector< NBNode * > & getNodes() const
Returns the list of controlled nodes.
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.
NBTrafficLightLogic * compute(const OptionsCont &oc)
Computes the traffic light logic.
SUMOTime getOffset()
Returns the offset.
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
const NBConnectionVector & getControlledLinks() const
returns the controlled links (depends on previous call to collectLinks)
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
NBTrafficLightDefinition(const std::string &id, const std::vector< NBNode * > &junctions, const std::string &programID, SUMOTime offset, TrafficLightType type)
Constructor.
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 setType(TrafficLightType type)
set the algorithm type (static etc..)
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).
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.
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.
#define UNUSED_PARAMETER(x)
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:21899
bool indirectLeft
Whether this connection is an indirect left turn.
Definition NBEdge.h:261
data structure for caching needsCont information