Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIImporter_SUMO.cpp
194025 views
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 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
ed->builtEdge->setRoutingType(ed->routingType);
176
}
177
}
178
// assign further lane attributes (edges are built)
179
EdgeVector toRemove;
180
const bool dismissVclasses = oc.getBool("dismiss-vclasses");
181
for (std::map<std::string, EdgeAttrs*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
182
EdgeAttrs* ed = (*i).second;
183
NBEdge* nbe = ed->builtEdge;
184
if (nbe == nullptr) { // inner edge or removed by explicit list, vclass, ...
185
continue;
186
}
187
const SumoXMLNodeType toType = nbe->getToNode()->getType();
188
for (int fromLaneIndex = 0; fromLaneIndex < (int) ed->lanes.size(); ++fromLaneIndex) {
189
LaneAttrs* lane = ed->lanes[fromLaneIndex];
190
// connections
191
const std::vector<Connection>& connections = lane->connections;
192
for (const Connection& c : connections) {
193
if (myEdges.count(c.toEdgeID) == 0) {
194
WRITE_ERRORF(TL("Unknown edge '%' given in connection."), c.toEdgeID);
195
continue;
196
}
197
NBEdge* toEdge = myEdges[c.toEdgeID]->builtEdge;
198
if (toEdge == nullptr) { // removed by explicit list, vclass, ...
199
continue;
200
}
201
if (toEdge->getFromNode() != nbe->getToNode()) { // inconsistency may occur when merging networks
202
WRITE_WARNINGF("Removing invalid connection from edge '%' to edge '%'", nbe->getID(), toEdge->getID());
203
continue;
204
}
205
// patch attribute uncontrolled for legacy networks where it is not set explicitly
206
bool uncontrolled = c.uncontrolled;
207
208
if ((NBNode::isTrafficLight(toType) || toType == SumoXMLNodeType::RAIL_SIGNAL)
209
&& c.tlLinkIndex == NBConnection::InvalidTlIndex) {
210
uncontrolled = true;
211
}
212
nbe->addLane2LaneConnection(
213
fromLaneIndex, toEdge, c.toLaneIdx, NBEdge::Lane2LaneInfoType::VALIDATED,
214
true, c.mayDefinitelyPass, c.keepClear ? KEEPCLEAR_TRUE : KEEPCLEAR_FALSE,
215
c.contPos, c.visibility, c.speed, c.friction, c.customLength, c.customShape, uncontrolled, c.permissions, c.indirectLeft, c.edgeType, c.changeLeft, c.changeRight);
216
if (c.getParametersMap().size() > 0) {
217
nbe->getConnectionRef(fromLaneIndex, toEdge, c.toLaneIdx).updateParameters(c.getParametersMap());
218
}
219
// maybe we have a tls-controlled connection
220
if (c.tlID != "" && myRailSignals.count(c.tlID) == 0) {
221
const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(c.tlID);
222
if (programs.size() > 0) {
223
std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
224
for (it = programs.begin(); it != programs.end(); it++) {
225
NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
226
if (tlDef) {
227
tlDef->addConnection(nbe, toEdge, fromLaneIndex, c.toLaneIdx, c.tlLinkIndex, c.tlLinkIndex2, false);
228
} else {
229
throw ProcessError("Corrupt traffic light definition '" + c.tlID + "' (program '" + it->first + "')");
230
}
231
}
232
} else {
233
WRITE_ERRORF(TL("The traffic light '%' is not known."), c.tlID);
234
}
235
}
236
}
237
// allow/disallow XXX preferred
238
if (!dismissVclasses) {
239
nbe->setPermissions(parseVehicleClasses(lane->allow, lane->disallow, myNetworkVersion), fromLaneIndex);
240
}
241
nbe->setPermittedChanging(fromLaneIndex, parseVehicleClasses(lane->changeLeft, ""), parseVehicleClasses(lane->changeRight, ""));
242
// width, offset
243
nbe->setLaneWidth(fromLaneIndex, lane->width);
244
nbe->setEndOffset(fromLaneIndex, lane->endOffset);
245
nbe->setSpeed(fromLaneIndex, lane->maxSpeed);
246
nbe->setFriction(fromLaneIndex, lane->friction);
247
nbe->setAcceleration(fromLaneIndex, lane->accelRamp);
248
nbe->getLaneStruct(fromLaneIndex).oppositeID = lane->oppositeID;
249
nbe->getLaneStruct(fromLaneIndex).type = lane->type;
250
nbe->getLaneStruct(fromLaneIndex).updateParameters(lane->getParametersMap());
251
if (lane->customShape) {
252
nbe->setLaneShape(fromLaneIndex, lane->shape);
253
}
254
// stop offset for lane
255
bool stopOffsetSet = false;
256
if (lane->laneStopOffset.isDefined() || nbe->getEdgeStopOffset().isDefined()) {
257
// apply lane-specific stopOffset (might be none as well)
258
stopOffsetSet = nbe->setEdgeStopOffset(fromLaneIndex, lane->laneStopOffset);
259
}
260
if (!stopOffsetSet) {
261
// apply default stop offset to lane
262
nbe->setEdgeStopOffset(fromLaneIndex, nbe->getEdgeStopOffset());
263
}
264
}
265
nbe->declareConnectionsAsLoaded();
266
if (!nbe->hasLaneSpecificWidth() && nbe->getLanes()[0].width != NBEdge::UNSPECIFIED_WIDTH) {
267
nbe->setLaneWidth(-1, nbe->getLaneWidth(0));
268
}
269
if (!nbe->hasLaneSpecificEndOffset() && nbe->getEndOffset(0) != NBEdge::UNSPECIFIED_OFFSET) {
270
nbe->setEndOffset(-1, nbe->getEndOffset(0));
271
}
272
if (!nbe->hasLaneSpecificStopOffsets() && nbe->getEdgeStopOffset().isDefined()) {
273
nbe->setEdgeStopOffset(-1, nbe->getEdgeStopOffset());
274
}
275
// check again after permissions are set
276
if (myNetBuilder.getEdgeCont().ignoreFilterMatch(nbe)) {
277
myNetBuilder.getEdgeCont().ignore(nbe->getID());
278
toRemove.push_back(nbe);
279
}
280
}
281
for (EdgeVector::iterator i = toRemove.begin(); i != toRemove.end(); ++i) {
282
myNetBuilder.getEdgeCont().erase(myNetBuilder.getDistrictCont(), *i);
283
}
284
// insert loaded prohibitions
285
for (std::vector<Prohibition>::const_iterator it = myProhibitions.begin(); it != myProhibitions.end(); it++) {
286
NBEdge* prohibitedFrom = myEdges[it->prohibitedFrom]->builtEdge;
287
NBEdge* prohibitedTo = myEdges[it->prohibitedTo]->builtEdge;
288
NBEdge* prohibitorFrom = myEdges[it->prohibitorFrom]->builtEdge;
289
NBEdge* prohibitorTo = myEdges[it->prohibitorTo]->builtEdge;
290
if (prohibitedFrom == nullptr) {
291
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitedFrom);
292
} else if (prohibitedTo == nullptr) {
293
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitedTo);
294
} else if (prohibitorFrom == nullptr) {
295
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitorFrom);
296
} else if (prohibitorTo == nullptr) {
297
WRITE_WARNINGF(TL("Edge '%' in prohibition was not built."), it->prohibitorTo);
298
} else {
299
NBNode* n = prohibitedFrom->getToNode();
300
n->addSortedLinkFoes(
301
NBConnection(prohibitorFrom, prohibitorTo),
302
NBConnection(prohibitedFrom, prohibitedTo));
303
}
304
}
305
if (!myHaveSeenInternalEdge && oc.isWriteable("no-internal-links")) {
306
oc.set("no-internal-links", "true");
307
}
308
if (oc.isWriteable("lefthand")) {
309
oc.set("lefthand", toString(myAmLefthand));
310
}
311
if (oc.isWriteable("junctions.corner-detail")) {
312
oc.set("junctions.corner-detail", toString(myCornerDetail));
313
}
314
if (oc.isWriteable("junctions.internal-link-detail") && myLinkDetail > 0) {
315
oc.set("junctions.internal-link-detail", toString(myLinkDetail));
316
}
317
if (oc.isWriteable("rectangular-lane-cut")) {
318
oc.set("rectangular-lane-cut", toString(myRectLaneCut));
319
}
320
if (oc.isWriteable("walkingareas")) {
321
oc.set("walkingareas", toString(myWalkingAreas));
322
}
323
if (oc.isWriteable("junctions.limit-turn-speed")) {
324
oc.set("junctions.limit-turn-speed", toString(myLimitTurnSpeed));
325
}
326
if (oc.isWriteable("check-lane-foes.all") && oc.getBool("check-lane-foes.all") != myCheckLaneFoesAll) {
327
oc.set("check-lane-foes.all", toString(myCheckLaneFoesAll));
328
}
329
if (oc.isWriteable("check-lane-foes.roundabout") && oc.getBool("check-lane-foes.roundabout") != myCheckLaneFoesRoundabout) {
330
oc.set("check-lane-foes.roundabout", toString(myCheckLaneFoesRoundabout));
331
}
332
if (oc.isWriteable("tls.ignore-internal-junction-jam") && oc.getBool("tls.ignore-internal-junction-jam") != myTlsIgnoreInternalJunctionJam) {
333
oc.set("tls.ignore-internal-junction-jam", toString(myTlsIgnoreInternalJunctionJam));
334
}
335
if (oc.isWriteable("default.spreadtype") && oc.getString("default.spreadtype") != myDefaultSpreadType) {
336
oc.set("default.spreadtype", myDefaultSpreadType);
337
}
338
if (oc.isWriteable("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap") != myGeomAvoidOverlap) {
339
oc.set("geometry.avoid-overlap", toString(myGeomAvoidOverlap));
340
}
341
if (oc.isWriteable("junctions.higher-speed") && oc.getBool("junctions.higher-speed") != myJunctionsHigherSpeed) {
342
oc.set("junctions.higher-speed", toString(myJunctionsHigherSpeed));
343
}
344
if (oc.isWriteable("internal-junctions.vehicle-width") && oc.getFloat("internal-junctions.vehicle-width") != myInternalJunctionsVehicleWidth) {
345
oc.set("internal-junctions.vehicle-width", toString(myInternalJunctionsVehicleWidth));
346
}
347
if (oc.isWriteable("junctions.minimal-shape") && oc.getBool("junctions.minimal-shape") != myJunctionsMinimalShape) {
348
oc.set("junctions.minimal-shape", toString(myJunctionsMinimalShape));
349
}
350
if (oc.isWriteable("junctions.endpoint-shape") && oc.getBool("junctions.endpoint-shape") != myJunctionsEndpointShape) {
351
oc.set("junctions.endpoint-shape", toString(myJunctionsEndpointShape));
352
}
353
if (!deprecatedVehicleClassesSeen.empty()) {
354
WRITE_WARNINGF(TL("Deprecated vehicle class(es) '%' in input network."), toString(deprecatedVehicleClassesSeen));
355
deprecatedVehicleClassesSeen.clear();
356
}
357
if (!oc.getBool("no-internal-links")) {
358
// add loaded crossings
359
for (const auto& crossIt : myPedestrianCrossings) {
360
NBNode* const node = myNodeCont.retrieve(crossIt.first);
361
for (const Crossing& crossing : crossIt.second) {
362
EdgeVector edges;
363
for (const std::string& edgeID : crossing.crossingEdges) {
364
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
365
// edge might have been removed due to options
366
if (edge != nullptr) {
367
edges.push_back(edge);
368
}
369
}
370
if (!edges.empty()) {
371
node->addCrossing(edges, crossing.width, crossing.priority,
372
crossing.customTLIndex, crossing.customTLIndex2, crossing.customShape, true, &crossing);
373
}
374
}
375
}
376
myNetBuilder.setHaveNetworkCrossings(myPedestrianCrossings.size() > 0);
377
// add walking area custom shapes
378
for (const auto& item : myWACustomShapes) {
379
std::string nodeID = SUMOXMLDefinitions::getJunctionIDFromInternalEdge(item.first);
380
NBNode* node = myNodeCont.retrieve(nodeID);
381
std::vector<std::string> edgeIDs;
382
if (item.second.fromEdges.size() + item.second.toEdges.size() == 0) {
383
// must be a split crossing
384
assert(item.second.fromCrossed.size() > 0);
385
assert(item.second.toCrossed.size() > 0);
386
edgeIDs = item.second.fromCrossed;
387
edgeIDs.insert(edgeIDs.end(), item.second.toCrossed.begin(), item.second.toCrossed.end());
388
} else if (item.second.fromEdges.size() > 0) {
389
edgeIDs = item.second.fromEdges;
390
} else {
391
edgeIDs = item.second.toEdges;
392
}
393
EdgeVector edges;
394
for (const std::string& edgeID : edgeIDs) {
395
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
396
// edge might have been removed due to options
397
if (edge != nullptr) {
398
edges.push_back(edge);
399
}
400
}
401
if (edges.size() > 0) {
402
node->addWalkingAreaShape(edges, item.second.shape, item.second.width);
403
}
404
}
405
}
406
// add roundabouts
407
for (const std::vector<std::string>& ra : myRoundabouts) {
408
EdgeSet roundabout;
409
for (const std::string& edgeID : ra) {
410
NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeID);
411
if (edge == nullptr) {
412
if (!myNetBuilder.getEdgeCont().wasIgnored(edgeID)) {
413
WRITE_ERRORF(TL("Unknown edge '%' in roundabout"), (edgeID));
414
}
415
} else {
416
roundabout.insert(edge);
417
}
418
}
419
myNetBuilder.getEdgeCont().addRoundabout(roundabout);
420
}
421
}
422
423
424
void
425
NIImporter_SUMO::myStartElement(int element,
426
const SUMOSAXAttributes& attrs) {
427
/* our goal is to reproduce the input net faithfully
428
* there are different types of objects in the netfile:
429
* 1) those which must be loaded into NBNetBuilder-Containers for processing
430
* 2) those which can be ignored because they are recomputed based on group 1
431
* 3) those which are of no concern to NBNetBuilder but should be exposed to
432
* netedit. We will probably have to patch NBNetBuilder to contain them
433
* and hand them over to netedit
434
* alternative idea: those shouldn't really be contained within the
435
* network but rather in separate files. teach netedit how to open those
436
* (POI?)
437
* 4) those which are of concern neither to NBNetBuilder nor netedit and
438
* must be copied over - need to patch NBNetBuilder for this.
439
* copy unknown by default
440
*/
441
switch (element) {
442
case SUMO_TAG_NET: {
443
bool ok;
444
myNetworkVersion = StringUtils::toVersion(attrs.get<std::string>(SUMO_ATTR_VERSION, nullptr, ok, false));
445
myAmLefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, nullptr, ok, false);
446
myCornerDetail = attrs.getOpt<int>(SUMO_ATTR_CORNERDETAIL, nullptr, ok, 0);
447
myLinkDetail = attrs.getOpt<int>(SUMO_ATTR_LINKDETAIL, nullptr, ok, -1);
448
myRectLaneCut = attrs.getOpt<bool>(SUMO_ATTR_RECTANGULAR_LANE_CUT, nullptr, ok, false);
449
myWalkingAreas = attrs.getOpt<bool>(SUMO_ATTR_WALKINGAREAS, nullptr, ok, false);
450
myLimitTurnSpeed = attrs.getOpt<double>(SUMO_ATTR_LIMIT_TURN_SPEED, nullptr, ok, -1);
451
myCheckLaneFoesAll = attrs.getOpt<bool>(SUMO_ATTR_CHECKLANEFOES_ALL, nullptr, ok, false);
452
myCheckLaneFoesRoundabout = attrs.getOpt<bool>(SUMO_ATTR_CHECKLANEFOES_ROUNDABOUT, nullptr, ok, true);
453
myTlsIgnoreInternalJunctionJam = attrs.getOpt<bool>(SUMO_ATTR_TLS_IGNORE_INTERNAL_JUNCTION_JAM, nullptr, ok, false);
454
myDefaultSpreadType = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, nullptr, ok, myDefaultSpreadType);
455
myGeomAvoidOverlap = attrs.getOpt<bool>(SUMO_ATTR_AVOID_OVERLAP, nullptr, ok, myGeomAvoidOverlap);
456
myJunctionsHigherSpeed = attrs.getOpt<bool>(SUMO_ATTR_HIGHER_SPEED, nullptr, ok, myJunctionsHigherSpeed);
457
myInternalJunctionsVehicleWidth = attrs.getOpt<double>(SUMO_ATTR_INTERNAL_JUNCTIONS_VEHICLE_WIDTH, nullptr, ok, myInternalJunctionsVehicleWidth);
458
myJunctionsMinimalShape = attrs.getOpt<bool>(SUMO_ATTR_JUNCTIONS_MINIMAL_SHAPE, nullptr, ok, myJunctionsMinimalShape);
459
myJunctionsEndpointShape = attrs.getOpt<bool>(SUMO_ATTR_JUNCTIONS_ENDPOINT_SHAPE, nullptr, ok, myJunctionsEndpointShape);
460
// derived
461
const OptionsCont& oc = OptionsCont::getOptions();
462
myChangeLefthand = !oc.isDefault("lefthand") && (oc.getBool("lefthand") != myAmLefthand);
463
464
break;
465
}
466
case SUMO_TAG_EDGE:
467
addEdge(attrs);
468
break;
469
case SUMO_TAG_LANE:
470
addLane(attrs);
471
break;
472
case SUMO_TAG_STOPOFFSET: {
473
bool ok = true;
474
addStopOffsets(attrs, ok);
475
}
476
break;
477
case SUMO_TAG_NEIGH:
478
myCurrentLane->oppositeID = attrs.getString(SUMO_ATTR_LANE);
479
break;
480
case SUMO_TAG_JUNCTION:
481
addJunction(attrs);
482
break;
483
case SUMO_TAG_REQUEST:
484
addRequest(attrs);
485
break;
486
case SUMO_TAG_CONNECTION:
487
addConnection(attrs);
488
break;
489
case SUMO_TAG_TLLOGIC:
490
myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
491
if (myCurrentTL) {
492
myLastParameterised.push_back(myCurrentTL);
493
}
494
break;
495
case SUMO_TAG_PHASE:
496
addPhase(attrs, myCurrentTL);
497
break;
498
case SUMO_TAG_LOCATION:
499
delete myLocation;
500
myLocation = loadLocation(attrs);
501
break;
502
case SUMO_TAG_PROHIBITION:
503
addProhibition(attrs);
504
break;
505
case SUMO_TAG_ROUNDABOUT:
506
addRoundabout(attrs);
507
break;
508
case SUMO_TAG_PARAM:
509
if (myLastParameterised.size() != 0) {
510
bool ok = true;
511
const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
512
if (myDiscardableParams.count(key) == 0) {
513
// circumventing empty string test
514
const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
515
myLastParameterised.back()->setParameter(key, val);
516
}
517
}
518
break;
519
default:
520
myTypesHandler.myStartElement(element, attrs);
521
break;
522
}
523
}
524
525
526
void
527
NIImporter_SUMO::myEndElement(int element) {
528
switch (element) {
529
case SUMO_TAG_EDGE:
530
if (myCurrentEdge != nullptr) {
531
if (myEdges.find(myCurrentEdge->id) != myEdges.end()) {
532
WRITE_WARNINGF(TL("Edge '%' occurred at least twice in the input."), myCurrentEdge->id);
533
for (LaneAttrs* const lane : myCurrentEdge->lanes) {
534
delete lane;
535
}
536
delete myCurrentEdge;
537
} else {
538
myEdges[myCurrentEdge->id] = myCurrentEdge;
539
}
540
myCurrentEdge = nullptr;
541
myLastParameterised.pop_back();
542
}
543
break;
544
case SUMO_TAG_LANE:
545
if (myCurrentEdge != nullptr && myCurrentLane != nullptr) {
546
myCurrentEdge->maxSpeed = MAX2(myCurrentEdge->maxSpeed, myCurrentLane->maxSpeed);
547
myCurrentEdge->lanes.push_back(myCurrentLane);
548
myLastParameterised.pop_back();
549
}
550
myCurrentLane = nullptr;
551
break;
552
case SUMO_TAG_TLLOGIC:
553
if (myCurrentTL == nullptr) {
554
WRITE_ERROR(TL("Unmatched closing tag for tl-logic."));
555
} else {
556
if (!myTLLCont.insert(myCurrentTL)) {
557
WRITE_WARNINGF(TL("Could not add program '%' for traffic light '%'"), myCurrentTL->getProgramID(), myCurrentTL->getID());
558
delete myCurrentTL;
559
}
560
myCurrentTL = nullptr;
561
myLastParameterised.pop_back();
562
}
563
break;
564
case SUMO_TAG_JUNCTION:
565
if (myCurrentJunction.node != nullptr) {
566
myLastParameterised.pop_back();
567
}
568
break;
569
case SUMO_TAG_CONNECTION:
570
// !!! this just avoids a crash but is not a real check that it was a connection
571
if (!myLastParameterised.empty()) {
572
myLastParameterised.pop_back();
573
}
574
break;
575
default:
576
break;
577
}
578
}
579
580
581
void
582
NIImporter_SUMO::addEdge(const SUMOSAXAttributes& attrs) {
583
// get the id, report an error if not given or empty...
584
bool ok = true;
585
const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
586
if (!ok) {
587
return;
588
}
589
myCurrentEdge = new EdgeAttrs();
590
myLastParameterised.push_back(myCurrentEdge);
591
myCurrentEdge->builtEdge = nullptr;
592
myCurrentEdge->id = id;
593
// get the function
594
myCurrentEdge->func = attrs.getOpt<SumoXMLEdgeFunc>(SUMO_ATTR_FUNCTION, id.c_str(), ok, SumoXMLEdgeFunc::NORMAL);
595
if (myCurrentEdge->func == SumoXMLEdgeFunc::CROSSING) {
596
// add the crossing but don't do anything else
597
Crossing c(id);
598
c.crossingEdges = attrs.get<std::vector<std::string> >(SUMO_ATTR_CROSSING_EDGES, nullptr, ok);
599
myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(id)].push_back(c);
600
return;
601
} else if (myCurrentEdge->func == SumoXMLEdgeFunc::INTERNAL || myCurrentEdge->func == SumoXMLEdgeFunc::WALKINGAREA) {
602
myHaveSeenInternalEdge = true;
603
return; // skip internal edges
604
}
605
// get the origin and the destination node
606
myCurrentEdge->fromNode = attrs.getOpt<std::string>(SUMO_ATTR_FROM, id.c_str(), ok, "");
607
myCurrentEdge->toNode = attrs.getOpt<std::string>(SUMO_ATTR_TO, id.c_str(), ok, "");
608
myCurrentEdge->priority = attrs.getOpt<int>(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1);
609
myCurrentEdge->type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
610
myCurrentEdge->routingType = attrs.getOpt<std::string>(SUMO_ATTR_ROUTINGTYPE, 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.response.clear();
731
bool ok = true;
732
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
733
if (!ok) {
734
return;
735
}
736
if (id[0] == ':') { // internal node
737
return;
738
}
739
SumoXMLNodeType type = attrs.getOpt<SumoXMLNodeType>(SUMO_ATTR_TYPE, id.c_str(), ok, SumoXMLNodeType::UNKNOWN);
740
if (ok) {
741
if (type == SumoXMLNodeType::DEAD_END_DEPRECATED || type == SumoXMLNodeType::DEAD_END) {
742
// dead end is a computed status. Reset this to unknown so it will
743
// be corrected if additional connections are loaded
744
type = SumoXMLNodeType::UNKNOWN;
745
} else if (type == SumoXMLNodeType::INTERNAL) {
746
WRITE_WARNINGF("Invalid node type '%' for junction '%' in input network", toString(SumoXMLNodeType::INTERNAL), id);
747
type = SumoXMLNodeType::UNKNOWN;
748
}
749
}
750
Position pos = readPosition(attrs, id, ok);
751
NBNetBuilder::transformCoordinate(pos, true, myLocation);
752
NBNode* node = new NBNode(id, pos, type);
753
if (!myNodeCont.insert(node)) {
754
WRITE_WARNINGF(TL("Junction '%' occurred at least twice in the input."), id);
755
delete node;
756
myLastParameterised.push_back(myNodeCont.retrieve(id));
757
return;
758
} else {
759
myLastParameterised.push_back(node);
760
}
761
myCurrentJunction.node = node;
762
// set optional radius
763
if (attrs.hasAttribute(SUMO_ATTR_RADIUS)) {
764
node->setRadius(attrs.get<double>(SUMO_ATTR_RADIUS, id.c_str(), ok));
765
}
766
// handle custom shape
767
if (attrs.getOpt<bool>(SUMO_ATTR_CUSTOMSHAPE, id.c_str(), ok, false)) {
768
PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
769
NBNetBuilder::transformCoordinates(shape, true, myLocation);
770
node->setCustomShape(shape);
771
}
772
if (type == SumoXMLNodeType::RAIL_SIGNAL || type == SumoXMLNodeType::RAIL_CROSSING) {
773
// both types of nodes come without a tlLogic
774
myRailSignals.insert(id);
775
}
776
node->setRightOfWay(attrs.getOpt<RightOfWay>(SUMO_ATTR_RIGHT_OF_WAY, id.c_str(), ok, node->getRightOfWay()));
777
node->setFringeType(attrs.getOpt<FringeType>(SUMO_ATTR_FRINGE, id.c_str(), ok, node->getFringeType()));
778
node->setRoundaboutType(attrs.getOpt<RoundaboutType>(SUMO_ATTR_ROUNDABOUT, id.c_str(), ok, node->getRoundaboutType()));
779
if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
780
node->setName(attrs.get<std::string>(SUMO_ATTR_NAME, id.c_str(), ok));
781
}
782
}
783
784
785
void
786
NIImporter_SUMO::addRequest(const SUMOSAXAttributes& attrs) {
787
if (myCurrentJunction.node != nullptr) {
788
bool ok = true;
789
myCurrentJunction.response.push_back(attrs.get<std::string>(SUMO_ATTR_RESPONSE, nullptr, ok));
790
}
791
}
792
793
794
void
795
NIImporter_SUMO::addConnection(const SUMOSAXAttributes& attrs) {
796
bool ok = true;
797
std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
798
if (myEdges.count(fromID) == 0) {
799
WRITE_ERRORF(TL("Unknown edge '%' given in connection."), fromID);
800
return;
801
}
802
EdgeAttrs* from = myEdges[fromID];
803
if (from->func == SumoXMLEdgeFunc::INTERNAL) {
804
// internal junction connection
805
return;
806
}
807
808
Connection conn;
809
conn.toEdgeID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
810
int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
811
conn.toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
812
conn.tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
813
conn.mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, nullptr, ok, false);
814
conn.keepClear = attrs.getOpt<bool>(SUMO_ATTR_KEEP_CLEAR, nullptr, ok, true);
815
conn.indirectLeft = attrs.getOpt<bool>(SUMO_ATTR_INDIRECT, nullptr, ok, false);
816
conn.edgeType = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok, "");
817
double contPos = NBEdge::UNSPECIFIED_CONTPOS;
818
if (OptionsCont::getOptions().isSet("default.connection.cont-pos")) {
819
contPos = OptionsCont::getOptions().getFloat("default.connection.cont-pos");
820
}
821
conn.contPos = attrs.getOpt<double>(SUMO_ATTR_CONTPOS, nullptr, ok, contPos);
822
conn.visibility = attrs.getOpt<double>(SUMO_ATTR_VISIBILITY_DISTANCE, nullptr, ok, NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE);
823
std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "", false);
824
std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "", false);
825
if (allow == "" && disallow == "") {
826
conn.permissions = SVC_UNSPECIFIED;
827
} else {
828
conn.permissions = parseVehicleClasses(allow, disallow, myNetworkVersion);
829
}
830
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_LEFT)) {
831
conn.changeLeft = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_LEFT, nullptr, ok), "");
832
} else {
833
conn.changeLeft = SVC_UNSPECIFIED;
834
}
835
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_RIGHT)) {
836
conn.changeRight = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_RIGHT, nullptr, ok), "");
837
} else {
838
conn.changeRight = SVC_UNSPECIFIED;
839
}
840
if (myChangeLefthand) {
841
std::swap(conn.changeLeft, conn.changeRight);
842
}
843
conn.speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, NBEdge::UNSPECIFIED_SPEED);
844
conn.friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, nullptr, ok, NBEdge::UNSPECIFIED_FRICTION);
845
conn.customLength = attrs.getOpt<double>(SUMO_ATTR_LENGTH, nullptr, ok, NBEdge::UNSPECIFIED_LOADED_LENGTH);
846
conn.customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector::EMPTY);
847
NBNetBuilder::transformCoordinates(conn.customShape, false, myLocation);
848
conn.uncontrolled = attrs.getOpt<bool>(SUMO_ATTR_UNCONTROLLED, nullptr, ok, NBEdge::UNSPECIFIED_CONNECTION_UNCONTROLLED, false);
849
if (conn.tlID != "") {
850
conn.tlLinkIndex = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
851
conn.tlLinkIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);
852
} else {
853
conn.tlLinkIndex = NBConnection::InvalidTlIndex;
854
}
855
if ((int)from->lanes.size() <= fromLaneIdx) {
856
WRITE_ERRORF(TL("Invalid lane index '%' for connection from '%'."), toString(fromLaneIdx), fromID);
857
return;
858
}
859
from->lanes[fromLaneIdx]->connections.push_back(conn);
860
myLastParameterised.push_back(&from->lanes[fromLaneIdx]->connections.back());
861
862
// determine crossing priority and tlIndex
863
if (myPedestrianCrossings.size() > 0) {
864
if (from->func == SumoXMLEdgeFunc::WALKINGAREA && myEdges[conn.toEdgeID]->func == SumoXMLEdgeFunc::CROSSING) {
865
// connection from walkingArea to crossing
866
std::vector<Crossing>& crossings = myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)];
867
for (std::vector<Crossing>::iterator it = crossings.begin(); it != crossings.end(); ++it) {
868
if (conn.toEdgeID == (*it).edgeID) {
869
if (conn.tlID != "") {
870
(*it).priority = true;
871
(*it).customTLIndex = conn.tlLinkIndex;
872
} else {
873
LinkState state = SUMOXMLDefinitions::LinkStates.get(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
874
(*it).priority = state == LINKSTATE_MAJOR;
875
}
876
}
877
}
878
} else if (from->func == SumoXMLEdgeFunc::CROSSING && myEdges[conn.toEdgeID]->func == SumoXMLEdgeFunc::WALKINGAREA) {
879
// connection from crossing to walkingArea (set optional linkIndex2)
880
for (Crossing& c : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
881
if (fromID == c.edgeID) {
882
c.customTLIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);
883
}
884
}
885
}
886
}
887
// determine walking area reference edges
888
if (myWACustomShapes.size() > 0) {
889
EdgeAttrs* to = myEdges[conn.toEdgeID];
890
if (from->func == SumoXMLEdgeFunc::WALKINGAREA) {
891
std::map<std::string, WalkingAreaParsedCustomShape>::iterator it = myWACustomShapes.find(fromID);
892
if (it != myWACustomShapes.end()) {
893
if (to->func == SumoXMLEdgeFunc::NORMAL) {
894
// add target sidewalk as reference
895
it->second.toEdges.push_back(conn.toEdgeID);
896
} else if (to->func == SumoXMLEdgeFunc::CROSSING) {
897
// add target crossing edges as reference
898
for (Crossing crossing : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
899
if (conn.toEdgeID == crossing.edgeID) {
900
it->second.toCrossed.insert(it->second.toCrossed.end(), crossing.crossingEdges.begin(), crossing.crossingEdges.end());
901
}
902
}
903
}
904
}
905
} else if (to->func == SumoXMLEdgeFunc::WALKINGAREA) {
906
std::map<std::string, WalkingAreaParsedCustomShape>::iterator it = myWACustomShapes.find(conn.toEdgeID);
907
if (it != myWACustomShapes.end()) {
908
if (from->func == SumoXMLEdgeFunc::NORMAL) {
909
// add origin sidewalk as reference
910
it->second.fromEdges.push_back(fromID);
911
} else if (from->func == SumoXMLEdgeFunc::CROSSING) {
912
// add origin crossing edges as reference
913
for (Crossing crossing : myPedestrianCrossings[SUMOXMLDefinitions::getJunctionIDFromInternalEdge(fromID)]) {
914
if (fromID == crossing.edgeID) {
915
it->second.fromCrossed.insert(it->second.fromCrossed.end(), crossing.crossingEdges.begin(), crossing.crossingEdges.end());
916
}
917
}
918
}
919
}
920
}
921
}
922
}
923
924
925
void
926
NIImporter_SUMO::addProhibition(const SUMOSAXAttributes& attrs) {
927
bool ok = true;
928
std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, nullptr, ok, "");
929
std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, nullptr, ok, "");
930
if (!ok) {
931
return;
932
}
933
Prohibition p;
934
parseProhibitionConnection(prohibitor, p.prohibitorFrom, p.prohibitorTo, ok);
935
parseProhibitionConnection(prohibited, p.prohibitedFrom, p.prohibitedTo, ok);
936
if (!ok) {
937
return;
938
}
939
myProhibitions.push_back(p);
940
}
941
942
943
NBLoadedSUMOTLDef*
944
NIImporter_SUMO::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
945
if (currentTL) {
946
WRITE_ERRORF(TL("Definition of tl-logic '%' was not finished."), currentTL->getID());
947
return nullptr;
948
}
949
bool ok = true;
950
std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
951
SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);
952
std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
953
std::string typeS = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
954
TrafficLightType type;
955
if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
956
type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
957
} else {
958
WRITE_ERRORF(TL("Unknown traffic light type '%' for tlLogic '%'."), typeS, id);
959
return nullptr;
960
}
961
if (ok) {
962
return new NBLoadedSUMOTLDef(id, programID, offset, type);
963
} else {
964
return nullptr;
965
}
966
}
967
968
969
void
970
NIImporter_SUMO::addPhase(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
971
if (!currentTL) {
972
WRITE_ERROR(TL("found phase without tl-logic"));
973
return;
974
}
975
const std::string& id = currentTL->getID();
976
bool ok = true;
977
std::string state = attrs.get<std::string>(SUMO_ATTR_STATE, id.c_str(), ok);
978
SUMOTime duration = TIME2STEPS(attrs.get<double>(SUMO_ATTR_DURATION, id.c_str(), ok));
979
if (duration < 0) {
980
WRITE_ERRORF(TL("Phase duration for tl-logic '%/%' must be positive."), id, currentTL->getProgramID());
981
return;
982
}
983
// if the traffic light is an actuated traffic light, try to get the minimum and maximum durations and ends
984
std::vector<int> nextPhases = attrs.getOpt<std::vector<int> >(SUMO_ATTR_NEXT, id.c_str(), ok);
985
const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, nullptr, ok);
986
// Specific from actuated
987
const SUMOTime minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
988
const SUMOTime maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
989
const SUMOTime earliestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EARLIEST_END, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
990
const SUMOTime latestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_LATEST_END, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
991
// specific von NEMA
992
const SUMOTime vehExt = attrs.getOptSUMOTimeReporting(SUMO_ATTR_VEHICLEEXTENSION, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
993
const SUMOTime yellow = attrs.getOptSUMOTimeReporting(SUMO_ATTR_YELLOW, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
994
const SUMOTime red = attrs.getOptSUMOTimeReporting(SUMO_ATTR_RED, id.c_str(), ok, NBTrafficLightDefinition::UNSPECIFIED_DURATION);
995
if (ok) {
996
currentTL->addPhase(duration, state, minDuration, maxDuration, earliestEnd, latestEnd, vehExt, yellow, red, nextPhases, name);
997
}
998
}
999
1000
1001
GeoConvHelper*
1002
NIImporter_SUMO::loadLocation(const SUMOSAXAttributes& attrs, bool setLoaded) {
1003
// @todo refactor parsing of location since its duplicated in NLHandler and PCNetProjectionLoader
1004
bool ok = true;
1005
GeoConvHelper* result = nullptr;
1006
const Position offset = attrs.get<Position>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
1007
const Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
1008
const Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
1009
const std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
1010
if (ok) {
1011
result = new GeoConvHelper(proj, offset, origBoundary, convBoundary);
1012
result->resolveAbstractProjection();
1013
if (setLoaded) {
1014
GeoConvHelper::setLoaded(*result);
1015
}
1016
}
1017
return result;
1018
}
1019
1020
1021
Position
1022
NIImporter_SUMO::readPosition(const SUMOSAXAttributes& attrs, const std::string& id, bool& ok) {
1023
const double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
1024
const double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
1025
const double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0.);
1026
return Position(x, y, z);
1027
}
1028
1029
1030
void
1031
NIImporter_SUMO::parseProhibitionConnection(const std::string& attr, std::string& from, std::string& to, bool& ok) {
1032
// split from/to
1033
const std::string::size_type div = attr.find("->");
1034
if (div == std::string::npos) {
1035
WRITE_ERRORF(TL("Missing connection divider in prohibition attribute '%'"), attr);
1036
ok = false;
1037
}
1038
from = attr.substr(0, div);
1039
to = attr.substr(div + 2);
1040
// check whether the edges are known
1041
if (myEdges.count(from) == 0) {
1042
WRITE_ERRORF(TL("Unknown edge prohibition '%'"), from);
1043
ok = false;
1044
}
1045
if (myEdges.count(to) == 0) {
1046
WRITE_ERRORF(TL("Unknown edge prohibition '%'"), to);
1047
ok = false;
1048
}
1049
}
1050
1051
1052
void
1053
NIImporter_SUMO::addRoundabout(const SUMOSAXAttributes& attrs) {
1054
bool ok = true;
1055
const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
1056
if (ok) {
1057
myRoundabouts.push_back(edgeIDs);
1058
}
1059
}
1060
1061
1062
/****************************************************************************/
1063
1064