1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2011-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file NBLoadedSUMOTLDef.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Michael Behrisch
13 /// @author Jakob Erdmann
14 /// @date Mar 2011
15 /// @version $Id$
16 ///
17 // A complete traffic light logic loaded from a sumo-net. (opted to reimplement
18 // since NBLoadedTLDef is quite vissim specific)
19 /****************************************************************************/
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include <vector>
27 #include <set>
28 #include <cassert>
29 #include <iterator>
30 #include <utils/common/MsgHandler.h>
31 #include <utils/common/ToString.h>
32 #include <utils/options/OptionsCont.h>
33 #include "NBTrafficLightLogic.h"
34 #include "NBOwnTLDef.h"
35 #include "NBTrafficLightDefinition.h"
36 #include "NBLoadedSUMOTLDef.h"
37 #include "NBNetBuilder.h"
38 #include "NBOwnTLDef.h"
39 #include "NBNode.h"
40
41 //#define DEBUG_RECONSTRUCTION
42
43 // ===========================================================================
44 // method definitions
45 // ===========================================================================
46
NBLoadedSUMOTLDef(const std::string & id,const std::string & programID,SUMOTime offset,TrafficLightType type)47 NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(const std::string& id, const std::string& programID,
48 SUMOTime offset, TrafficLightType type) :
49 NBTrafficLightDefinition(id, programID, offset, type),
50 myTLLogic(nullptr),
51 myReconstructAddedConnections(false),
52 myReconstructRemovedConnections(false),
53 myPhasesLoaded(false) {
54 myTLLogic = new NBTrafficLightLogic(id, programID, 0, offset, type);
55 }
56
57
NBLoadedSUMOTLDef(NBTrafficLightDefinition * def,NBTrafficLightLogic * logic)58 NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(NBTrafficLightDefinition* def, NBTrafficLightLogic* logic) :
59 // allow for adding a new program for the same def: take the offset and programID from the new logic
60 NBTrafficLightDefinition(def->getID(), logic->getProgramID(), logic->getOffset(), def->getType()),
61 myTLLogic(new NBTrafficLightLogic(logic)),
62 myOriginalNodes(def->getNodes().begin(), def->getNodes().end()),
63 myReconstructAddedConnections(false),
64 myReconstructRemovedConnections(false),
65 myPhasesLoaded(false) {
66 assert(def->getType() == logic->getType());
67 myControlledLinks = def->getControlledLinks();
68 myControlledNodes = def->getNodes();
69 NBLoadedSUMOTLDef* sumoDef = dynamic_cast<NBLoadedSUMOTLDef*>(def);
70 updateParameter(def->getParametersMap());
71 if (sumoDef != nullptr) {
72 myReconstructAddedConnections = sumoDef->myReconstructAddedConnections;
73 myReconstructRemovedConnections = sumoDef->myReconstructRemovedConnections;
74 }
75 }
76
77
~NBLoadedSUMOTLDef()78 NBLoadedSUMOTLDef::~NBLoadedSUMOTLDef() {
79 delete myTLLogic;
80 }
81
82
83 NBTrafficLightLogic*
myCompute(int brakingTimeSeconds)84 NBLoadedSUMOTLDef::myCompute(int brakingTimeSeconds) {
85 // @todo what to do with those parameters?
86 UNUSED_PARAMETER(brakingTimeSeconds);
87 reconstructLogic();
88 myTLLogic->closeBuilding(false);
89 patchIfCrossingsAdded();
90 myTLLogic->closeBuilding();
91 return new NBTrafficLightLogic(myTLLogic);
92 }
93
94
95 void
addConnection(NBEdge * from,NBEdge * to,int fromLane,int toLane,int linkIndex,bool reconstruct)96 NBLoadedSUMOTLDef::addConnection(NBEdge* from, NBEdge* to, int fromLane, int toLane, int linkIndex, bool reconstruct) {
97 assert(myTLLogic->getNumLinks() > 0); // logic should be loaded by now
98 if (linkIndex >= (int)myTLLogic->getNumLinks()) {
99 throw ProcessError("Invalid linkIndex " + toString(linkIndex) + " for traffic light '" + getID() +
100 "' with " + toString(myTLLogic->getNumLinks()) + " links.");
101 }
102 NBConnection conn(from, fromLane, to, toLane, linkIndex);
103 // avoid duplicates
104 auto newEnd = remove_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(conn));
105 // remove_if does not remove, only re-order
106 myControlledLinks.erase(newEnd, myControlledLinks.end());
107 myControlledLinks.push_back(conn);
108 addNode(from->getToNode());
109 addNode(to->getFromNode());
110 myOriginalNodes.insert(from->getToNode());
111 myOriginalNodes.insert(to->getFromNode());
112 // added connections are definitely controlled. make sure none are removed because they lie within the tl
113 // myControlledInnerEdges.insert(from->getID()); // @todo recheck: this appears to be obsolete
114 // set this information now so that it can be used while loading diffs
115 from->setControllingTLInformation(conn, getID());
116 myReconstructAddedConnections |= reconstruct;
117 }
118
119
120 void
setTLControllingInformation() const121 NBLoadedSUMOTLDef::setTLControllingInformation() const {
122 if (myReconstructAddedConnections) {
123 NBOwnTLDef dummy(DummyID, myControlledNodes, 0, getType());
124 dummy.setParticipantsInformation();
125 dummy.setTLControllingInformation();
126 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
127 (*i)->removeTrafficLight(&dummy);
128 }
129 }
130 if (myReconstructRemovedConnections) {
131 return; // will be called again in reconstructLogic()
132 }
133 // if nodes have been removed our links may have been invalidated as well
134 // since no logic will be built anyway there is no reason to inform any edges
135 if (amInvalid()) {
136 return;
137 }
138 // set the information about the link's positions within the tl into the
139 // edges the links are starting at, respectively
140 for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
141 const NBConnection& c = *it;
142 if (c.getTLIndex() >= (int)myTLLogic->getNumLinks()) {
143 throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
144 "' with " + toString(myTLLogic->getNumLinks()) + " links.");
145 }
146 NBEdge* edge = c.getFrom();
147 if (edge != nullptr && edge->getNumLanes() > c.getFromLane()) {
148 // logic may have yet to be reconstructed
149 edge->setControllingTLInformation(c, getID());
150 }
151 }
152 }
153
154
155 void
remapRemoved(NBEdge *,const EdgeVector &,const EdgeVector &)156 NBLoadedSUMOTLDef::remapRemoved(NBEdge*, const EdgeVector&, const EdgeVector&) {}
157
158
159 void
replaceRemoved(NBEdge * removed,int removedLane,NBEdge * by,int byLane)160 NBLoadedSUMOTLDef::replaceRemoved(NBEdge* removed, int removedLane, NBEdge* by, int byLane) {
161 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
162 (*it).replaceFrom(removed, removedLane, by, byLane);
163 (*it).replaceTo(removed, removedLane, by, byLane);
164 }
165 }
166
167
168 void
addPhase(SUMOTime duration,const std::string & state,SUMOTime minDur,SUMOTime maxDur,const std::vector<int> & next,const std::string & name)169 NBLoadedSUMOTLDef::addPhase(SUMOTime duration, const std::string& state, SUMOTime minDur, SUMOTime maxDur, const std::vector<int>& next, const std::string& name) {
170 myTLLogic->addStep(duration, state, minDur, maxDur, next, name);
171 }
172
173
174 bool
amInvalid() const175 NBLoadedSUMOTLDef::amInvalid() const {
176 if (myControlledLinks.size() == 0) {
177 return true;
178 }
179 // make sure that myControlledNodes are the original nodes
180 if (myControlledNodes.size() != myOriginalNodes.size()) {
181 //std::cout << " myControlledNodes=" << myControlledNodes.size() << " myOriginalNodes=" << myOriginalNodes.size() << "\n";
182 return true;
183 }
184 if (myIncomingEdges.size() == 0) {
185 return true;
186 }
187 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
188 if (myOriginalNodes.count(*i) != 1) {
189 //std::cout << " node " << (*i)->getID() << " missing from myOriginalNodes\n";
190 return true;
191 }
192 }
193 return false;
194 }
195
196
197 void
removeConnection(const NBConnection & conn,bool reconstruct)198 NBLoadedSUMOTLDef::removeConnection(const NBConnection& conn, bool reconstruct) {
199 NBConnectionVector::iterator it = myControlledLinks.begin();
200 // find the connection but ignore its TLIndex since it might have been
201 // invalidated by an earlier removal
202 for (; it != myControlledLinks.end(); ++it) {
203 if (it->getFrom() == conn.getFrom() &&
204 it->getTo() == conn.getTo() &&
205 it->getFromLane() == conn.getFromLane() &&
206 it->getToLane() == conn.getToLane()) {
207 break;
208 }
209 }
210 if (it == myControlledLinks.end()) {
211 // a traffic light doesn't always controll all connections at a junction
212 // especially when using the option --tls.join
213 return;
214 }
215 myReconstructRemovedConnections |= reconstruct;
216 }
217
218
219 void
setOffset(SUMOTime offset)220 NBLoadedSUMOTLDef::setOffset(SUMOTime offset) {
221 myOffset = offset;
222 myTLLogic->setOffset(offset);
223 }
224
225
226 void
setType(TrafficLightType type)227 NBLoadedSUMOTLDef::setType(TrafficLightType type) {
228 myType = type;
229 myTLLogic->setType(type);
230 }
231
232
233 void
collectEdges()234 NBLoadedSUMOTLDef::collectEdges() {
235 if (myControlledLinks.size() == 0) {
236 NBTrafficLightDefinition::collectEdges();
237 }
238 myIncomingEdges.clear();
239 EdgeVector myOutgoing;
240 // collect the edges from the participating nodes
241 for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
242 const EdgeVector& incoming = (*i)->getIncomingEdges();
243 copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
244 const EdgeVector& outgoing = (*i)->getOutgoingEdges();
245 copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
246 }
247 // check which of the edges are completely within the junction
248 // and which are uncontrolled as well (we already know myControlledLinks)
249 for (EdgeVector::iterator j = myIncomingEdges.begin(); j != myIncomingEdges.end();) {
250 NBEdge* edge = *j;
251 // an edge lies within the logic if it is outgoing as well as incoming
252 EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
253 if (k != myOutgoing.end()) {
254 if (myControlledInnerEdges.count(edge->getID()) == 0) {
255 bool controlled = false;
256 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
257 if ((*it).getFrom() == edge) {
258 controlled = true;
259 break;
260 }
261 }
262 if (controlled) {
263 myControlledInnerEdges.insert(edge->getID());
264 } else {
265 myEdgesWithin.push_back(edge);
266 (*j)->setInternal();
267 ++j; //j = myIncomingEdges.erase(j);
268 continue;
269 }
270 }
271 }
272 ++j;
273 }
274 }
275
276
277 void
collectLinks()278 NBLoadedSUMOTLDef::collectLinks() {
279 if (myControlledLinks.size() == 0) {
280 // maybe we only loaded a different program for a default traffic light.
281 // Try to build links now.
282 myOriginalNodes.insert(myControlledNodes.begin(), myControlledNodes.end());
283 collectAllLinks();
284 }
285 }
286
287
288 /// @brief patches signal plans by modifying lane indices
289 void
shiftTLConnectionLaneIndex(NBEdge * edge,int offset,int threshold)290 NBLoadedSUMOTLDef::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
291 // avoid shifting twice if the edge is incoming and outgoing to a joined TLS
292 if (myShifted.count(edge) == 0) {
293 /// XXX what if an edge should really be shifted twice?
294 myShifted.insert(edge);
295 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
296 (*it).shiftLaneIndex(edge, offset, threshold);
297 }
298 }
299 }
300
301 void
patchIfCrossingsAdded()302 NBLoadedSUMOTLDef::patchIfCrossingsAdded() {
303 const int size = myTLLogic->getNumLinks();
304 int noLinksAll = 0;
305 for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
306 const NBConnection& c = *it;
307 if (c.getTLIndex() != NBConnection::InvalidTlIndex) {
308 noLinksAll = MAX2(noLinksAll, (int)c.getTLIndex() + 1);
309 }
310 }
311 const int numNormalLinks = noLinksAll;
312 int oldCrossings = 0;
313 // collect crossings
314 bool customIndex = false;
315 std::vector<NBNode::Crossing*> crossings;
316 for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
317 const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
318 // set tl indices for crossings
319 customIndex |= (*i)->setCrossingTLIndices(getID(), noLinksAll);
320 copy(c.begin(), c.end(), std::back_inserter(crossings));
321 noLinksAll += (int)c.size();
322 oldCrossings += (*i)->numCrossingsFromSumoNet();
323 }
324 if ((int)crossings.size() != oldCrossings) {
325 std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
326 // do not rebuilt crossing states there are custom indices and the state string is long enough
327 if (phases.size() > 0 && (
328 (int)(phases.front().state.size()) < noLinksAll ||
329 ((int)(phases.front().state.size()) > noLinksAll && !customIndex))) {
330 // collect edges
331 EdgeVector fromEdges(size, (NBEdge*)nullptr);
332 EdgeVector toEdges(size, (NBEdge*)nullptr);
333 std::vector<int> fromLanes(size, 0);
334 collectEdgeVectors(fromEdges, toEdges, fromLanes);
335 const std::string crossingDefaultState(crossings.size(), 'r');
336
337 // rebuild the logic (see NBOwnTLDef.cpp::myCompute)
338 NBTrafficLightLogic* newLogic = new NBTrafficLightLogic(getID(), getProgramID(), 0, myOffset, myType);
339 SUMOTime brakingTime = TIME2STEPS(computeBrakingTime(OptionsCont::getOptions().getFloat("tls.yellow.min-decel")));
340 //std::cout << "patchIfCrossingsAdded for " << getID() << " numPhases=" << phases.size() << "\n";
341 for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
342 const std::string state = it->state.substr(0, numNormalLinks) + crossingDefaultState;
343 NBOwnTLDef::addPedestrianPhases(newLogic, it->duration, it->minDur, it->maxDur, state, crossings, fromEdges, toEdges);
344 }
345 NBOwnTLDef::addPedestrianScramble(newLogic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
346
347 delete myTLLogic;
348 myTLLogic = newLogic;
349 } else if (phases.size() == 0) {
350 WRITE_WARNING("Could not patch tlLogic '" + getID() + "' for changed crossings");
351 }
352 }
353 }
354
355
356 void
collectEdgeVectors(EdgeVector & fromEdges,EdgeVector & toEdges,std::vector<int> & fromLanes) const357 NBLoadedSUMOTLDef::collectEdgeVectors(EdgeVector& fromEdges, EdgeVector& toEdges, std::vector<int>& fromLanes) const {
358 assert(fromEdges.size() > 0);
359 assert(fromEdges.size() == toEdges.size());
360 const int size = (int)fromEdges.size();
361
362 for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
363 const NBConnection& c = *it;
364 if (c.getTLIndex() != NBConnection::InvalidTlIndex) {
365 if (c.getTLIndex() >= size) {
366 throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
367 "' with " + toString(size) + " links.");
368 }
369 fromEdges[c.getTLIndex()] = c.getFrom();
370 toEdges[c.getTLIndex()] = c.getTo();
371 fromLanes[c.getTLIndex()] = c.getFromLane();
372 }
373 }
374 }
375
376
377 void
initNeedsContRelation() const378 NBLoadedSUMOTLDef::initNeedsContRelation() const {
379 if (!amInvalid() && !myNeedsContRelationReady) {
380 myNeedsContRelation.clear();
381 myRightOnRedConflicts.clear();
382 const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
383 const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
384 for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
385 const std::string state = (*it).state;
386 for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
387 const NBConnection& c1 = *it1;
388 const int i1 = c1.getTLIndex();
389 if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
390 continue;
391 }
392 for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
393 const NBConnection& c2 = *it2;
394 const int i2 = c2.getTLIndex();
395 if (i2 != NBConnection::InvalidTlIndex
396 && i2 != i1
397 && (state[i2] == 'G' || state[i2] == 'g')
398 && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
399 const bool rightTurnConflict = NBNode::rightTurnConflict(
400 c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
401 const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
402 const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
403 if (forbidden || rightTurnConflict) {
404 myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
405 }
406 if (isFoes) {
407 myRightOnRedConflicts.insert(std::make_pair(i1, i2));
408 }
409 //std::cout << getID() << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
410 }
411 }
412 }
413 }
414 }
415 myNeedsContRelationReady = true;
416 myRightOnRedConflictsReady = true;
417 }
418
419
420 bool
rightOnRedConflict(int index,int foeIndex) const421 NBLoadedSUMOTLDef::rightOnRedConflict(int index, int foeIndex) const {
422 if (amInvalid()) {
423 return false;
424 }
425 if (!myRightOnRedConflictsReady) {
426 initNeedsContRelation();
427 assert(myRightOnRedConflictsReady);
428 }
429 return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
430 }
431
432
433 void
registerModifications(bool addedConnections,bool removedConnections)434 NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
435 myReconstructAddedConnections |= addedConnections;
436 myReconstructRemovedConnections |= removedConnections;
437 }
438
439 void
reconstructLogic()440 NBLoadedSUMOTLDef::reconstructLogic() {
441 const bool netedit = NBNetBuilder::runningNetedit();
442 #ifdef DEBUG_RECONSTRUCTION
443 bool debugPrintModified = myReconstructAddedConnections || myReconstructRemovedConnections;
444 std::cout << " reconstructLogic added=" << myReconstructAddedConnections << " removed=" << myReconstructRemovedConnections << " valid=" << hasValidIndices() << " oldLinks:\n";
445 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
446 std::cout << " " << *it << "\n";
447 }
448 #endif
449 if (myReconstructAddedConnections) {
450 myReconstructAddedConnections = false;
451 // do not rebuild the logic when running netedit and all links are already covered by the program
452 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
453 // rebuild the logic from scratch
454 // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
455 NBOwnTLDef dummy(DummyID, myControlledNodes, 0, getType());
456 dummy.setParticipantsInformation();
457 dummy.setProgramID(getProgramID());
458 dummy.setTLControllingInformation();
459 NBTrafficLightLogic* newLogic = dummy.compute(OptionsCont::getOptions());
460 myIncomingEdges = dummy.getIncomingEdges();
461 myControlledLinks = dummy.getControlledLinks();
462 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
463 (*i)->removeTrafficLight(&dummy);
464 }
465 delete myTLLogic;
466 myTLLogic = newLogic;
467 if (newLogic != nullptr) {
468 newLogic->setID(getID());
469 newLogic->setType(getType());
470 newLogic->setOffset(getOffset());
471 setTLControllingInformation();
472 // reset crossing custom indices
473 for (NBNode* n : myControlledNodes) {
474 for (NBNode::Crossing* c : n->getCrossings()) {
475 c->customTLIndex = NBConnection::InvalidTlIndex;
476 }
477 }
478
479 }
480 } else {
481 setTLControllingInformation();
482 }
483 }
484 if (myReconstructRemovedConnections) {
485 myReconstructRemovedConnections = false;
486 // for each connection, check whether it is still valid
487 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
488 const NBConnection con = (*it);
489 if (// edge still exists
490 std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
491 // connection still exists
492 && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
493 // connection is still set to be controlled
494 && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane())) {
495 it++;
496 } else {
497 // remove connection
498 const int removed = con.getTLIndex();
499 it = myControlledLinks.erase(it);
500 // no automatic modificaions when running netedit
501 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
502 // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
503 bool exclusive = true;
504 for (NBConnection& other : myControlledLinks) {
505 if (other != con && other.getTLIndex() == removed) {
506 exclusive = false;
507 break;
508 }
509 }
510 if (exclusive) {
511 // shift indices above the removed index downward
512 for (NBConnection& other : myControlledLinks) {
513 if (other.getTLIndex() > removed) {
514 other.setTLIndex(other.getTLIndex() - 1);
515 }
516 }
517 // shift crossing custom indices above the removed index downward
518 for (NBNode* n : myControlledNodes) {
519 for (NBNode::Crossing* c : n->getCrossings()) {
520 if (c->customTLIndex > removed) {
521 c->customTLIndex--;
522 }
523 }
524 }
525 // rebuild the logic
526 const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
527 NBTrafficLightLogic* newLogic = new NBTrafficLightLogic(getID(), getProgramID(), 0, myOffset, myType);
528 for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
529 std::string newState = it->state;
530 newState.erase(newState.begin() + removed);
531 newLogic->addStep(it->duration, newState);
532 }
533 delete myTLLogic;
534 myTLLogic = newLogic;
535 }
536 }
537 }
538 }
539 setTLControllingInformation();
540 }
541 #ifdef DEBUG_RECONSTRUCTION
542 if (debugPrintModified) {
543 std::cout << " newLinks:\n";
544 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
545 std::cout << " " << *it << "\n";
546 }
547 }
548 #endif
549 }
550
551
552 int
getMaxIndex()553 NBLoadedSUMOTLDef::getMaxIndex() {
554 int maxIndex = -1;
555 for (const NBConnection& c : myControlledLinks) {
556 maxIndex = MAX2(maxIndex, c.getTLIndex());
557 }
558 for (NBNode* n : myControlledNodes) {
559 for (NBNode::Crossing* c : n->getCrossings()) {
560 maxIndex = MAX2(maxIndex, c->tlLinkIndex);
561 maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
562 }
563 }
564 return maxIndex;
565 }
566
567
568 int
getMaxValidIndex()569 NBLoadedSUMOTLDef::getMaxValidIndex() {
570 return myTLLogic->getNumLinks() - 1;
571 }
572
573
574 bool
hasValidIndices() const575 NBLoadedSUMOTLDef::hasValidIndices() const {
576 for (const NBConnection& c : myControlledLinks) {
577 if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
578 return false;
579 }
580 }
581 for (NBNode* n : myControlledNodes) {
582 for (NBNode::Crossing* c : n->getCrossings()) {
583 if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
584 return false;
585 }
586 }
587 }
588 // method getMaxIndex() is const but cannot be declare as such due to inheritance
589 return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
590 }
591
592
593 bool
cleanupStates()594 NBLoadedSUMOTLDef::cleanupStates() {
595 const int maxIndex = getMaxIndex();
596 if (maxIndex >= 0 && maxIndex + 1 < myTLLogic->getNumLinks()) {
597 myTLLogic->setStateLength(maxIndex + 1);
598 return true;
599 }
600 return false;
601 }
602
603 void
joinLogic(NBTrafficLightDefinition * def)604 NBLoadedSUMOTLDef::joinLogic(NBTrafficLightDefinition* def) {
605 def->setParticipantsInformation();
606 def->compute(OptionsCont::getOptions());
607 const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
608 myTLLogic->setStateLength(maxIndex + 1);
609 myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
610 myOriginalNodes.insert(def->getNodes().begin(), def->getNodes().end());
611 }
612
613 bool
usingSignalGroups() const614 NBLoadedSUMOTLDef::usingSignalGroups() const {
615 // count how often each index is used
616 std::map<int, int> indexUsage;
617 for (const NBConnection& c : myControlledLinks) {
618 indexUsage[c.getTLIndex()]++;
619 }
620 for (NBNode* n : myControlledNodes) {
621 for (NBNode::Crossing* c : n->getCrossings()) {
622 indexUsage[c->tlLinkIndex]++;
623 indexUsage[c->tlLinkIndex2]++;
624 }
625 }
626 for (auto it : indexUsage) {
627 if (it.first >= 0 && it.second > 1) {
628 return true;
629 }
630 }
631 return false;
632 }
633
634 /****************************************************************************/
635
636