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-2023 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),
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
82NBLoadedSUMOTLDef::myCompute(int brakingTimeSeconds) {
83 // @todo what to do with those parameters?
84 UNUSED_PARAMETER(brakingTimeSeconds);
90}
91
92
93void
94NBLoadedSUMOTLDef::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
121void
122NBLoadedSUMOTLDef::setID(const std::string& newID) {
123 Named::setID(newID);
124 myTLLogic->setID(newID);
125}
126
127void
128NBLoadedSUMOTLDef::setProgramID(const std::string& programID) {
130 myTLLogic->setProgramID(programID);
131}
132
133
134void
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
168void
170
171
172void
173NBLoadedSUMOTLDef::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
184void
185NBLoadedSUMOTLDef::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
192bool
194 if (myControlledLinks.size() == 0) {
195 return true;
196 }
197 if (myIncomingEdges.size() == 0) {
198 return true;
199 }
200 return false;
201}
202
203
204void
205NBLoadedSUMOTLDef::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
227void
229 myOffset = offset;
230 myTLLogic->setOffset(offset);
231}
232
233
234void
236 myType = type;
237 myTLLogic->setType(type);
238}
239
240
241void
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
286void
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
297void
298NBLoadedSUMOTLDef::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
309void
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
365void
366NBLoadedSUMOTLDef::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
386void
389 myNeedsContRelation.clear();
390 myRightOnRedConflicts.clear();
391 const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
392 const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
393 for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
394 const std::string state = (*it).state;
395 for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
396 const NBConnection& c1 = *it1;
397 const int i1 = c1.getTLIndex();
398 if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
399 continue;
400 }
401 for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
402 const NBConnection& c2 = *it2;
403 const int i2 = c2.getTLIndex();
405 && i2 != i1
406 && (state[i2] == 'G' || state[i2] == 'g')
407 && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
408 const bool rightTurnConflict = NBNode::rightTurnConflict(
409 c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
410 const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
411 const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
412 if (forbidden || rightTurnConflict) {
413 myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
414 }
415 if (isFoes && state[i1] == 's') {
416 myRightOnRedConflicts.insert(std::make_pair(i1, i2));
417 //std::cout << getID() << " prog=" << getProgramID() << " phase=" << (it - phases.begin()) << " rightOnRedConflict i1=" << i1 << " i2=" << i2 << "\n";
418 }
419 //std::cout << getID() << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
420 }
421 }
422 }
423 }
424 }
427}
428
429
430bool
431NBLoadedSUMOTLDef::rightOnRedConflict(int index, int foeIndex) const {
432 if (amInvalid()) {
433 return false;
434 }
438 }
439 return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
440}
441
442
443void
444NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
445 myReconstructAddedConnections |= addedConnections;
446 myReconstructRemovedConnections |= removedConnections;
447}
448
449void
451 const bool netedit = NBNetBuilder::runningNetedit();
452#ifdef DEBUG_RECONSTRUCTION
454 std::cout << getID() << " reconstructLogic added=" << myReconstructAddedConnections
455 << " removed=" << myReconstructRemovedConnections
456 << " valid=" << hasValidIndices()
457 << " phasesLoaded=" << myPhasesLoaded
458 << " oldLinks:\n";
459 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
460 std::cout << " " << *it << "\n";
461 }
462#endif
465 // do not rebuild the logic when running netedit and all links are already covered by the program
466 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
467 // rebuild the logic from scratch
468 // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
471 dummy.setProgramID(getProgramID());
476 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
477 (*i)->removeTrafficLight(&dummy);
478 }
479 delete myTLLogic;
480 myTLLogic = newLogic;
481 if (newLogic != nullptr) {
482 newLogic->setID(getID());
483 newLogic->setType(getType());
484 newLogic->setOffset(getOffset());
486 // reset crossing custom indices
487 for (NBNode* n : myControlledNodes) {
488 for (NBNode::Crossing* c : n->getCrossings()) {
489 c->customTLIndex = NBConnection::InvalidTlIndex;
490 }
491 }
492
493 }
494 } else {
496 }
497 }
500 // for each connection, check whether it is still valid
501 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
502 const NBConnection con = (*it);
503 if (// edge still exists
504 std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
505 // connection still exists
506 && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
507 // connection is still set to be controlled
508 && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane())) {
509 it++;
510 } else {
511 // remove connection
512 const int removed = con.getTLIndex();
513 it = myControlledLinks.erase(it);
514 // no automatic modificaions when running netedit
515 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
516 // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
517 bool exclusive = true;
518 for (NBConnection& other : myControlledLinks) {
519 if (other != con && other.getTLIndex() == removed) {
520 exclusive = false;
521 break;
522 }
523 }
524 if (exclusive) {
525 // shift indices above the removed index downward
526 for (NBConnection& other : myControlledLinks) {
527 if (other.getTLIndex() > removed) {
528 other.setTLIndex(other.getTLIndex() - 1);
529 }
530 }
531 // shift crossing custom indices above the removed index downward
532 for (NBNode* n : myControlledNodes) {
533 for (NBNode::Crossing* c : n->getCrossings()) {
534 if (c->customTLIndex > removed) {
535 c->customTLIndex--;
536 }
537 }
538 }
539 // rebuild the logic
542 std::string newState = phase.state;
543 newState.erase(newState.begin() + removed);
544 newLogic->addStep(phase.duration, newState);
545 }
546 delete myTLLogic;
547 myTLLogic = newLogic;
548 }
549 }
550 }
551 }
553 }
554#ifdef DEBUG_RECONSTRUCTION
555 if (debugPrintModified) {
556 std::cout << " newLinks:\n";
557 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
558 std::cout << " " << *it << "\n";
559 }
560 }
561#endif
562}
563
564
565int
567 int maxIndex = -1;
568 for (const NBConnection& c : myControlledLinks) {
569 maxIndex = MAX2(maxIndex, c.getTLIndex());
570 maxIndex = MAX2(maxIndex, c.getTLIndex2());
571 }
572 for (NBNode* n : myControlledNodes) {
573 for (NBNode::Crossing* c : n->getCrossings()) {
574 maxIndex = MAX2(maxIndex, c->tlLinkIndex);
575 maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
576 }
577 }
578 return maxIndex;
579}
580
581
582int
584 return myTLLogic->getNumLinks() - 1;
585}
586
587
588bool
590 for (const NBConnection& c : myControlledLinks) {
591 if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
592 return false;
593 }
594 }
595 for (NBNode* n : myControlledNodes) {
596 for (NBNode::Crossing* c : n->getCrossings()) {
597 if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
598 return false;
599 }
600 }
601 }
602 // method getMaxIndex() is const but cannot be declare as such due to inheritance
603 return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
604}
605
606
607std::string
609 assert(index >= 0);
610 assert(index <= getMaxValidIndex());
611 std::string result;
612 for (auto& pd : myTLLogic->getPhases()) {
613 result += pd.state[index];
614 }
615 return result;
616}
617
618bool
620 for (const NBConnection& c : myControlledLinks) {
621 if (c.getTLIndex() == index || c.getTLIndex2() == index) {
622 return true;
623 }
624 }
625 for (NBNode* n : myControlledNodes) {
626 for (NBNode::Crossing* c : n->getCrossings()) {
627 if (c->tlLinkIndex == index || c->tlLinkIndex2 == index) {
628 return true;
629 }
630 }
631 }
632 return false;
633}
634
635std::set<const NBEdge*>
637 std::set<const NBEdge*> result;
638 for (const NBConnection& c : myControlledLinks) {
639 if (c.getTLIndex() == index || c.getTLIndex2() == index) {
640 result.insert(c.getFrom());
641 }
642 }
643 return result;
644}
645
646
647void
648NBLoadedSUMOTLDef::replaceIndex(int oldIndex, int newIndex) {
649 if (oldIndex == newIndex) {
650 return;
651 }
653 if (c.getTLIndex() == oldIndex) {
654 c.setTLIndex(newIndex);
655 }
656 if (c.getTLIndex2() == oldIndex) {
657 c.setTLIndex2(newIndex);
658 }
659 }
660 for (NBNode* n : myControlledNodes) {
661 for (NBNode::Crossing* c : n->getCrossings()) {
662 if (c->tlLinkIndex == oldIndex) {
663 c->tlLinkIndex = newIndex;
664 }
665 if (c->tlLinkIndex2 == oldIndex) {
666 c->tlLinkIndex2 = newIndex;
667 }
668 }
669 }
670}
671
672void
674 const int maxIndex = getMaxIndex();
675 std::vector<int> unusedIndices;
676 for (int i = 0; i <= maxIndex; i++) {
677 if (isUsed(i)) {
678 std::set<const NBEdge*> edges = getEdgesUsingIndex(i);
679 // compactify
680 replaceIndex(i, i - (int)unusedIndices.size());
681 if (edges.size() == 0) {
682 // do not group pedestrian crossing signals
683 continue;
684 }
685 std::string states = getStates(i);
686 for (int j = i + 1; j <= maxIndex; j++) {
687 // only group signals from the same edges as is commonly done by
688 // traffic engineers
689 if (states == getStates(j) && edges == getEdgesUsingIndex(j)) {
690 replaceIndex(j, i - (int)unusedIndices.size());
691 }
692 }
693 } else {
694 unusedIndices.push_back(i);
695 }
696 }
697 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
698 myTLLogic->deleteStateIndex(unusedIndices[i]);
699 }
701 //std::cout << "oldMaxIndex=" << maxIndex << " newMaxIndex=" << getMaxIndex() << " unused=" << toString(unusedIndices) << "\n";
703 // patch crossing indices
704 for (NBNode* n : myControlledNodes) {
705 for (NBNode::Crossing* c : n->getCrossings()) {
706 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
707 if (c->customTLIndex > i) {
708 c->customTLIndex--;
709 }
710 if (c->customTLIndex2 > i) {
711 c->customTLIndex2--;
712 }
713 }
714 }
715 }
716}
717
718void
720 NBConnectionVector defaultOrdering;
721 collectAllLinks(defaultOrdering);
722 std::vector<std::string> states; // organized per link rather than phase
723 int index = 0;
724 for (NBConnection& c : defaultOrdering) {
725 NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
726 states.push_back(getStates(c2.getTLIndex()));
727 c2.setTLIndex(index++);
728 }
729 for (NBNode* n : myControlledNodes) {
730 for (NBNode::Crossing* c : n->getCrossings()) {
731 states.push_back(getStates(c->tlLinkIndex));
732 c->customTLIndex = index++;
733 if (c->tlLinkIndex2 != NBConnection::InvalidTlIndex) {
734 states.push_back(getStates(c->tlLinkIndex2));
735 c->customTLIndex2 = index++;
736 }
737 }
738 }
740 for (int i = 0; i < (int)states.size(); i++) {
741 for (int p = 0; p < (int)states[i].size(); p++) {
742 myTLLogic->setPhaseState(p, i, (LinkState)states[i][p]);
743 }
744 }
746}
747
748
749void
751 std::map<int, std::string> oldStates; // organized per link index rather than phase
752 std::map<int, std::string> newStates; // organized per link index rather than phase
753 for (NBConnection& c : def->getControlledLinks()) {
754 NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
755 const int oldIndex = c2.getTLIndex();
756 const int newIndex = c.getTLIndex();
757 std::string states = getStates(oldIndex);
758 oldStates[oldIndex] = states;
759 if (newStates.count(newIndex) != 0 && newStates[newIndex] != states) {
760 WRITE_WARNING("Signal groups from program '" + def->getProgramID() + "' are incompatible with the states of program '" + getProgramID() + "' at tlLogic '" + getID()
761 + "'. Possibly unsafe program.");
762 } else {
763 newStates[newIndex] = states;
764 }
765 c2.setTLIndex(newIndex);
766 }
767 const int maxIndex = getMaxIndex();
768 myTLLogic->setStateLength(maxIndex + 1);
769 for (int i = 0; i < (int)newStates.size(); i++) {
770 for (int p = 0; p < (int)newStates[i].size(); p++) {
771 myTLLogic->setPhaseState(p, i, (LinkState)newStates[i][p]);
772 }
773 }
775}
776
777
778bool
780 const int maxIndex = getMaxValidIndex();
781 std::vector<int> unusedIndices;
782 for (int i = 0; i <= maxIndex; i++) {
783 if (isUsed(i)) {
784 if (unusedIndices.size() > 0) {
785 replaceIndex(i, i - (int)unusedIndices.size());
786 }
787 } else {
788 unusedIndices.push_back(i);
789 }
790 }
791 for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
792 myTLLogic->deleteStateIndex(unusedIndices[i]);
793 }
794 if (unusedIndices.size() > 0) {
795 myTLLogic->setStateLength(maxIndex + 1 - (int)unusedIndices.size());
797 return true;
798 } else {
799 return false;
800 }
801}
802
803
804void
808 const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
809 myTLLogic->setStateLength(maxIndex + 1);
810 myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
811}
812
813bool
815 // count how often each index is used
816 std::map<int, int> indexUsage;
817 for (const NBConnection& c : myControlledLinks) {
818 indexUsage[c.getTLIndex()]++;
819 }
820 for (NBNode* n : myControlledNodes) {
821 for (NBNode::Crossing* c : n->getCrossings()) {
822 indexUsage[c->tlLinkIndex]++;
823 indexUsage[c->tlLinkIndex2]++;
824 }
825 }
826 for (auto it : indexUsage) {
827 if (it.first >= 0 && it.second > 1) {
828 return true;
829 }
830 }
831 return false;
832}
833
834void
836 bool hasMinMaxDur = false;
837 for (auto phase : myTLLogic->getPhases()) {
838 if (phase.maxDur != UNSPECIFIED_DURATION) {
839 //std::cout << " phase=" << phase.state << " maxDur=" << phase.maxDur << "\n";
840 hasMinMaxDur = true;
841 }
842 }
843 if (!hasMinMaxDur) {
844 const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
845 const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
846 std::set<int> yellowIndices;
847 for (auto phase : myTLLogic->getPhases()) {
848 for (int i = 0; i < (int)phase.state.size(); i++) {
849 if (phase.state[i] == 'y' || phase.state[i] == 'Y') {
850 yellowIndices.insert(i);
851 }
852 }
853 }
854 for (int ip = 0; ip < (int)myTLLogic->getPhases().size(); ip++) {
855 bool needMinMaxDur = false;
856 auto phase = myTLLogic->getPhases()[ip];
857 std::set<int> greenIndices;
858 if (phase.state.find_first_of("yY") != std::string::npos) {
859 continue;
860 }
861 for (int i = 0; i < (int)phase.state.size(); i++) {
862 if (yellowIndices.count(i) != 0 && phase.state[i] == 'G') {
863 needMinMaxDur = true;
864 greenIndices.insert(i);
865 }
866 }
867 if (needMinMaxDur) {
868 double maxSpeed = 0;
870 if (greenIndices.count(c.getTLIndex()) != 0) {
871 maxSpeed = MAX2(maxSpeed, c.getFrom()->getLaneSpeed(c.getFromLane()));
872 }
873 }
874 // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
875 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
876 SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
877 myTLLogic->setPhaseMinDuration(ip, minDur);
878 myTLLogic->setPhaseMaxDuration(ip, maxDur);
879 }
880 }
881 }
882}
883
884
885void
887 for (int i = 0; i < myTLLogic->getNumLinks(); i++) {
888 if (!isUsed(i)) {
889 WRITE_WARNINGF(TL("Unused state in tlLogic '%', program '%' at tl-index %"), getID(), getProgramID(), i);
890 break;
891 }
892 }
893}
894
895
896/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:271
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:270
#define TL(string)
Definition: MsgHandler.h:287
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
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
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:536
void setInsideTLS(bool inside)
Marks this edge being within an intersection.
Definition: NBEdge.h:1127
const std::string & getID() const
Definition: NBEdge.h:1515
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3578
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3516
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:510
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:3567
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:529
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:1259
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:2000
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:862
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
Definition: NBOwnTLDef.cpp:948
The base class for traffic light logic definitions.
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.
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
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 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
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.
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
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