Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIXMLTrafficLightsHandler.cpp
169665 views
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
/****************************************************************************/
14
/// @file NIXMLTrafficLightsHandler.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @date 2011-10-05
19
///
20
// Importer for traffic lights stored in XML
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <iostream>
26
#include <utils/common/StringTokenizer.h>
27
#include <utils/xml/SUMOSAXHandler.h>
28
#include <utils/xml/SUMOXMLDefinitions.h>
29
#include <utils/common/ToString.h>
30
#include <utils/common/StringUtils.h>
31
#include <utils/common/UtilExceptions.h>
32
#include <utils/common/MsgHandler.h>
33
#include <utils/options/OptionsCont.h>
34
#include <netbuild/NBEdge.h>
35
#include <netbuild/NBEdgeCont.h>
36
#include <netbuild/NBNode.h>
37
#include <netbuild/NBOwnTLDef.h>
38
#include <netbuild/NBLoadedSUMOTLDef.h>
39
#include <netbuild/NBTrafficLightLogicCont.h>
40
#include "NIImporter_SUMO.h"
41
#include "NIXMLTrafficLightsHandler.h"
42
43
44
// ===========================================================================
45
// method definitions
46
// ===========================================================================
47
NIXMLTrafficLightsHandler::NIXMLTrafficLightsHandler(
48
NBTrafficLightLogicCont& tlCont, NBEdgeCont& ec, bool ignoreUnknown) :
49
SUMOSAXHandler("xml-tllogics"),
50
myTLLCont(tlCont),
51
myEdgeCont(ec),
52
myCurrentTL(nullptr),
53
myResetPhases(false),
54
myIgnoreUnknown(ignoreUnknown)
55
{ }
56
57
58
NIXMLTrafficLightsHandler::~NIXMLTrafficLightsHandler() {}
59
60
61
void
62
NIXMLTrafficLightsHandler::myStartElement(
63
int element, const SUMOSAXAttributes& attrs) {
64
switch (element) {
65
case SUMO_TAG_TLLOGIC:
66
myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
67
break;
68
case SUMO_TAG_PHASE:
69
if (myCurrentTL != nullptr) {
70
if (myResetPhases) {
71
myCurrentTL->getLogic()->resetPhases();
72
myResetPhases = false;
73
}
74
NIImporter_SUMO::addPhase(attrs, myCurrentTL);
75
myCurrentTL->phasesLoaded();
76
}
77
break;
78
case SUMO_TAG_CONNECTION:
79
addTlConnection(attrs);
80
break;
81
case SUMO_TAG_DEL:
82
removeTlConnection(attrs);
83
break;
84
case SUMO_TAG_PARAM:
85
if (myCurrentTL != nullptr) {
86
bool ok = true;
87
const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
88
// circumventing empty string test
89
const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
90
myCurrentTL->setParameter(key, val);
91
}
92
break;
93
default:
94
break;
95
}
96
}
97
98
99
void
100
NIXMLTrafficLightsHandler::myEndElement(int element) {
101
switch (element) {
102
case SUMO_TAG_TLLOGIC:
103
myCurrentTL = nullptr;
104
break;
105
default:
106
break;
107
}
108
}
109
110
111
NBLoadedSUMOTLDef*
112
NIXMLTrafficLightsHandler::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
113
if (currentTL) {
114
WRITE_ERRORF(TL("Definition of tlLogic '%' was not finished."), currentTL->getID());
115
return nullptr;
116
}
117
bool ok = true;
118
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
119
std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "UNKNOWN_PROGRAM");
120
const SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);
121
std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok,
122
OptionsCont::getOptions().getString("tls.default-type"));
123
TrafficLightType type;
124
if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
125
type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
126
} else {
127
WRITE_ERRORF(TL("Unknown traffic light type '%' for tlLogic '%'."), typeS, id);
128
return nullptr;
129
}
130
// there are three scenarios to consider
131
// 1) the tll.xml is loaded to update traffic lights defined in a net.xml:
132
// simply retrieve the loaded definitions and update them
133
// 2) the tll.xml is loaded to define new traffic lights
134
// nod.xml will have triggered building of NBOwnTLDef. Replace it with NBLoadedSUMOTLDef
135
// 3) the tll.xml is loaded to define new programs for a defined traffic light
136
// there should be a definition with the same id but different programID
137
const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(id);
138
if (programs.size() == 0) {
139
if (!myIgnoreUnknown) {
140
WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);
141
}
142
return nullptr;
143
}
144
const std::string existingProgram = programs.begin()->first; // arbitrary for our purpose
145
NBLoadedSUMOTLDef* loadedDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, programID));
146
if (loadedDef == nullptr) {
147
NBLoadedSUMOTLDef* oldDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, existingProgram));
148
if (oldDef == nullptr) {
149
// case 2
150
NBTrafficLightDefinition* newDef = dynamic_cast<NBOwnTLDef*>(myTLLCont.getDefinition(
151
id, NBTrafficLightDefinition::DefaultProgramID));
152
bool deleteDefault = false;
153
if (newDef == nullptr) {
154
// the default program may have already been replaced with a loaded program
155
newDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(
156
id, NBTrafficLightDefinition::DefaultProgramID));
157
if (newDef == nullptr) {
158
WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);
159
return nullptr;
160
}
161
} else {
162
deleteDefault = true;
163
}
164
assert(newDef != nullptr);
165
loadedDef = new NBLoadedSUMOTLDef(id, programID, offset, type);
166
// copy nodes and controlled inner edges
167
for (NBNode* const n : newDef->getNodes()) {
168
loadedDef->addNode(n);
169
}
170
loadedDef->addControlledInnerEdges(newDef->getControlledInnerEdges());
171
if (deleteDefault) {
172
// make a copy because the vector is modified in the loop
173
const std::vector<NBNode*> nodes = newDef->getNodes();
174
// replace default Program
175
for (NBNode* const n : nodes) {
176
n->removeTrafficLight(newDef);
177
}
178
myTLLCont.removeProgram(id, NBTrafficLightDefinition::DefaultProgramID);
179
}
180
myTLLCont.insert(loadedDef);
181
} else {
182
// case 3
183
NBTrafficLightLogic* oldLogic = oldDef->getLogic();
184
NBTrafficLightLogic newLogic(id, programID, oldLogic->getNumLinks(), offset, type);
185
loadedDef = new NBLoadedSUMOTLDef(*oldDef, newLogic);
186
// copy nodes
187
std::vector<NBNode*> nodes = oldDef->getNodes();
188
for (std::vector<NBNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
189
loadedDef->addNode(*it);
190
}
191
//std::cout << " case3 oldDef=" << oldDef->getDescription() << " loadedDef=" << loadedDef->getDescription() << "\n";
192
myTLLCont.insert(loadedDef);
193
}
194
} else {
195
// case 1
196
if (attrs.hasAttribute(SUMO_ATTR_OFFSET)) {
197
loadedDef->setOffset(offset);
198
}
199
if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
200
loadedDef->setType(type);
201
}
202
}
203
if (ok) {
204
myResetPhases = true;
205
mySeenIDs.insert(id);
206
return loadedDef;
207
} else {
208
return nullptr;
209
}
210
}
211
212
213
void
214
NIXMLTrafficLightsHandler::addTlConnection(const SUMOSAXAttributes& attrs) {
215
bool ok = true;
216
// parse identifying attributes
217
NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);
218
NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);
219
if (!ok) {
220
return;
221
}
222
int fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok);
223
int toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok);
224
if (!ok) {
225
return;
226
}
227
// retrieve connection
228
const std::vector<NBEdge::Connection>& connections = from->getConnections();
229
std::vector<NBEdge::Connection>::const_iterator con_it;
230
con_it = find_if(connections.begin(), connections.end(),
231
NBEdge::connections_finder(fromLane, to, toLane));
232
if (con_it == connections.end()) {
233
WRITE_ERROR("Connection from=" + from->getID() + " to=" + to->getID() +
234
" fromLane=" + toString(fromLane) + " toLane=" + toString(toLane) + " not found");
235
return;
236
}
237
NBEdge::Connection c = *con_it;
238
// read other attributes
239
std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
240
if (tlID == "") {
241
// we are updating an existing tl-controlled connection
242
tlID = (*(from->getToNode()->getControllingTLS().begin()))->getID();
243
assert(tlID != "");
244
}
245
int tlIndex = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);
246
if (tlIndex == -1) {
247
// we are updating an existing tl-controlled connection
248
tlIndex = c.tlLinkIndex;
249
}
250
int tlIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);
251
if (tlIndex2 == -1) {
252
// we are updating an existing tl-controlled connection or index2 is not used
253
tlIndex2 = c.tlLinkIndex2;
254
}
255
256
// register the connection with all definitions
257
const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);
258
if (programs.size() > 0) {
259
std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
260
for (it = programs.begin(); it != programs.end(); it++) {
261
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
262
if (tlDef) {
263
tlDef->addConnection(from, c.toEdge, c.fromLane, c.toLane, tlIndex, tlIndex2, false);
264
} else {
265
throw ProcessError("Corrupt traffic light definition '"
266
+ tlID + "' (program '" + it->first + "')");
267
}
268
}
269
} else {
270
SumoXMLNodeType type = from->getToNode()->getType();
271
if (type != SumoXMLNodeType::RAIL_CROSSING && type != SumoXMLNodeType::RAIL_SIGNAL) {
272
WRITE_ERRORF(TL("The traffic light '%' is not known."), tlID);
273
}
274
}
275
}
276
277
278
void
279
NIXMLTrafficLightsHandler::removeTlConnection(const SUMOSAXAttributes& attrs) {
280
bool ok = true;
281
std::string tlID = attrs.get<std::string>(SUMO_ATTR_TLID, nullptr, ok);
282
// does the traffic light still exist?
283
const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);
284
if (programs.size() > 0) {
285
// parse identifying attributes
286
NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);
287
NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);
288
int fromLane = -1;
289
int toLane = -1;
290
if (ok) {
291
fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok, true);
292
toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok, true);
293
}
294
int tlIndex = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
295
296
NBConnection conn(from, fromLane, to, toLane, tlIndex);
297
// remove the connection from all definitions
298
std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
299
for (it = programs.begin(); it != programs.end(); it++) {
300
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
301
if (tlDef) {
302
tlDef->removeConnection(conn, false);
303
} else {
304
throw ProcessError("Corrupt traffic light definition '"
305
+ tlID + "' (program '" + it->first + "')");
306
}
307
}
308
}
309
}
310
311
312
NBEdge*
313
NIXMLTrafficLightsHandler::retrieveEdge(
314
const SUMOSAXAttributes& attrs, SumoXMLAttr attr, bool& ok) {
315
std::string edgeID = attrs.get<std::string>(attr, nullptr, ok);
316
NBEdge* edge = myEdgeCont.retrieve(edgeID, true);
317
if (edge == nullptr) {
318
WRITE_ERRORF(TL("Unknown edge '%' given in connection."), edgeID);
319
ok = false;
320
}
321
return edge;
322
}
323
324
325
int
326
NIXMLTrafficLightsHandler::retrieveLaneIndex(
327
const SUMOSAXAttributes& attrs, SumoXMLAttr attr, NBEdge* edge, bool& ok, bool isDelete) {
328
int laneIndex = attrs.get<int>(attr, nullptr, ok);
329
if (edge->getNumLanes() <= laneIndex) {
330
if (!isDelete) {
331
WRITE_ERRORF(TL("Invalid lane index '%' for edge '%'."), toString(laneIndex), edge->getID());
332
}
333
ok = false;
334
}
335
return laneIndex;
336
}
337
338
339
/****************************************************************************/
340
341