Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 : /****************************************************************************/
14 : /// @file NBTrafficLightLogicCont.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // A container for traffic light definitions and built programs
21 : /****************************************************************************/
22 : #include <config.h>
23 : #include <map>
24 : #include <string>
25 : #include <algorithm>
26 : #include <utils/common/MsgHandler.h>
27 : #include <utils/common/ToString.h>
28 : #include <utils/common/IDSupplier.h>
29 : #include <utils/iodevices/OutputDevice.h>
30 : #include <utils/options/OptionsCont.h>
31 : #include "NBTrafficLightLogic.h"
32 : #include "NBTrafficLightLogicCont.h"
33 : #include "NBOwnTLDef.h"
34 : #include "NBLoadedSUMOTLDef.h"
35 : #include "NBEdgeCont.h"
36 : #include "NBNodeCont.h"
37 :
38 :
39 : // ===========================================================================
40 : // static members
41 : // ===========================================================================
42 : const NBTrafficLightLogicCont::Program2Def NBTrafficLightLogicCont::EmptyDefinitions = NBTrafficLightLogicCont::Program2Def();
43 :
44 : // ===========================================================================
45 : // method definitions
46 : // ===========================================================================
47 2541 : NBTrafficLightLogicCont::NBTrafficLightLogicCont() {}
48 :
49 :
50 2541 : NBTrafficLightLogicCont::~NBTrafficLightLogicCont() {
51 2541 : clear();
52 2541 : }
53 :
54 :
55 : void
56 2531 : NBTrafficLightLogicCont::applyOptions(OptionsCont& oc) {
57 : // check whether any offsets shall be manipulated by setting
58 : // them to half of the duration
59 5062 : if (oc.isSet("tls.half-offset")) {
60 2 : std::vector<std::string> ids = oc.getStringVector("tls.half-offset");
61 : myHalfOffsetTLS.insert(ids.begin(), ids.end());
62 1 : }
63 : // check whether any offsets shall be manipulated by setting
64 : // them to a quarter of the duration
65 5062 : if (oc.isSet("tls.quarter-offset")) {
66 2 : std::vector<std::string> ids = oc.getStringVector("tls.quarter-offset");
67 : myQuarterOffsetTLS.insert(ids.begin(), ids.end());
68 1 : }
69 2531 : }
70 :
71 :
72 : std::string
73 0 : NBTrafficLightLogicCont::getNextProgramID(const std::string& id) const {
74 0 : IDSupplier idS("", 0);
75 : if (myDefinitions.count(id)) {
76 : const Program2Def& programs = myDefinitions.find(id)->second;
77 0 : for (auto item : programs) {
78 0 : idS.avoid(item.first);
79 : }
80 : }
81 0 : return idS.getNext();
82 0 : }
83 :
84 :
85 : bool
86 4768 : NBTrafficLightLogicCont::insert(NBTrafficLightDefinition* logic, bool forceInsert) {
87 : myExtracted.erase(logic);
88 4768 : if (myDefinitions.count(logic->getID())) {
89 53 : if (myDefinitions[logic->getID()].count(logic->getProgramID())) {
90 2 : if (forceInsert) {
91 0 : logic->setProgramID(getNextProgramID(logic->getID()));
92 : } else {
93 : return false;
94 : }
95 : }
96 : } else {
97 9430 : myDefinitions[logic->getID()] = Program2Def();
98 : }
99 4766 : myDefinitions[logic->getID()][logic->getProgramID()] = logic;
100 4766 : return true;
101 : }
102 :
103 :
104 : bool
105 148 : NBTrafficLightLogicCont::removeFully(const std::string id) {
106 : if (myDefinitions.count(id)) {
107 : // delete all programs
108 286 : for (Program2Def::iterator i = myDefinitions[id].begin(); i != myDefinitions[id].end(); i++) {
109 143 : delete i->second;
110 : }
111 : myDefinitions.erase(id);
112 : // also delete any logics that were already computed
113 : if (myComputed.count(id)) {
114 10 : for (Program2Logic::iterator i = myComputed[id].begin(); i != myComputed[id].end(); i++) {
115 5 : delete i->second;
116 : }
117 : myComputed.erase(id);
118 : }
119 143 : return true;
120 : } else {
121 5 : return false;
122 : }
123 : }
124 :
125 :
126 : bool
127 991 : NBTrafficLightLogicCont::removeProgram(const std::string id, const std::string programID, bool del) {
128 991 : if (myDefinitions.count(id) && myDefinitions[id].count(programID)) {
129 986 : if (del) {
130 38 : delete myDefinitions[id][programID];
131 : }
132 986 : myDefinitions[id].erase(programID);
133 0 : if (myComputed.count(id) && myComputed[id].count(programID)) {
134 0 : if (del) {
135 0 : delete myComputed[id][programID];
136 : }
137 0 : myComputed[id].erase(programID);
138 : }
139 986 : return true;
140 : } else {
141 5 : return false;
142 : }
143 : }
144 :
145 :
146 : void
147 953 : NBTrafficLightLogicCont::extract(NBTrafficLightDefinition* definition) {
148 : myExtracted.insert(definition);
149 2859 : removeProgram(definition->getID(), definition->getProgramID(), false);
150 953 : }
151 :
152 :
153 : bool
154 2 : NBTrafficLightLogicCont::exist(const std::string& newID, bool requireComputed) const {
155 : const auto itD = myDefinitions.find(newID);
156 : const auto itC = myComputed.find(newID);
157 2 : if ((itD != myDefinitions.end()) && (itC != myComputed.end() || !requireComputed)) {
158 1 : return true;
159 : } else {
160 : return false;
161 : }
162 : }
163 :
164 :
165 : std::pair<int, int>
166 2240 : NBTrafficLightLogicCont::computeLogics(OptionsCont& oc) {
167 : // clean previous logics
168 2240 : Logics logics = getComputed();
169 2240 : for (Logics::iterator it = logics.begin(); it != logics.end(); it++) {
170 0 : delete *it;
171 : }
172 : myComputed.clear();
173 4480 : if (oc.getBool("tls.rebuild")) {
174 21 : for (NBTrafficLightDefinition* def : getDefinitions()) {
175 13 : NBLoadedSUMOTLDef* lDef = dynamic_cast<NBLoadedSUMOTLDef*>(def);
176 13 : if (lDef != nullptr) {
177 : TrafficLightType type = def->getType();
178 26 : if (!oc.isDefault("tls.default-type")) {
179 14 : type = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
180 : }
181 13 : NBOwnTLDef* oDef = new NBOwnTLDef(def->getID(), def->getNodes(), def->getOffset(), type);
182 13 : oDef->setProgramID(def->getProgramID());
183 13 : oDef->setParticipantsInformation();
184 61 : for (NBEdge* e : oDef->getIncomingEdges()) {
185 48 : e->clearControllingTLInformation();
186 : }
187 13 : oDef->setTLControllingInformation();
188 27 : for (NBNode* node : oDef->getNodes()) {
189 14 : node->removeTrafficLight(def);
190 17 : for (auto c : node->getCrossings()) {
191 3 : c->customTLIndex = -1;
192 3 : c->customTLIndex2 = -1;
193 3 : c->tlLinkIndex2 = -1;
194 14 : }
195 : }
196 26 : removeProgram(def->getID(), def->getProgramID());
197 13 : insert(oDef);
198 : }
199 8 : }
200 : }
201 4480 : if (oc.getBool("tls.group-signals")) {
202 : // replace NBOwnTLDef tld with NBLoadedSUMOTLDef
203 8 : for (NBTrafficLightDefinition* def : getDefinitions()) {
204 4 : NBLoadedSUMOTLDef* lDef = dynamic_cast<NBLoadedSUMOTLDef*>(def);
205 4 : if (lDef == nullptr) {
206 2 : NBTrafficLightLogic* logic = def->compute(oc);
207 2 : if (logic != nullptr) {
208 2 : lDef = new NBLoadedSUMOTLDef(*def, *logic);
209 2 : lDef->setParticipantsInformation();
210 4 : for (NBNode* node : lDef->getNodes()) {
211 2 : node->removeTrafficLight(def);
212 2 : node->addTrafficLight(lDef);
213 : }
214 4 : removeProgram(def->getID(), def->getProgramID());
215 2 : insert(lDef);
216 2 : delete logic;
217 : }
218 : }
219 2 : if (lDef != nullptr) {
220 4 : lDef->groupSignals();
221 : }
222 4 : }
223 4472 : } else if (oc.getBool("tls.ungroup-signals")) {
224 4 : for (NBTrafficLightDefinition* def : getDefinitions()) {
225 2 : NBLoadedSUMOTLDef* lDef = dynamic_cast<NBLoadedSUMOTLDef*>(def);
226 : // NBOwnTLDef are always ungrouped
227 2 : if (lDef != nullptr) {
228 2 : if (lDef->usingSignalGroups()) {
229 2 : lDef->ungroupSignals();
230 : }
231 : }
232 2 : }
233 : }
234 : int numPrograms = 0;
235 5871 : for (NBTrafficLightDefinition* def : getDefinitions()) {
236 3631 : if (computeSingleLogic(oc, def)) {
237 2717 : numPrograms++;
238 : }
239 2240 : }
240 2240 : return std::pair<int, int>((int)myComputed.size(), numPrograms);
241 2240 : }
242 :
243 :
244 : bool
245 4432 : NBTrafficLightLogicCont::computeSingleLogic(OptionsCont& oc, NBTrafficLightDefinition* def) {
246 4432 : if (def->getNodes().size() == 0) {
247 : return false;
248 : }
249 : const std::string& id = def->getID();
250 : const std::string& programID = def->getProgramID();
251 : // build program
252 3583 : NBTrafficLightLogic* built = def->compute(oc);
253 3583 : if (built == nullptr) {
254 195 : WRITE_WARNINGF(TL("Could not build program '%' for traffic light '%'"), programID, id);
255 65 : return false;
256 : }
257 : // compute offset
258 3518 : SUMOTime T = built->getDuration();
259 : if (myHalfOffsetTLS.count(id)) {
260 2 : built->setOffset(TIME2STEPS(floor(STEPS2TIME(T / 2))));
261 : }
262 : if (myQuarterOffsetTLS.count(id)) {
263 2 : built->setOffset(TIME2STEPS(floor(STEPS2TIME(T / 4))));
264 : }
265 : // and insert the result after computation
266 : // make sure we don't leak memory if computeSingleLogic is called externally
267 3518 : if (myComputed[id][programID] != nullptr) {
268 801 : delete myComputed[id][programID];
269 : }
270 3518 : myComputed[id][programID] = built;
271 3518 : return true;
272 : }
273 :
274 :
275 : void
276 2541 : NBTrafficLightLogicCont::clear() {
277 2541 : Definitions definitions = getDefinitions();
278 6178 : for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) {
279 3637 : delete *it;
280 : }
281 : myDefinitions.clear();
282 2541 : Logics logics = getComputed();
283 5253 : for (Logics::iterator it = logics.begin(); it != logics.end(); it++) {
284 2712 : delete *it;
285 : }
286 : myComputed.clear();
287 3489 : for (std::set<NBTrafficLightDefinition*>::iterator it = myExtracted.begin(); it != myExtracted.end(); it++) {
288 948 : delete *it;
289 : }
290 : myExtracted.clear();
291 2541 : }
292 :
293 :
294 : void
295 0 : NBTrafficLightLogicCont::remapRemoved(NBEdge* removed, const EdgeVector& incoming,
296 : const EdgeVector& outgoing) {
297 0 : Definitions definitions = getDefinitions();
298 0 : for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) {
299 0 : (*it)->remapRemoved(removed, incoming, outgoing);
300 : }
301 0 : }
302 :
303 :
304 : void
305 54 : NBTrafficLightLogicCont::replaceRemoved(NBEdge* removed, int removedLane,
306 : NBEdge* by, int byLane, bool incoming) {
307 54 : Definitions definitions = getDefinitions();
308 340 : for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) {
309 286 : (*it)->replaceRemoved(removed, removedLane, by, byLane, incoming);
310 : }
311 54 : }
312 :
313 :
314 : NBTrafficLightDefinition*
315 2845 : NBTrafficLightLogicCont::getDefinition(const std::string& id, const std::string& programID) const {
316 : Id2Defs::const_iterator i = myDefinitions.find(id);
317 2845 : if (i != myDefinitions.end()) {
318 : Program2Def programs = i->second;
319 : Program2Def::const_iterator i2 = programs.find(programID);
320 2845 : if (i2 != programs.end()) {
321 2829 : return i2->second;
322 : }
323 : }
324 : return nullptr;
325 : }
326 :
327 : const NBTrafficLightLogicCont::Program2Def&
328 11605 : NBTrafficLightLogicCont::getPrograms(const std::string& id) const {
329 : Id2Defs::const_iterator it = myDefinitions.find(id);
330 11605 : if (it != myDefinitions.end()) {
331 11259 : return it->second;
332 : } else {
333 : return EmptyDefinitions;
334 : }
335 : }
336 :
337 :
338 : NBTrafficLightLogic*
339 0 : NBTrafficLightLogicCont::getLogic(const std::string& id, const std::string& programID) const {
340 : Id2Logics::const_iterator i = myComputed.find(id);
341 0 : if (i != myComputed.end()) {
342 : Program2Logic programs = i->second;
343 : Program2Logic::const_iterator i2 = programs.find(programID);
344 0 : if (i2 != programs.end()) {
345 0 : return i2->second;
346 : }
347 : }
348 : return nullptr;
349 : }
350 :
351 :
352 : void
353 2241 : NBTrafficLightLogicCont::setTLControllingInformation(const NBEdgeCont& ec, const NBNodeCont& nc) {
354 2241 : Definitions definitions = getDefinitions();
355 : // set the information about all participants, first
356 5874 : for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) {
357 3633 : (*it)->setParticipantsInformation();
358 : }
359 : // clear previous information because tlDefs may have been removed in netedit
360 2241 : ec.clearControllingTLInformation();
361 : // insert the information about the tl-controlling
362 5872 : for (Definitions::iterator it = definitions.begin(); it != definitions.end(); it++) {
363 3632 : (*it)->setTLControllingInformation();
364 : }
365 : // handle rail signals which are not instantiated as normal definitions
366 73128 : for (std::map<std::string, NBNode*>::const_iterator it = nc.begin(); it != nc.end(); it ++) {
367 70888 : NBNode* n = it->second;
368 70888 : if (n->getType() == SumoXMLNodeType::RAIL_SIGNAL || n->getType() == SumoXMLNodeType::RAIL_CROSSING) {
369 1829 : NBOwnTLDef dummy(n->getID(), n, 0, TrafficLightType::STATIC);
370 1829 : dummy.setParticipantsInformation();
371 1829 : dummy.setTLControllingInformation();
372 1829 : n->setCrossingTLIndices(dummy.getID(), (int)dummy.getControlledLinks().size());
373 1829 : n->removeTrafficLight(&dummy);
374 1829 : }
375 : }
376 2241 : }
377 :
378 :
379 : void
380 23 : NBTrafficLightLogicCont::setOpenDriveSignalParameters() {
381 23 : Definitions definitions = getDefinitions();
382 26 : for (NBTrafficLightDefinition* def : getDefinitions()) {
383 : std::map<NBEdge*, std::string> defaultSignalIDs;
384 28 : for (const NBConnection& con : def->getControlledLinks()) {
385 25 : const NBEdge::Connection& c = con.getFrom()->getConnection(con.getFromLane(), con.getTo(), con.getToLane());
386 50 : if (c.hasParameter("signalID")) {
387 75 : defaultSignalIDs[con.getFrom()] = c.getParameter("signalID");
388 100 : def->setParameter("linkSignalID:" + toString(con.getTLIndex()), c.getParameter("signalID"));
389 : }
390 : }
391 : // oftentimes, signals are placed on connecting road but are meant to apply to all connections from the incoming edge
392 28 : for (const NBConnection& con : def->getControlledLinks()) {
393 25 : const NBEdge::Connection& c = con.getFrom()->getConnection(con.getFromLane(), con.getTo(), con.getToLane());
394 50 : if (!c.hasParameter("signalID") && defaultSignalIDs.count(con.getFrom()) != 0) {
395 0 : WRITE_WARNINGF(TL("Guessing signalID for link index % at traffic light '%'."), con.getTLIndex(), def->getID());
396 0 : def->setParameter("linkSignalID:" + toString(con.getTLIndex()), defaultSignalIDs[con.getFrom()]);
397 : }
398 : }
399 23 : }
400 23 : }
401 :
402 :
403 : void
404 0 : NBTrafficLightLogicCont::applyOpenDriveControllers(OptionsCont& oc) {
405 : // collect connections with controllerID which can be controlled together
406 0 : Definitions definitions = getDefinitions();
407 : std::map<std::string, NBTrafficLightDefinition*> defsToGroup;
408 : std::map<std::string, std::map<std::string, std::set<int>>> controllerID2tlIndex;
409 0 : for (NBTrafficLightDefinition* def : definitions) {
410 : bool makeGroups = false;
411 : NBConnectionVector& connections = def->getControlledLinks();
412 : std::string defID = def->getID();
413 :
414 0 : for (NBConnection conn : connections) {
415 0 : std::string controllerID = conn.getFrom()->getConnection(conn.getFromLane(), conn.getTo(), conn.getToLane()).getParameter("controllerID");
416 0 : if (controllerID != "") {
417 0 : if (controllerID2tlIndex.find(defID) == controllerID2tlIndex.end()) {
418 0 : controllerID2tlIndex[defID][controllerID] = std::set<int>({ conn.getTLIndex() });
419 0 : } else if (controllerID2tlIndex[defID].find(controllerID) != controllerID2tlIndex[defID].end()) {
420 0 : controllerID2tlIndex[defID][controllerID].insert(conn.getTLIndex());
421 : } else {
422 0 : controllerID2tlIndex[defID][controllerID] = std::set<int>({ conn.getTLIndex() });
423 : }
424 0 : makeGroups = controllerID2tlIndex[defID][controllerID].size() > 1 || makeGroups;
425 : }
426 0 : }
427 0 : if (makeGroups) {
428 0 : defsToGroup[def->getID()] = def;
429 : }
430 : }
431 : bool same = true;
432 0 : for (NBTrafficLightLogic* computed : getComputed()) {
433 : const std::string computedID = computed->getID();
434 0 : if (defsToGroup.find(computedID) != defsToGroup.end()) {
435 : // remember corresponding tl indices and check if they can be joined
436 : // execute tl index joins if possible
437 0 : const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = computed->getPhases();
438 : std::vector<int> major2minor;
439 0 : for (const auto& indexSet : controllerID2tlIndex[computedID]) {
440 0 : if (indexSet.second.size() < 2) {
441 0 : continue;
442 : }
443 : bool toMinor = false;
444 0 : for (NBTrafficLightLogic::PhaseDefinition phase : phases) {
445 : std::set<int>::iterator it = indexSet.second.begin();
446 0 : char firstChar = phase.state[*it];
447 0 : if (firstChar == LINKSTATE_TL_GREEN_MAJOR) {
448 : firstChar = LINKSTATE_TL_GREEN_MINOR;
449 : }
450 : it++;
451 0 : for (; it != indexSet.second.end(); it++) {
452 0 : const char compareChar = (phase.state[*it] != LINKSTATE_TL_GREEN_MAJOR) ? phase.state[*it] : (char)LINKSTATE_TL_GREEN_MINOR;
453 0 : if (compareChar != firstChar) {
454 : same = false;
455 : break;
456 0 : } else if (phase.state[*it] == LINKSTATE_TL_GREEN_MINOR) {
457 : toMinor = true;
458 : }
459 : }
460 0 : if (!same) {
461 : break;
462 : }
463 0 : }
464 0 : if (toMinor) {
465 0 : major2minor.push_back(*indexSet.second.begin());
466 : }
467 : }
468 0 : if (same) {
469 0 : NBLoadedSUMOTLDef* lDef = dynamic_cast<NBLoadedSUMOTLDef*>(defsToGroup[computedID]);
470 0 : if (lDef == nullptr) {
471 0 : lDef = new NBLoadedSUMOTLDef(*defsToGroup[computedID], *computed);
472 0 : lDef->setParticipantsInformation();
473 0 : for (int index : major2minor) { // update the signal states (G -> g where needed)
474 0 : for (int i = 0; i < (int)phases.size(); i++) {
475 0 : if (phases[i].state[index] == LINKSTATE_TL_GREEN_MAJOR) {
476 0 : lDef->getLogic()->setPhaseState(i, index, LINKSTATE_TL_GREEN_MINOR);
477 : }
478 : }
479 : }
480 : // join signal groups, update the connections
481 : std::vector<int> indexToRemove;
482 0 : for (const auto& indexSet : controllerID2tlIndex[computedID]) {
483 0 : int minIndex = *indexSet.second.begin();
484 0 : for (int index : indexSet.second) {
485 0 : if (index != minIndex) {
486 0 : lDef->replaceIndex(index, minIndex);
487 0 : indexToRemove.push_back(index);
488 : }
489 : }
490 : }
491 : // remove unused indices from signal programs
492 0 : lDef->cleanupStates();
493 0 : for (NBNode* node : lDef->getNodes()) {
494 0 : node->removeTrafficLight(defsToGroup[computedID]);
495 0 : node->addTrafficLight(lDef);
496 : }
497 0 : removeProgram(defsToGroup[computedID]->getID(), defsToGroup[computedID]->getProgramID());
498 0 : insert(lDef);
499 0 : computeSingleLogic(oc, lDef);
500 0 : }
501 : } else { // TODO: try other strategy to build signal groups
502 0 : WRITE_WARNINGF(TL("Was not able to apply the OpenDRIVE signal group information onto the signal program of traffic light % generated by SUMO."), computed->getID());
503 : }
504 : break;
505 0 : }
506 0 : }
507 0 : }
508 :
509 :
510 : NBTrafficLightLogicCont::Logics
511 7107 : NBTrafficLightLogicCont::getComputed() const {
512 : Logics result;
513 12539 : for (Id2Logics::const_iterator it_id = myComputed.begin(); it_id != myComputed.end(); it_id++) {
514 : const Program2Logic& programs = it_id->second;
515 10887 : for (Program2Logic::const_iterator it_prog = programs.begin(); it_prog != programs.end(); it_prog++) {
516 5455 : result.push_back(it_prog->second);
517 : }
518 : }
519 7107 : return result;
520 0 : }
521 :
522 :
523 : NBTrafficLightLogicCont::Definitions
524 7136 : NBTrafficLightLogicCont::getDefinitions() const {
525 : Definitions result;
526 21185 : for (Id2Defs::const_iterator it_id = myDefinitions.begin(); it_id != myDefinitions.end(); it_id++) {
527 : const Program2Def& programs = it_id->second;
528 25261 : for (Program2Def::const_iterator it_prog = programs.begin(); it_prog != programs.end(); it_prog++) {
529 11212 : result.push_back(it_prog->second);
530 : }
531 : }
532 7136 : return result;
533 0 : }
534 :
535 :
536 : void
537 21 : NBTrafficLightLogicCont::rename(NBTrafficLightDefinition* tlDef, const std::string& newID) {
538 : auto it = myDefinitions.find(tlDef->getID());
539 21 : if (it != myDefinitions.end()) {
540 42 : for (auto item : it->second) {
541 21 : item.second->setID(newID);
542 : }
543 21 : myDefinitions[newID] = it->second;
544 : myDefinitions.erase(it);
545 : }
546 : auto it2 = myComputed.find(tlDef->getID());
547 21 : if (it2 != myComputed.end()) {
548 0 : for (auto item : it2->second) {
549 0 : item.second->setID(newID);
550 : }
551 0 : myComputed[newID] = it2->second;
552 : myComputed.erase(it2);
553 : }
554 21 : }
555 :
556 :
557 : int
558 56 : NBTrafficLightLogicCont::getNumExtracted() const {
559 56 : return (int)myExtracted.size();
560 : }
561 :
562 : /****************************************************************************/
|