Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIImporter_SUMO.cpp
169666 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-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 NIImporter_SUMO.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Leonhard Luecken
19
/// @date Mon, 14.04.2008
20
///
21
// Importer for networks stored in SUMO format
22
/****************************************************************************/
23
#include <config.h>
24
#include <string>
25
#include <utils/common/UtilExceptions.h>
26
#include <utils/common/StringUtils.h>
27
#include <utils/common/MsgHandler.h>
28
#include <utils/common/StringTokenizer.h>
29
#include <utils/common/FileHelpers.h>
30
#include <utils/common/ToString.h>
31
#include <utils/common/StringUtils.h>
32
#include <utils/xml/SUMOXMLDefinitions.h>
33
#include <utils/xml/SUMOSAXHandler.h>
34
#include <utils/xml/XMLSubSys.h>
35
#include <utils/geom/GeoConvHelper.h>
36
#include <utils/geom/GeomConvHelper.h>
37
#include <utils/options/OptionsCont.h>
38
#include <netbuild/NBEdge.h>
39
#include <netbuild/NBEdgeCont.h>
40
#include <netbuild/NBNode.h>
41
#include <netbuild/NBNodeCont.h>
42
#include <netbuild/NBAlgorithms_Ramps.h>
43
#include <netbuild/NBNetBuilder.h>
44
#include "NILoader.h"
45
#include "NIXMLTypesHandler.h"
46
#include "NIImporter_SUMO.h"
47
48
49
// ===========================================================================
50
// method definitions
51
// ===========================================================================
52
// ---------------------------------------------------------------------------
53
// static methods (interface in this case)
54
// ---------------------------------------------------------------------------
55
void
56
NIImporter_SUMO::loadNetwork(OptionsCont& oc, NBNetBuilder& nb) {
57
NIImporter_SUMO importer(nb);
58
importer._loadNetwork(oc);
59
}
60
61
62
// ---------------------------------------------------------------------------
63
// loader methods
64
// ---------------------------------------------------------------------------
65
NIImporter_SUMO::NIImporter_SUMO(NBNetBuilder& nb)
66
: SUMOSAXHandler("sumo-network"),
67
myNetBuilder(nb),
68
myNodeCont(nb.getNodeCont()),
69
myTLLCont(nb.getTLLogicCont()),
70
myTypesHandler(nb.getTypeCont()),
71
myCurrentEdge(nullptr),
72
myCurrentLane(nullptr),
73
myCurrentTL(nullptr),
74
myLocation(nullptr),
75
myNetworkVersion(0, 0),
76
myHaveSeenInternalEdge(false),
77
myAmLefthand(false),
78
myChangeLefthand(false),
79
myCornerDetail(0),
80
myLinkDetail(-1),
81
myRectLaneCut(false),
82
myWalkingAreas(false),
83
myLimitTurnSpeed(-1),
84
myCheckLaneFoesAll(false),
85
myCheckLaneFoesRoundabout(true),
86
myTlsIgnoreInternalJunctionJam(false),
87
myDefaultSpreadType(toString(LaneSpreadFunction::RIGHT)),
88
myGeomAvoidOverlap(false),
89
myJunctionsHigherSpeed(false),
90
myInternalJunctionsVehicleWidth(OptionsCont::getOptions().getFloat("internal-junctions.vehicle-width")),
91
myJunctionsMinimalShape(OptionsCont::getOptions().getBool("junctions.minimal-shape")),
92
myJunctionsEndpointShape(OptionsCont::getOptions().getBool("junctions.endpoint-shape")) {
93
}
94
95
96
NIImporter_SUMO::~NIImporter_SUMO() {
97
for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
98
EdgeAttrs* ed = (*i).second;
99
for (std::vector<LaneAttrs*>::const_iterator j = ed->lanes.begin(); j != ed->lanes.end(); ++j) {
100
delete *j;
101
}
102
delete ed;
103
}
104
delete myLocation;
105
}
106
107
108
void
109
NIImporter_SUMO::_loadNetwork(OptionsCont& oc) {
110
// check whether the option is set (properly)
111
if (!oc.isUsableFileList("sumo-net-file")) {
112
return;
113
}
114
const std::vector<std::string> discardableParams = oc.getStringVector("discard-params");
115
myDiscardableParams.insert(discardableParams.begin(), discardableParams.end());
116
// parse file(s)
117
const std::vector<std::string> files = oc.getStringVector("sumo-net-file");
118
for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
119
if (!FileHelpers::isReadable(*file)) {
120
WRITE_ERRORF(TL("Could not open sumo-net-file '%'."), *file);
121
return;
122
}
123
setFileName(*file);
124
const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing sumo-net from '" + *file + "'");
125
XMLSubSys::runParser(*this, *file, true);
126
PROGRESS_TIME_MESSAGE(before);
127
}
128
// build edges
129
const double maxSegmentLength = oc.getFloat("geometry.max-segment-length");
130
for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
131
EdgeAttrs* ed = (*i).second;
132
// skip internal edges
133
if (ed->func == SumoXMLEdgeFunc::INTERNAL || ed->func == SumoXMLEdgeFunc::CROSSING || ed->func == SumoXMLEdgeFunc::WALKINGAREA) {
134
continue;
135
}
136
// get and check the nodes
137
NBNode* from = myNodeCont.retrieve(ed->fromNode);
138
NBNode* to = myNodeCont.retrieve(ed->toNode);
139
if (from == nullptr) {
140
WRITE_ERRORF(TL("Edge's '%' from-node '%' is not known."), ed->id, ed->fromNode);
141
continue;
142
}
143
if (to == nullptr) {
144
WRITE_ERRORF(TL("Edge's '%' to-node '%' is not known."), ed->id, ed->toNode);
145
continue;
146
}
147
if (from == to) {
148
WRITE_ERRORF(TL("Edge's '%' from-node and to-node '%' are identical."), ed->id, ed->toNode);
149
continue;
150
}
151
if (ed->shape.size() == 0 && maxSegmentLength > 0) {
152
ed->shape.push_back(from->getPosition());
153
ed->shape.push_back(to->getPosition());
154
// shape is already cartesian but we must use a copy because the original will be modified
155
NBNetBuilder::addGeometrySegments(ed->shape, PositionVector(ed->shape), maxSegmentLength);
156
}
157
// build and insert the edge
158
NBEdge* e = new NBEdge(ed->id, from, to,
159
ed->type, ed->maxSpeed, NBEdge::UNSPECIFIED_FRICTION,
160
(int) ed->lanes.size(),
161
ed->priority, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
162
ed->shape, ed->lsf, ed->streetName, "", true); // always use tryIgnoreNodePositions to keep original shape
163
e->setLoadedLength(ed->length);
164
e->updateParameters(ed->getParametersMap());
165
e->setDistance(ed->distance);
166
if (!myNetBuilder.getEdgeCont().insert(e)) {
167
WRITE_ERRORF(TL("Could not insert edge '%'."), ed->id);
168
delete e;
169
continue;
170
}
171
ed->builtEdge = myNetBuilder.getEdgeCont().retrieve(ed->id);
172
if (ed->builtEdge != nullptr) {
173
ed->builtEdge->setEdgeStopOffset(-1, ed->edgeStopOffset);
174
ed->builtEdge->setBidi(ed->bidi != "");
175
}
176
}
177
// assign further lane attributes (edges are built)
178
EdgeVector toRemove;
179
const bool dismissVclasses = oc.getBool("dismiss-vclasses");
180
for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
181
EdgeAttrs* ed = (*i).second;
182
NBEdge* nbe = ed->builtEdge;
183
if (nbe == nullptr) { // inner edge or removed by explicit list, vclass, ...
184
continue;
185
}
186
const SumoXMLNodeType toType = nbe->getToNode()->getType();
187
for (int fromLaneIndex = 0; fromLaneIndex < (int) ed->lanes.size(); ++fromLaneIndex) {
188
LaneAttrs* lane = ed->lanes[fromLaneIndex];
189
// connections
190
const std::vector<Connection>& connections = lane->connections;
191
for (const Connection& c : connections) {
192
if (myEdges.count(c.toEdgeID) == 0) {
193
WRITE_ERRORF(TL("Unknown edge '%' given in connection."), c.toEdgeID);
194
continue;
195
}
196
NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge;
197
if (toEdge == nullptr) { // removed by explicit list, vclass, ...
198
continue;
199
}
200
if (toEdge->getFromNode() != nbe->getToNode()) { // inconsistency may occur when merging networks
201
WRITE_WARNINGF("Removing invalid connection from edge '%' to edge '%'", nbe->getID(), toEdge->getID());
202
continue;
203
}
204
// patch attribute uncontrolled for legacy networks where it is not set explicitly
205
bool uncontrolled = c.uncontrolled;
206
207
if ((NBNode::isTrafficLight(toType) || toType == SumoXMLNodeType::RAIL_SIGNAL)
208
&& c.tlLinkIndex == NBConnection::InvalidTlIndex) {
209
uncontrolled = true;
210
}
211
nbe->addLane2LaneConnection(
212
fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::Lane2LaneInfoType::VALIDATED,
213
true, c.mayDefinitelyPass, c.keepClear ? KEEPCLEAR_TRUE : KEEPCLEAR_FALSE,
214
c.contPos, c.visibility, c.speed, c.friction, c.customLength, c.customShape, uncontrolled, c.permissions, c.indirectLeft, c.edgeType, c.changeLeft, c.changeRight);
215
if (c.getParametersMap().size() > 0) {
216
nbe->getConnectionRef(fromLaneIndex, toEdge, c.toLaneIdx).updateParameters(c.getParametersMap());
217
}
218
// maybe we have a tls-controlled connection
219
if (c.tlID != "" && myRailSignals.count(c.tlID) == 0) {
220
const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
221
if (programs.size() > 0) {
222
std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
223
for (it = programs.begin(); it != programs.end(); it++) {
224
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
225
if (tlDef) {
226
tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkIndex, c.tlLinkIndex2, false);
227
} else {
228
throw ProcessError("Corrupt traffic light definition '" + c.tlID + "' (program '" + it->first + "')");
229
}
230
}
231
} else {
232
WRITE_ERRORF(TL("The traffic light '%' is not known."), c.tlID);
233
}
234
}
235
}
236
// allow/disallow XXX preferred
237
if (!dismissVclasses) {
238
nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow, myNetworkVersion), fromLaneIndex);
239
}
240
nbe->setPermittedChanging(fromLaneIndex, parseVehicleClasses(lane->changeLeft, ""), parseVehicleClasses(lane->changeRight, ""));
241
// width, offset
242
nbe->setLaneWidth(fromLaneIndex, lane->width);
243
nbe->setEndOffset(fromLaneIndex, lane->endOffset);
244
nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
245
nbe->setFriction(fromLaneIndex, lane->friction);
246
nbe->setAcceleration(fromLaneIndex, lane->accelRamp);
247
nbe->getLaneStruct(fromLaneIndex).oppositeID = lane->oppositeID;
248
nbe->getLaneStruct(fromLaneIndex).type = lane->type;
249
nbe->getLaneStruct(fromLaneIndex).updateParameters(lane->getParametersMap());
250
if (lane->customShape) {
251
nbe->setLaneShape(fromLaneIndex, lane->shape);
252
}
253
// stop offset for lane
254
bool stopOffsetSet = false;
255
if (lane->laneStopOffset.isDefined() || nbe->getEdgeStopOffset().isDefined()) {
256
// apply lane-specific stopOffset (might be none as well)
257
stopOffsetSet = nbe->setEdgeStopOffset(fromLaneIndex, lane->laneStopOffset);
258
}
259
if (!stopOffsetSet) {
260
// apply default stop offset to lane
261
nbe->setEdgeStopOffset(fromLaneIndex, nbe->getEdgeStopOffset());
262
}
263
}
264
nbe->declareConnectionsAsLoaded();
265
if (!nbe->hasLaneSpecificWidth() && nbe->getLanes()[0].width != NBEdge::UNSPECIFIED_WIDTH) {
266
nbe->setLaneWidth(-1, nbe->getLaneWidth(0));
267
}
268
if (!nbe->hasLaneSpecificEndOffset() && nbe->getEndOffset(0) != NBEdge::UNSPECIFIED_OFFSET) {
269
nbe->setEndOffset(-1, nbe->getEndOffset(0));
270
}
271
if (!nbe->hasLaneSpecificStopOffsets() && nbe->getEdgeStopOffset().isDefined()) {
272
nbe->setEdgeStopOffset(-1, nbe->getEdgeStopOffset());
273
}
274
// check again after permissions are set
275
if (myNetBuilder.getEdgeCont().ignoreFilterMatch(nbe)) {
276
myNetBuilder.getEdgeCont().ignore(nbe->getID());
277
toRemove.push_back(nbe);
278
}
279
}
280
for (EdgeVector::iterator i = toRemove.begin(); i != toRemove.end(); ++i) {
281
myNetBuilder.getEdgeCont().erase(myNetBuilder.getDistrictCont(), *i);
282
}
283
// insert loaded prohibitions
284
for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
285
NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
286
NBEdge* prohibitedTo = myEdges[it->prohibitedTo]->builtEdge;
287
NBEdge* prohibitorFrom = myEdges[it->prohibitorFrom]->builtEdge;
288
NBEdge* prohibitorTo = myEdges[it->prohibitorTo]->builtEdge;
289
if (prohibitedFrom == nullptr) {
290
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitedFrom);
291
} else if (prohibitedTo == nullptr) {
292
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitedTo);
293
} else if (prohibitorFrom == nullptr) {
294
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitorFrom);
295
} else if (prohibitorTo == nullptr) {
296
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitorTo);
297
} else {
298
NBNode* n = prohibitedFrom->getToNode();
299
n->addSortedLinkFoes(
300
NBConnection(prohibitorFrom, prohibitorTo),
301
NBConnection(prohibitedFrom, prohibitedTo));
302
}
303
}
304
if (!myHaveSeenInternalEdge && oc.isWriteable("no-internal-links")) {
305
oc.set("no-internal-links", "true");
306
}
307
if (oc.isWriteable("lefthand")) {
308
oc.set("lefthand", toString(myAmLefthand));
309
}
310
if (oc.isWriteable("junctions.corner-detail")) {
311
oc.set("junctions.corner-detail", toString(myCornerDetail));
312
}
313
if (oc.isWriteable("junctions.internal-link-detail") && myLinkDetail > 0) {
314
oc.set("junctions.internal-link-detail", toString(myLinkDetail));
315
}
316
if (oc.isWriteable("rectangular-lane-cut")) {
317
oc.set("rectangular-lane-cut", toString(myRectLaneCut));
318
}
319
if (oc.isWriteable("walkingareas")) {
320
oc.set("walkingareas", toString(myWalkingAreas));
321
}
322
if (oc.isWriteable("junctions.limit-turn-speed")) {
323
oc.set("junctions.limit-turn-speed", toString(myLimitTurnSpeed));
324
}
325
if (oc.isWriteable("check-lane-foes.all") && oc.getBool("check-lane-foes.all") != myCheckLaneFoesAll) {
326
oc.set("check-lane-foes.all", toString(myCheckLaneFoesAll));
327
}
328
if (oc.isWriteable("check-lane-foes.roundabout") && oc.getBool("check-lane-foes.roundabout") != myCheckLaneFoesRoundabout) {
329
oc.set("check-lane-foes.roundabout", toString(myCheckLaneFoesRoundabout));
330
}
331
if (oc.isWriteable("tls.ignore-internal-junction-jam") && oc.getBool("tls.ignore-internal-junction-jam") != myTlsIgnoreInternalJunctionJam) {
332
oc.set("tls.ignore-internal-junction-jam", toString(myTlsIgnoreInternalJunctionJam));
333
}
334
if (oc.isWriteable("default.spreadtype") && oc.getString("default.spreadtype") != myDefaultSpreadType) {
335
oc.set("default.spreadtype", myDefaultSpreadType);
336
}
337
if (oc.isWriteable("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap") != myGeomAvoidOverlap) {
338
oc.set("geometry.avoid-overlap", toString(myGeomAvoidOverlap));
339
}
340
if (oc.isWriteable("junctions.higher-speed") && oc.getBool("junctions.higher-speed") != myJunctionsHigherSpeed) {
341
oc.set("junctions.higher-speed", toString(myJunctionsHigherSpeed));
342
}
343
if (oc.isWriteable("internal-junctions.vehicle-width") && oc.getFloat("internal-junctions.vehicle-width") != myInternalJunctionsVehicleWidth) {
344
oc.set("internal-junctions.vehicle-width", toString(myInternalJunctionsVehicleWidth));
345
}
346
if (oc.isWriteable("junctions.minimal-shape") && oc.getBool("junctions.minimal-shape") != myJunctionsMinimalShape) {
347
oc.set("junctions.minimal-shape", toString(myJunctionsMinimalShape));
348
}
349
if (oc.isWriteable("junctions.endpoint-shape") && oc.getBool("junctions.endpoint-shape") != myJunctionsEndpointShape) {
350
oc.set("junctions.endpoint-shape", toString(myJunctionsEndpointShape));
351
}
352
if (!deprecatedVehicleClassesSeen.empty()) {
353
WRITE_WARNINGF(TL("Deprecated vehicle class(es) '%' in input network."), toString(deprecatedVehicleClassesSeen));
354
deprecatedVehicleClassesSeen.clear();
355
}
356
if (!oc.getBool("no-internal-links")) {
357
// add loaded crossings
358
for (const auto& crossIt : myPedestrianCrossings) {
359
NBNode* const node = myNodeCont.retrieve(crossIt.first);
360
for (const Crossing& crossing : crossIt.second) {
361
EdgeVector edges;
362
for (const std::string& edgeID : crossing.crossingEdges) {
363
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
364
// edge might have been removed due to options
365
if (edge != nullptr) {
366
edges.push_back(edge);
367
}
368
}
369
if (!edges.empty()) {
370
node->addCrossing(edges, crossing.width, crossing.priority,
371
crossing.customTLIndex, crossing.customTLIndex2, crossing.customShape, true, &crossing);
372
}
373
}
374
}
375
myNetBuilder.setHaveNetworkCrossings(myPedestrianCrossings.size() > 0);
376
// add walking area custom shapes
377
for (const auto& item : myWACustomShapes) {
378
std::string nodeID = SUMOXMLDefinitions::getJunctionIDFromInternalEdge(item.first);
379
NBNode* node = myNodeCont.retrieve(nodeID);
380
std::vector<std::string> edgeIDs;
381
if (item.second.fromEdges.size() + item.second.toEdges.size() == 0) {
382
// must be a split crossing
383
assert(item.second.fromCrossed.size() > 0);
384
assert(item.second.toCrossed.size() > 0);
385
edgeIDs = item.second.fromCrossed;
386
edgeIDs.insert(edgeIDs.end(), item.second.toCrossed.begin(), item.second.toCrossed.end());
387
} else if (item.second.fromEdges.size() > 0) {
388
edgeIDs = item.second.fromEdges;
389
} else {
390
edgeIDs = item.second.toEdges;
391
}
392
EdgeVector edges;
393
for (const std::string& edgeID : edgeIDs) {
394
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
395
// edge might have been removed due to options
396
if (edge != nullptr) {
397
edges.push_back(edge);
398
}
399
}
400
if (edges.size() > 0) {
401
node->addWalkingAreaShape(edges, item.second.shape, item.second.width);
402
}
403
}
404
}
405
// add roundabouts
406
for (const std::vector<std::string>& ra : myRoundabouts) {
407
EdgeSet roundabout;
408
for (const std::string& edgeID : ra) {
409
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
410
if (edge == nullptr) {
411
if (!myNetBuilder.getEdgeCont().wasIgnored(edgeID)) {
412
WRITE_ERRORF(TL("Unknown edge '%' in roundabout"), (edgeID));
413
}
414
} else {
415
roundabout.insert(edge);
416
}
417
}
418
myNetBuilder.getEdgeCont().addRoundabout(roundabout);
419
}
420
}
421
422
423
void
424
NIImporter_SUMO::myStartElement(int element,
425
const SUMOSAXAttributes& attrs) {
426
/* our goal is to reproduce the input net faithfully
427
* there are different types of objects in the netfile:
428
* 1) those which must be loaded into NBNetBuilder-Containers for processing
429
* 2) those which can be ignored because they are recomputed based on group 1
430
* 3) those which are of no concern to NBNetBuilder but should be exposed to
431
* netedit. We will probably have to patch NBNetBuilder to contain them
432
* and hand them over to netedit
433
* alternative idea: those shouldn't really be contained within the
434
* network but rather in separate files. teach netedit how to open those
435
* (POI?)
436
* 4) those which are of concern neither to NBNetBuilder nor netedit and
437
* must be copied over - need to patch NBNetBuilder for this.
438
* copy unknown by default
439
*/
440
switch (element) {
441
case SUMO_TAG_NET: {
442
bool ok;
443
myNetworkVersion = StringUtils::toVersion(attrs.get<std::string>(SUMO_ATTR_VERSION, nullptr, ok, false));
444
myAmLefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, nullptr, ok, false);
445
myCornerDetail = attrs.getOpt<int>(SUMO_ATTR_CORNERDETAIL, nullptr, ok, 0);
446
myLinkDetail = attrs.getOpt<int>(SUMO_ATTR_LINKDETAIL, nullptr, ok, -1);
447
myRectLaneCut = attrs.getOpt<bool>(SUMO_ATTR_RECTANGULAR_LANE_CUT, nullptr, ok, false);
448
myWalkingAreas = attrs.getOpt<bool>(SUMO_ATTR_WALKINGAREAS, nullptr, ok, false);
449
myLimitTurnSpeed = attrs.getOpt<double>(SUMO_ATTR_LIMIT_TURN_SPEED, nullptr, ok, -1);
450
myCheckLaneFoesAll = attrs.getOpt<bool>(SUMO_ATTR_CHECKLANEFOES_ALL, nullptr, ok, false);
451
myCheckLaneFoesRoundabout = attrs.getOpt<bool>(SUMO_ATTR_CHECKLANEFOES_ROUNDABOUT, nullptr, ok, true);
452
myTlsIgnoreInternalJunctionJam = attrs.getOpt<bool>(SUMO_ATTR_TLS_IGNORE_INTERNAL_JUNCTION_JAM, nullptr, ok, false);
453
myDefaultSpreadType = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, nullptr, ok, myDefaultSpreadType);
454
myGeomAvoidOverlap = attrs.getOpt<bool>(SUMO_ATTR_AVOID_OVERLAP, nullptr, ok, myGeomAvoidOverlap);
455
myJunctionsHigherSpeed = attrs.getOpt<bool>(SUMO_ATTR_HIGHER_SPEED, nullptr, ok, myJunctionsHigherSpeed);
456
myInternalJunctionsVehicleWidth = attrs.getOpt<double>(SUMO_ATTR_INTERNAL_JUNCTIONS_VEHICLE_WIDTH, nullptr, ok, myInternalJunctionsVehicleWidth);
457
myJunctionsMinimalShape = attrs.getOpt<bool>(SUMO_ATTR_JUNCTIONS_MINIMAL_SHAPE, nullptr, ok, myJunctionsMinimalShape);
458
myJunctionsEndpointShape = attrs.getOpt<bool>(SUMO_ATTR_JUNCTIONS_ENDPOINT_SHAPE, nullptr, ok, myJunctionsEndpointShape);
459
// derived
460
const OptionsCont& oc = OptionsCont::getOptions();
461
myChangeLefthand = !oc.isDefault("lefthand") && (oc.getBool("lefthand") != myAmLefthand);
462
463
break;
464
}
465
case SUMO_TAG_EDGE:
466
addEdge(attrs);
467
break;
468
case SUMO_TAG_LANE:
469
addLane(attrs);
470
break;
471
case SUMO_TAG_STOPOFFSET: {
472
bool ok = true;
473
addStopOffsets(attrs, ok);
474
}
475
break;
476
case SUMO_TAG_NEIGH:
477
myCurrentLane->oppositeID = attrs.getString(SUMO_ATTR_LANE);
478
break;
479
case SUMO_TAG_JUNCTION:
480
addJunction(attrs);
481
break;
482
case SUMO_TAG_REQUEST:
483
addRequest(attrs);
484
break;
485
case SUMO_TAG_CONNECTION:
486
addConnection(attrs);
487
break;
488
case SUMO_TAG_TLLOGIC:
489
myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
490
if (myCurrentTL) {
491
myLastParameterised.push_back(myCurrentTL);
492
}
493
break;
494
case SUMO_TAG_PHASE:
495
addPhase(attrs, myCurrentTL);
496
break;
497
case SUMO_TAG_LOCATION:
498
delete myLocation;
499
myLocation = loadLocation(attrs);
500
break;
501
case SUMO_TAG_PROHIBITION:
502
addProhibition(attrs);
503
break;
504
case SUMO_TAG_ROUNDABOUT:
505
addRoundabout(attrs);
506
break;
507
case SUMO_TAG_PARAM:
508
if (myLastParameterised.size() != 0) {
509
bool ok = true;
510
const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
511
if (myDiscardableParams.count(key) == 0) {
512
// circumventing empty string test
513
const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
514
myLastParameterised.back()->setParameter(key, val);
515
}
516
}
517
break;
518
default:
519
myTypesHandler.myStartElement(element, attrs);
520
break;
521
}
522
}
523
524
525
void
526
NIImporter_SUMO::myEndElement(int element) {
527
switch (element) {
528
case SUMO_TAG_EDGE:
529
if (myCurrentEdge != nullptr) {
530
if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
531
WRITE_WARNINGF(TL("Edge '%' occurred at least twice in the input."), myCurrentEdge->id);
532
for (LaneAttrs* const lane : myCurrentEdge->lanes) {
533
delete lane;
534
}
535
delete myCurrentEdge;
536
} else {
537
myEdges[myCurrentEdge->id] = myCurrentEdge;
538
}
539
myCurrentEdge = nullptr;
540
myLastParameterised.pop_back();
541
}
542
break;
543
case SUMO_TAG_LANE:
544
if (myCurrentEdge != nullptr && myCurrentLane != nullptr) {
545
myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed);
546
myCurrentEdge->lanes.push_back(myCurrentLane);
547
myLastParameterised.pop_back();
548
}
549
myCurrentLane = nullptr;
550
break;
551
case SUMO_TAG_TLLOGIC:
552
if (myCurrentTL == nullptr) {
553
WRITE_ERROR(TL("Unmatched closing tag for tl-logic."));
554
} else {
555
if (!myTLLCont.insert(myCurrentTL)) {
556
WRITE_WARNINGF(TL("Could not add program '%' for traffic light '%'"), myCurrentTL->getProgramID(), myCurrentTL->getID());
557
delete myCurrentTL;
558
}
559
myCurrentTL = nullptr;
560
myLastParameterised.pop_back();
561
}
562
break;
563
case SUMO_TAG_JUNCTION:
564
if (myCurrentJunction.node != nullptr) {
565
myLastParameterised.pop_back();
566
}
567
break;
568
case SUMO_TAG_CONNECTION:
569
// !!! this just avoids a crash but is not a real check that it was a connection
570
if (!myLastParameterised.empty()) {
571
myLastParameterised.pop_back();
572
}
573
break;
574
default:
575
break;
576
}
577
}
578
579
580
void
581
NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) {
582
// get the id, report an error if not given or empty...
583
bool ok = true;
584
const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
585
if (!ok) {
586
return;
587
}
588
myCurrentEdge = new EdgeAttrs();
589
myLastParameterised.push_back(myCurrentEdge);
590
myCurrentEdge->builtEdge = nullptr;
591
myCurrentEdge->id = id;
592
// get the function
593
myCurrentEdge->func = attrs.getOpt<SumoXMLEdgeFunc>(SUMO_ATTR_FUNCTION, id.c_str(), ok, SumoXMLEdgeFunc::NORMAL);
594
if (myCurrentEdge->func == SumoXMLEdgeFunc::CROSSING) {
595
// add the crossing but don't do anything else
596
Crossing c(id);
597
c.crossingEdges = attrs.get<std::vector<std::string> >(SUMO_ATTR_CROSSING_EDGES, nullptr, ok);
598
myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(id)].push_back(c);
599
return;
600
} else if (myCurrentEdge->func == SumoXMLEdgeFunc::INTERNAL || myCurrentEdge->func == SumoXMLEdgeFunc::WALKINGAREA) {
601
myHaveSeenInternalEdge = true;
602
return; // skip internal edges
603
}
604
// get the type
605
myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
606
// get the origin and the destination node
607
myCurrentEdge->fromNode = attrs.getOpt<std::string>(SUMO_ATTR_FROM, id.c_str(), ok, "");
608
myCurrentEdge->toNode = attrs.getOpt<std::string>(SUMO_ATTR_TO, id.c_str(), ok, "");
609
myCurrentEdge->priority = attrs.getOpt<int>(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
610
myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
611
myCurrentEdge->shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok, PositionVector());
612
NBNetBuilder::transformCoordinates(myCurrentEdge->shape, true, myLocation);
613
myCurrentEdge->length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, NBEdge::UNSPECIFIED_LOADED_LENGTH);
614
myCurrentEdge->maxSpeed = 0;
615
myCurrentEdge->streetName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
616
myCurrentEdge->distance = attrs.getOpt<double>(SUMO_ATTR_DISTANCE, id.c_str(), ok, 0);
617
myCurrentEdge->bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, id.c_str(), ok, "");
618
if (myCurrentEdge->streetName != "" && OptionsCont::getOptions().isDefault("output.street-names")) {
619
OptionsCont::getOptions().set("output.street-names", "true");
620
}
621
622
std::string lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, id.c_str(), ok, myDefaultSpreadType);
623
if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
624
myCurrentEdge->lsf = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS);
625
} else {
626
WRITE_ERRORF(TL("Unknown spreadType '%' for edge '%'."), lsfS, id);
627
}
628
}
629
630
631
void
632
NIImporter_SUMO::addLane(const SUMOSAXAttributes& attrs) {
633
bool ok = true;
634
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
635
if (!ok) {
636
return;
637
}
638
if (myCurrentEdge == nullptr) {
639
WRITE_ERRORF(TL("Found lane '%' not within edge element."), id);
640
return;
641
}
642
const std::string expectedID = myCurrentEdge->id + "_" + toString(myCurrentEdge->lanes.size());
643
if (id != expectedID) {
644
WRITE_WARNINGF(TL("Renaming lane '%' to '%'."), id, expectedID);
645
}
646
myCurrentLane = new LaneAttrs();
647
myLastParameterised.push_back(myCurrentLane);
648
myCurrentLane->customShape = attrs.getOpt<bool>(SUMO_ATTR_CUSTOMSHAPE, nullptr, ok, false);
649
myCurrentLane->shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
650
myCurrentLane->width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, (double) NBEdge::UNSPECIFIED_WIDTH);
651
myCurrentLane->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
652
if (myCurrentEdge->func == SumoXMLEdgeFunc::CROSSING) {
653
// save the width and the lane id of the crossing but don't do anything else
654
std::vector<Crossing>& crossings = myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(myCurrentEdge->id)];
655
assert(crossings.size() > 0);
656
crossings.back().width = attrs.get<double>(SUMO_ATTR_WIDTH, id.c_str(), ok);
657
myLastParameterised.pop_back();
658
myLastParameterised.push_back(&crossings.back());
659
if (myCurrentLane->customShape) {
660
crossings.back().customShape = myCurrentLane->shape;
661
NBNetBuilder::transformCoordinates(crossings.back().customShape, true, myLocation);
662
}
663
} else if (myCurrentEdge->func == SumoXMLEdgeFunc::WALKINGAREA) {
664
// save custom shape if needed but don't do anything else
665
if (myCurrentLane->customShape) {
666
WalkingAreaParsedCustomShape wacs;
667
wacs.shape = myCurrentLane->shape;
668
wacs.width = myCurrentLane->width;
669
NBNetBuilder::transformCoordinates(wacs.shape, true, myLocation);
670
myWACustomShapes[myCurrentEdge->id] = wacs;
671
}
672
return;
673
} else if (myCurrentEdge->func == SumoXMLEdgeFunc::INTERNAL) {
674
return; // skip internal edges
675
}
676
if (attrs.hasAttribute("maxspeed")) {
677
// !!! deprecated
678
myCurrentLane->maxSpeed = attrs.getFloat("maxspeed");
679
} else {
680
myCurrentLane->maxSpeed = attrs.get<double>(SUMO_ATTR_SPEED, id.c_str(), ok);
681
}
682
myCurrentLane->friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, id.c_str(), ok, NBEdge::UNSPECIFIED_FRICTION, false); //sets 1 on empty
683
try {
684
myCurrentLane->allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "", false);
685
} catch (EmptyData&) {
686
// !!! deprecated
687
myCurrentLane->allow = "";
688
}
689
myCurrentLane->disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
690
myCurrentLane->endOffset = attrs.getOpt<double>(SUMO_ATTR_ENDOFFSET, id.c_str(), ok, (double) NBEdge::UNSPECIFIED_OFFSET);
691
myCurrentLane->accelRamp = attrs.getOpt<bool>(SUMO_ATTR_ACCELERATION, id.c_str(), ok, false);
692
myCurrentLane->changeLeft = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_LEFT, id.c_str(), ok, "");
693
myCurrentLane->changeRight = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_RIGHT, id.c_str(), ok, "");
694
if (myChangeLefthand) {
695
std::swap(myCurrentLane->changeLeft, myCurrentLane->changeRight);
696
}
697
698
// lane coordinates are derived (via lane spread) do not include them in convex boundary
699
NBNetBuilder::transformCoordinates(myCurrentLane->shape, false, myLocation);
700
}
701
702
703
void
704
NIImporter_SUMO::addStopOffsets(const SUMOSAXAttributes& attrs, bool& ok) {
705
const StopOffset offset(attrs, ok);
706
if (!ok) {
707
return;
708
}
709
// Admissibility of value will be checked in _loadNetwork(), when lengths are known
710
if (myCurrentLane == nullptr) {
711
if (myCurrentEdge->edgeStopOffset.isDefined()) {
712
WRITE_WARNINGF(TL("Duplicate definition of stopOffset for edge %.\nIgnoring duplicate specification."), myCurrentEdge->id);
713
} else {
714
myCurrentEdge->edgeStopOffset = offset;
715
}
716
} else {
717
if (myCurrentLane->laneStopOffset.isDefined()) {
718
WRITE_WARNINGF(TL("Duplicate definition of lane's stopOffset on edge %.\nIgnoring duplicate specifications."), myCurrentEdge->id);
719
} else {
720
myCurrentLane->laneStopOffset = offset;
721
}
722
}
723
}
724
725
726
void
727
NIImporter_SUMO::addJunction(const SUMOSAXAttributes& attrs) {
728
// get the id, report an error if not given or empty...
729
myCurrentJunction.node = nullptr;
730
myCurrentJunction.intLanes.clear();
731
myCurrentJunction.response.clear();
732
bool ok = true;
733
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
734
if (!ok) {
735
return;
736
}
737
if (id[0] == ':') { // internal node
738
return;
739
}
740
SumoXMLNodeType type = attrs.getOpt<SumoXMLNodeType>(SUMO_ATTR_TYPE, id.c_str(), ok, SumoXMLNodeType::UNKNOWN);
741
if (ok) {
742
if (type == SumoXMLNodeType::DEAD_END_DEPRECATED || type == SumoXMLNodeType::DEAD_END) {
743
// dead end is a computed status. Reset this to unknown so it will
744
// be corrected if additional connections are loaded
745
type = SumoXMLNodeType::UNKNOWN;
746
} else if (type == SumoXMLNodeType::INTERNAL) {
747
WRITE_WARNINGF("Invalid node type '%' for junction '%' in input network", toString(SumoXMLNodeType::INTERNAL), id);
748
type = SumoXMLNodeType::UNKNOWN;
749
}
750
}
751
Position pos = readPosition(attrs, id, ok);
752
NBNetBuilder::transformCoordinate(pos, true, myLocation);
753
NBNode* node = new NBNode(id, pos, type);
754
if (!myNodeCont.insert(node)) {
755
WRITE_WARNINGF(TL("Junction '%' occurred at least twice in the input."), id);
756
delete node;
757
myLastParameterised.push_back(myNodeCont.retrieve(id));
758
return;
759
} else {
760
myLastParameterised.push_back(node);
761
}
762
myCurrentJunction.node = node;
763
myCurrentJunction.intLanes = attrs.get<std::vector<std::string> >(SUMO_ATTR_INTLANES, nullptr, ok, false);
764
// set optional radius
765
if (attrs.hasAttribute(SUMO_ATTR_RADIUS)) {
766
node->setRadius(attrs.get<double>(SUMO_ATTR_RADIUS, id.c_str(), ok));
767
}
768
// handle custom shape
769
if (attrs.getOpt<bool>(SUMO_ATTR_CUSTOMSHAPE, id.c_str(), ok, false)) {
770
PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
771
NBNetBuilder::transformCoordinates(shape, true, myLocation);
772
node->setCustomShape(shape);
773
}
774
if (type == SumoXMLNodeType::RAIL_SIGNAL || type == SumoXMLNodeType::RAIL_CROSSING) {
775
// both types of nodes come without a tlLogic
776
myRailSignals.insert(id);
777
}
778
node->setRightOfWay(attrs.getOpt<RightOfWay>(SUMO_ATTR_RIGHT_OF_WAY, id.c_str(), ok, node->getRightOfWay()));
779
node->setFringeType(attrs.getOpt<FringeType>(SUMO_ATTR_FRINGE, id.c_str(), ok, node->getFringeType()));
780
if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
781
node->setName(attrs.get<std::string>(SUMO_ATTR_NAME, id.c_str(), ok));
782
}
783
}
784
785
786
void
787
NIImporter_SUMO::addRequest(const SUMOSAXAttributes& attrs) {
788
if (myCurrentJunction.node != nullptr) {
789
bool ok = true;
790
myCurrentJunction.response.push_back(attrs.get<std::string>(SUMO_ATTR_RESPONSE, nullptr, ok));
791
}
792
}
793
794
795
void
796
NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) {
797
bool ok = true;
798
std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
799
if (myEdges.count(fromID) == 0) {
800
WRITE_ERRORF(TL("Unknown edge '%' given in connection."), fromID);
801
return;
802
}
803
EdgeAttrs* from = myEdges[fromID];
804
if (from->func == SumoXMLEdgeFunc::INTERNAL) {
805
// internal junction connection
806
return;
807
}
808
809
Connection conn;
810
conn.toEdgeID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
811
int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
812
conn.toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
813
conn.tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
814
conn.mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, nullptr, ok, false);
815
conn.keepClear = attrs.getOpt<bool>(SUMO_ATTR_KEEP_CLEAR, nullptr, ok, true);
816
conn.indirectLeft = attrs.getOpt<bool>(SUMO_ATTR_INDIRECT, nullptr, ok, false);
817
conn.edgeType = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok, "");
818
double contPos = NBEdge::UNSPECIFIED_CONTPOS;
819
if (OptionsCont::getOptions().isSet("default.connection.cont-pos")) {
820
contPos = OptionsCont::getOptions().getFloat("default.connection.cont-pos");
821
}
822
conn.contPos = attrs.getOpt<double>(SUMO_ATTR_CONTPOS, nullptr, ok, contPos);
823
conn.visibility = attrs.getOpt<double>(SUMO_ATTR_VISIBILITY_DISTANCE, nullptr, ok, NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE);
824
std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "", false);
825
std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "", false);
826
if (allow == "" && disallow == "") {
827
conn.permissions = SVC_UNSPECIFIED;
828
} else {
829
conn.permissions = parseVehicleClasses(allow, disallow, myNetworkVersion);
830
}
831
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_LEFT)) {
832
conn.changeLeft = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_LEFT, nullptr, ok), "");
833
} else {
834
conn.changeLeft = SVC_UNSPECIFIED;
835
}
836
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_RIGHT)) {
837
conn.changeRight = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_RIGHT, nullptr, ok), "");
838
} else {
839
conn.changeRight = SVC_UNSPECIFIED;
840
}
841
if (myChangeLefthand) {
842
std::swap(conn.changeLeft, conn.changeRight);
843
}
844
conn.speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, NBEdge::UNSPECIFIED_SPEED);
845
conn.friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, nullptr, ok, NBEdge::UNSPECIFIED_FRICTION);
846
conn.customLength = attrs.getOpt<double>(SUMO_ATTR_LENGTH, nullptr, ok, NBEdge::UNSPECIFIED_LOADED_LENGTH);
847
conn.customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector::EMPTY);
848
NBNetBuilder::transformCoordinates(conn.customShape, false, myLocation);
849
conn.uncontrolled = attrs.getOpt<bool>(SUMO_ATTR_UNCONTROLLED, nullptr, ok, NBEdge::UNSPECIFIED_CONNECTION_UNCONTROLLED, false);
850
if (conn.tlID != "") {
851
conn.tlLinkIndex = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
852
conn.tlLinkIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);
853
} else {
854
conn.tlLinkIndex = NBConnection::InvalidTlIndex;
855
}
856
if ((int)from->lanes.size() <= fromLaneIdx) {
857
WRITE_ERRORF(TL("Invalid lane index '%' for connection from '%'."), toString(fromLaneIdx), fromID);
858
return;
859
}
860
from->lanes[fromLaneIdx]->connections.push_back(conn);
861
myLastParameterised.push_back(&from->lanes[fromLaneIdx]->connections.back());
862
863
// determine crossing priority and tlIndex
864
if (myPedestrianCrossings.size() > 0) {
865
if (from->func == SumoXMLEdgeFunc::WALKINGAREA && myEdges[conn.toEdgeID]->func == SumoXMLEdgeFunc::CROSSING) {
866
// connection from walkingArea to crossing
867
std::vector<Crossing>& crossings = myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)];
868
for (std::vector<Crossing>::iterator it = crossings.begin(); it != crossings.end(); ++it) {
869
if (conn.toEdgeID == (*it).edgeID) {
870
if (conn.tlID != "") {
871
(*it).priority = true;
872
(*it).customTLIndex = conn.tlLinkIndex;
873
} else {
874
LinkState state = SUMOXMLDefinitions::LinkStates.get(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
875
(*it).priority = state == LINKSTATE_MAJOR;
876
}
877
}
878
}
879
} else if (from->func == SumoXMLEdgeFunc::CROSSING && myEdges[conn.toEdgeID]->func == SumoXMLEdgeFunc::WALKINGAREA) {
880
// connection from crossing to walkingArea (set optional linkIndex2)
881
for (Crossing& c : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
882
if (fromID == c.edgeID) {
883
c.customTLIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);
884
}
885
}
886
}
887
}
888
// determine walking area reference edges
889
if (myWACustomShapes.size() > 0) {
890
EdgeAttrs* to = myEdges[conn.toEdgeID];
891
if (from->func == SumoXMLEdgeFunc::WALKINGAREA) {
892
std::map<std::string, WalkingAreaParsedCustomShape>::iterator it = myWACustomShapes.find(fromID);
893
if (it != myWACustomShapes.end()) {
894
if (to->func == SumoXMLEdgeFunc::NORMAL) {
895
// add target sidewalk as reference
896
it->second.toEdges.push_back(conn.toEdgeID);
897
} else if (to->func == SumoXMLEdgeFunc::CROSSING) {
898
// add target crossing edges as reference
899
for (Crossing crossing : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
900
if (conn.toEdgeID == crossing.edgeID) {
901
it->second.toCrossed.insert(it->second.toCrossed.end(), crossing.crossingEdges.begin(), crossing.crossingEdges.end());
902
}
903
}
904
}
905
}
906
} else if (to->func == SumoXMLEdgeFunc::WALKINGAREA) {
907
std::map<std::string, WalkingAreaParsedCustomShape>::iterator it = myWACustomShapes.find(conn.toEdgeID);
908
if (it != myWACustomShapes.end()) {
909
if (from->func == SumoXMLEdgeFunc::NORMAL) {
910
// add origin sidewalk as reference
911
it->second.fromEdges.push_back(fromID);
912
} else if (from->func == SumoXMLEdgeFunc::CROSSING) {
913
// add origin crossing edges as reference
914
for (Crossing crossing : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
915
if (fromID == crossing.edgeID) {
916
it->second.fromCrossed.insert(it->second.fromCrossed.end(), crossing.crossingEdges.begin(), crossing.crossingEdges.end());
917
}
918
}
919
}
920
}
921
}
922
}
923
}
924
925
926
void
927
NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) {
928
bool ok = true;
929
std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, nullptr, ok, "");
930
std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, nullptr, ok, "");
931
if (!ok) {
932
return;
933
}
934
Prohibition p;
935
parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok);
936
parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok);
937
if (!ok) {
938
return;
939
}
940
myProhibitions.push_back(p);
941
}
942
943
944
NBLoadedSUMOTLDef*
945
NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
946
if (currentTL) {
947
WRITE_ERRORF(TL("Definition of tl-logic '%' was not finished."), currentTL->getID());
948
return nullptr;
949
}
950
bool ok = true;
951
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
952
SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);
953
std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
954
std::string typeS = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
955
TrafficLightType type;
956
if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
957
type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
958
} else {
959
WRITE_ERRORF(TL("Unknown traffic light type '%' for tlLogic '%'."), typeS, id);
960
return nullptr;
961
}
962
if (ok) {
963
return new NBLoadedSUMOTLDef(id, programID, offset, type);
964
} else {
965
return nullptr;
966
}
967
}
968
969
970
void
971
NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
972
if (!currentTL) {
973
WRITE_ERROR(TL("found phase without tl-logic"));
974
return;
975
}
976
const std::string& id = currentTL->getID();
977
bool ok = true;
978
std::string state = attrs.get<std::string>(SUMO_ATTR_STATE, id.c_str(), ok);
979
SUMOTime duration = TIME2STEPS(attrs.get<double>(SUMO_ATTR_DURATION, id.c_str(), ok));
980
if (duration < 0) {
981
WRITE_ERRORF(TL("Phase duration for tl-logic '%/%' must be positive."), id, currentTL->getProgramID());
982
return;
983
}
984
// if the traffic light is an actuated traffic light, try to get the minimum and maximum durations and ends
985
std::vector<int> nextPhases = attrs.getOpt<std::vector<int> >(SUMO_ATTR_NEXT, id.c_str(), ok);
986
const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, nullptr, ok);
987
// Specific from actuated
988
const SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
989
const SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
990
const SUMOTime earliestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EARLIEST_END, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
991
const SUMOTime latestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_LATEST_END, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
992
// specific von NEMA
993
const SUMOTime vehExt = attrs.getOptSUMOTimeReporting(SUMO_ATTR_VEHICLEEXTENSION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
994
const SUMOTime yellow = attrs.getOptSUMOTimeReporting(SUMO_ATTR_YELLOW, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
995
const SUMOTime red = attrs.getOptSUMOTimeReporting(SUMO_ATTR_RED, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
996
if (ok) {
997
currentTL->addPhase(duration, state, minDuration, maxDuration, earliestEnd, latestEnd, vehExt, yellow, red, nextPhases, name);
998
}
999
}
1000
1001
1002
GeoConvHelper*
1003
NIImporter_SUMO::loadLocation(const SUMOSAXAttributes& attrs, bool setLoaded) {
1004
// @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
1005
bool ok = true;
1006
GeoConvHelper* result = nullptr;
1007
const Position offset = attrs.get<Position>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
1008
const Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
1009
const Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
1010
const std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
1011
if (ok) {
1012
result = new GeoConvHelper(proj, offset, origBoundary, convBoundary);
1013
result->resolveAbstractProjection();
1014
if (setLoaded) {
1015
GeoConvHelper::setLoaded(*result);
1016
}
1017
}
1018
return result;
1019
}
1020
1021
1022
Position
1023
NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
1024
const double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
1025
const double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
1026
const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0.);
1027
return Position(x, y, z);
1028
}
1029
1030
1031
void
1032
NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
1033
// split from/to
1034
const std::string::size_type div = attr.find("->");
1035
if (div == std::string::npos) {
1036
WRITE_ERRORF(TL("Missing connection divider in prohibition attribute '%'"), attr);
1037
ok = false;
1038
}
1039
from = attr.substr(0, div);
1040
to = attr.substr(div + 2);
1041
// check whether the edges are known
1042
if (myEdges.count(from) == 0) {
1043
WRITE_ERRORF(TL("Unknown edge prohibition '%'"), from);
1044
ok = false;
1045
}
1046
if (myEdges.count(to) == 0) {
1047
WRITE_ERRORF(TL("Unknown edge prohibition '%'"), to);
1048
ok = false;
1049
}
1050
}
1051
1052
1053
void
1054
NIImporter_SUMO::addRoundabout(const SUMOSAXAttributes& attrs) {
1055
bool ok = true;
1056
const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
1057
if (ok) {
1058
myRoundabouts.push_back(edgeIDs);
1059
}
1060
}
1061
1062
1063
/****************************************************************************/
1064
1065