Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIImporter_OpenDrive.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_OpenDrive.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Laura Bieker
19
/// @author Mirko Barthauer
20
/// @date Mon, 14.04.2008
21
///
22
// Importer for networks stored in openDrive format
23
/****************************************************************************/
24
#include <config.h>
25
#include <string>
26
#include <cmath>
27
#include <iterator>
28
#include <utils/xml/SUMOSAXHandler.h>
29
#include <utils/common/UtilExceptions.h>
30
#include <utils/common/StringUtils.h>
31
#include <utils/common/ToString.h>
32
#include <utils/common/StringUtils.h>
33
#include <utils/common/MsgHandler.h>
34
#include <utils/common/SUMOVehicleClass.h>
35
#include <utils/shapes/SUMOPolygon.h>
36
#include <utils/shapes/PointOfInterest.h>
37
#include <utils/iodevices/OutputDevice.h>
38
#include <netbuild/NBEdge.h>
39
#include <netbuild/NBEdgeCont.h>
40
#include <netbuild/NBNode.h>
41
#include <netbuild/NBNodeCont.h>
42
#include <netbuild/NBNetBuilder.h>
43
#include <netbuild/NBOwnTLDef.h>
44
#include <netbuild/NBLoadedSUMOTLDef.h>
45
#include <netbuild/NBTrafficLightLogicCont.h>
46
#include <utils/xml/SUMOXMLDefinitions.h>
47
#include <utils/geom/GeoConvHelper.h>
48
#include <utils/geom/GeomConvHelper.h>
49
#include <foreign/eulerspiral/odrSpiral.h>
50
#include <utils/options/OptionsCont.h>
51
#include <utils/common/FileHelpers.h>
52
#include <utils/xml/SUMOXMLDefinitions.h>
53
#include <utils/xml/XMLSubSys.h>
54
#include <utils/geom/Boundary.h>
55
#include "NILoader.h"
56
#include "NIImporter_OpenDrive.h"
57
58
//#define DEBUG_VARIABLE_WIDTHS
59
//#define DEBUG_VARIABLE_SPEED
60
//#define DEBUG_CONNECTIONS
61
//#define DEBUG_SPIRAL
62
//#define DEBUG_INTERNALSHAPES
63
//#define DEBUG_SHAPE
64
65
#define DEBUG_ID ""
66
#define DEBUG_COND(road) ((road)->id == DEBUG_ID)
67
#define DEBUG_COND2(edgeID) (StringUtils::startsWith((edgeID), DEBUG_ID))
68
#define DEBUG_COND3(roadID) (roadID == DEBUG_ID)
69
//#define DEBUG_COND(road) (true)
70
//#define DEBUG_COND2(edgeID) (true)
71
//#define DEBUG_COND3(roadID) (true)
72
73
// ===========================================================================
74
// definitions
75
// ===========================================================================
76
77
// ===========================================================================
78
// static variables
79
// ===========================================================================
80
SequentialStringBijection::Entry NIImporter_OpenDrive::openDriveTags[] = {
81
{ "header", NIImporter_OpenDrive::OPENDRIVE_TAG_HEADER },
82
{ "road", NIImporter_OpenDrive::OPENDRIVE_TAG_ROAD },
83
{ "predecessor", NIImporter_OpenDrive::OPENDRIVE_TAG_PREDECESSOR },
84
{ "successor", NIImporter_OpenDrive::OPENDRIVE_TAG_SUCCESSOR },
85
{ "geometry", NIImporter_OpenDrive::OPENDRIVE_TAG_GEOMETRY },
86
{ "line", NIImporter_OpenDrive::OPENDRIVE_TAG_LINE },
87
{ "spiral", NIImporter_OpenDrive::OPENDRIVE_TAG_SPIRAL },
88
{ "arc", NIImporter_OpenDrive::OPENDRIVE_TAG_ARC },
89
{ "poly3", NIImporter_OpenDrive::OPENDRIVE_TAG_POLY3 },
90
{ "paramPoly3", NIImporter_OpenDrive::OPENDRIVE_TAG_PARAMPOLY3 },
91
{ "laneSection", NIImporter_OpenDrive::OPENDRIVE_TAG_LANESECTION },
92
{ "laneOffset", NIImporter_OpenDrive::OPENDRIVE_TAG_LANEOFFSET },
93
{ "left", NIImporter_OpenDrive::OPENDRIVE_TAG_LEFT },
94
{ "center", NIImporter_OpenDrive::OPENDRIVE_TAG_CENTER },
95
{ "right", NIImporter_OpenDrive::OPENDRIVE_TAG_RIGHT },
96
{ "lane", NIImporter_OpenDrive::OPENDRIVE_TAG_LANE },
97
{ "access", NIImporter_OpenDrive::OPENDRIVE_TAG_ACCESS },
98
{ "signal", NIImporter_OpenDrive::OPENDRIVE_TAG_SIGNAL },
99
{ "signalReference", NIImporter_OpenDrive::OPENDRIVE_TAG_SIGNALREFERENCE },
100
{ "controller", NIImporter_OpenDrive::OPENDRIVE_TAG_CONTROLLER },
101
{ "control", NIImporter_OpenDrive::OPENDRIVE_TAG_CONTROL },
102
{ "validity", NIImporter_OpenDrive::OPENDRIVE_TAG_VALIDITY },
103
{ "semantics", NIImporter_OpenDrive::OPENDRIVE_TAG_SEMANTICS },
104
{ "priority", NIImporter_OpenDrive::OPENDRIVE_TAG_PRIORITY },
105
{ "junction", NIImporter_OpenDrive::OPENDRIVE_TAG_JUNCTION },
106
{ "connection", NIImporter_OpenDrive::OPENDRIVE_TAG_CONNECTION },
107
{ "laneLink", NIImporter_OpenDrive::OPENDRIVE_TAG_LANELINK },
108
{ "width", NIImporter_OpenDrive::OPENDRIVE_TAG_WIDTH },
109
{ "speed", NIImporter_OpenDrive::OPENDRIVE_TAG_SPEED },
110
{ "elevation", NIImporter_OpenDrive::OPENDRIVE_TAG_ELEVATION },
111
{ "geoReference", NIImporter_OpenDrive::OPENDRIVE_TAG_GEOREFERENCE },
112
{ "offset", NIImporter_OpenDrive::OPENDRIVE_TAG_OFFSET },
113
{ "object", NIImporter_OpenDrive::OPENDRIVE_TAG_OBJECT },
114
{ "repeat", NIImporter_OpenDrive::OPENDRIVE_TAG_REPEAT },
115
{ "include", NIImporter_OpenDrive::OPENDRIVE_TAG_INCLUDE },
116
117
{ "", NIImporter_OpenDrive::OPENDRIVE_TAG_NOTHING }
118
};
119
120
121
SequentialStringBijection::Entry NIImporter_OpenDrive::openDriveAttrs[] = {
122
{ "revMajor", NIImporter_OpenDrive::OPENDRIVE_ATTR_REVMAJOR },
123
{ "revMinor", NIImporter_OpenDrive::OPENDRIVE_ATTR_REVMINOR },
124
{ "id", NIImporter_OpenDrive::OPENDRIVE_ATTR_ID },
125
{ "length", NIImporter_OpenDrive::OPENDRIVE_ATTR_LENGTH },
126
{ "width", NIImporter_OpenDrive::OPENDRIVE_ATTR_WIDTH },
127
{ "radius", NIImporter_OpenDrive::OPENDRIVE_ATTR_RADIUS },
128
{ "distance", NIImporter_OpenDrive::OPENDRIVE_ATTR_DISTANCE },
129
{ "tStart", NIImporter_OpenDrive::OPENDRIVE_ATTR_TSTART },
130
{ "tEnd", NIImporter_OpenDrive::OPENDRIVE_ATTR_TEND },
131
{ "widthStart", NIImporter_OpenDrive::OPENDRIVE_ATTR_WIDTHSTART },
132
{ "widthEnd", NIImporter_OpenDrive::OPENDRIVE_ATTR_WIDTHEND },
133
{ "junction", NIImporter_OpenDrive::OPENDRIVE_ATTR_JUNCTION },
134
{ "elementType", NIImporter_OpenDrive::OPENDRIVE_ATTR_ELEMENTTYPE },
135
{ "elementId", NIImporter_OpenDrive::OPENDRIVE_ATTR_ELEMENTID },
136
{ "contactPoint", NIImporter_OpenDrive::OPENDRIVE_ATTR_CONTACTPOINT },
137
{ "s", NIImporter_OpenDrive::OPENDRIVE_ATTR_S },
138
{ "t", NIImporter_OpenDrive::OPENDRIVE_ATTR_T },
139
{ "x", NIImporter_OpenDrive::OPENDRIVE_ATTR_X },
140
{ "y", NIImporter_OpenDrive::OPENDRIVE_ATTR_Y },
141
{ "z", NIImporter_OpenDrive::OPENDRIVE_ATTR_Z },
142
{ "hdg", NIImporter_OpenDrive::OPENDRIVE_ATTR_HDG },
143
{ "curvStart", NIImporter_OpenDrive::OPENDRIVE_ATTR_CURVSTART },
144
{ "curvEnd", NIImporter_OpenDrive::OPENDRIVE_ATTR_CURVEND },
145
{ "curvature", NIImporter_OpenDrive::OPENDRIVE_ATTR_CURVATURE },
146
{ "a", NIImporter_OpenDrive::OPENDRIVE_ATTR_A },
147
{ "b", NIImporter_OpenDrive::OPENDRIVE_ATTR_B },
148
{ "c", NIImporter_OpenDrive::OPENDRIVE_ATTR_C },
149
{ "d", NIImporter_OpenDrive::OPENDRIVE_ATTR_D },
150
{ "aU", NIImporter_OpenDrive::OPENDRIVE_ATTR_AU },
151
{ "bU", NIImporter_OpenDrive::OPENDRIVE_ATTR_BU },
152
{ "cU", NIImporter_OpenDrive::OPENDRIVE_ATTR_CU },
153
{ "dU", NIImporter_OpenDrive::OPENDRIVE_ATTR_DU },
154
{ "aV", NIImporter_OpenDrive::OPENDRIVE_ATTR_AV },
155
{ "bV", NIImporter_OpenDrive::OPENDRIVE_ATTR_BV },
156
{ "cV", NIImporter_OpenDrive::OPENDRIVE_ATTR_CV },
157
{ "dV", NIImporter_OpenDrive::OPENDRIVE_ATTR_DV },
158
{ "pRange", NIImporter_OpenDrive::OPENDRIVE_ATTR_PRANGE },
159
{ "type", NIImporter_OpenDrive::OPENDRIVE_ATTR_TYPE },
160
{ "level", NIImporter_OpenDrive::OPENDRIVE_ATTR_LEVEL },
161
{ "orientation", NIImporter_OpenDrive::OPENDRIVE_ATTR_ORIENTATION },
162
{ "dynamic", NIImporter_OpenDrive::OPENDRIVE_ATTR_DYNAMIC },
163
{ "incomingRoad", NIImporter_OpenDrive::OPENDRIVE_ATTR_INCOMINGROAD },
164
{ "connectingRoad", NIImporter_OpenDrive::OPENDRIVE_ATTR_CONNECTINGROAD },
165
{ "from", NIImporter_OpenDrive::OPENDRIVE_ATTR_FROM },
166
{ "to", NIImporter_OpenDrive::OPENDRIVE_ATTR_TO },
167
{ "fromLane", NIImporter_OpenDrive::OPENDRIVE_ATTR_FROMLANE },
168
{ "toLane", NIImporter_OpenDrive::OPENDRIVE_ATTR_TOLANE },
169
{ "max", NIImporter_OpenDrive::OPENDRIVE_ATTR_MAX },
170
{ "sOffset", NIImporter_OpenDrive::OPENDRIVE_ATTR_SOFFSET },
171
{ "rule", NIImporter_OpenDrive::OPENDRIVE_ATTR_RULE },
172
{ "restriction", NIImporter_OpenDrive::OPENDRIVE_ATTR_RESTRICTION },
173
{ "name", NIImporter_OpenDrive::OPENDRIVE_ATTR_NAME },
174
{ "signalId", NIImporter_OpenDrive::OPENDRIVE_ATTR_SIGNALID },
175
{ "file", NIImporter_OpenDrive::OPENDRIVE_ATTR_FILE },
176
// towards xodr v1.4 speed:unit
177
{ "unit", NIImporter_OpenDrive::OPENDRIVE_ATTR_UNIT },
178
179
{ "", NIImporter_OpenDrive::OPENDRIVE_ATTR_NOTHING }
180
};
181
182
183
bool NIImporter_OpenDrive::myImportAllTypes;
184
bool NIImporter_OpenDrive::myImportWidths;
185
double NIImporter_OpenDrive::myMinWidth;
186
bool NIImporter_OpenDrive::myIgnoreMisplacedSignals;
187
bool NIImporter_OpenDrive::myImportInternalShapes;
188
NIImporter_OpenDrive::OpenDriveController NIImporter_OpenDrive::myDummyController("", "");
189
190
// ===========================================================================
191
// method definitions
192
// ===========================================================================
193
// ---------------------------------------------------------------------------
194
// static methods (interface in this case)
195
// ---------------------------------------------------------------------------
196
void
197
NIImporter_OpenDrive::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
198
// check whether the option is set properly and all files exist
199
if (!oc.isUsableFileList("opendrive-files")) {
200
return;
201
}
202
// prepare types
203
myImportAllTypes = oc.getBool("opendrive.import-all-lanes");
204
myImportWidths = !oc.getBool("opendrive.ignore-widths");
205
myMinWidth = oc.getFloat("opendrive.min-width");
206
myImportInternalShapes = oc.getBool("opendrive.internal-shapes");
207
myIgnoreMisplacedSignals = oc.getBool("opendrive.ignore-misplaced-signals");
208
const bool customLaneShapes = oc.getBool("opendrive.lane-shapes");
209
NBTypeCont& tc = nb.getTypeCont();
210
NBNodeCont& nc = nb.getNodeCont();
211
// build the handler
212
std::map<std::string, OpenDriveEdge*> edges;
213
NIImporter_OpenDrive handler(nb.getTypeCont(), edges);
214
handler.needsCharacterData();
215
// parse file(s)
216
for (const std::string& file : oc.getStringVector("opendrive-files")) {
217
handler.setFileName(file);
218
PROGRESS_BEGIN_MESSAGE("Parsing opendrive from '" + file + "'");
219
XMLSubSys::runParser(handler, file, false, false, true);
220
PROGRESS_DONE_MESSAGE();
221
}
222
// apply signal reference information
223
for (auto& item : edges) {
224
for (OpenDriveSignal& signal : item.second->signals) {
225
if (signal.type == "") {
226
if (handler.getSignals().count(signal.id) == 0) {
227
WRITE_WARNINGF(TL("Could not find signal reference '%'."), signal.id);
228
} else {
229
const OpenDriveSignal& ref = handler.getSignals()[signal.id];
230
signal.type = ref.type;
231
signal.name = ref.name;
232
signal.dynamic = ref.dynamic;
233
signal.controller = ref.controller;
234
}
235
}
236
}
237
}
238
239
// split inner/outer edges
240
std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
241
for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
242
if ((*i).second->isInner) {
243
innerEdges[(*i).first] = (*i).second;
244
} else {
245
outerEdges[(*i).first] = (*i).second;
246
}
247
}
248
249
// convert geometries into a discretised representation
250
computeShapes(edges);
251
// check whether lane sections are valid and whether further must be introduced
252
revisitLaneSections(tc, edges);
253
254
// -------------------------
255
// node building
256
// -------------------------
257
// build nodes#1
258
// look at all links which belong to a node, collect their bounding boxes
259
// and place the node in the middle of this bounding box
260
std::map<std::string, Boundary> posMap;
261
std::map<std::string, std::string> edge2junction;
262
std::vector<NodeSet> joinedNodeIDs;
263
// compute node positions
264
for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
265
OpenDriveEdge* e = (*i).second;
266
assert(e->junction != "-1" && e->junction != "");
267
edge2junction[e->id] = e->junction;
268
if (posMap.find(e->junction) == posMap.end()) {
269
posMap[e->junction] = Boundary();
270
}
271
posMap[e->junction].add(e->geom.getBoxBoundary());
272
}
273
// build nodes
274
for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
275
//std::cout << " import node=" << (*i).first << " z=" << (*i).second.getCenter() << " boundary=" << (*i).second << "\n";
276
if (!nb.getNodeCont().insert((*i).first, (*i).second.getCenter())) {
277
throw ProcessError(TLF("Could not add node '%'.", (*i).first));
278
}
279
}
280
// assign built nodes
281
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
282
OpenDriveEdge* e = (*i).second;
283
for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
284
OpenDriveLink& l = *j;
285
const std::string& nid = l.elementID;
286
if (l.elementType != OPENDRIVE_ET_ROAD) {
287
if (nb.getNodeCont().retrieve(nid) == nullptr) {
288
// not yet seen, build (possibly a junction without connections)
289
Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
290
if (!nb.getNodeCont().insert(nid, pos)) {
291
throw ProcessError(TLF("Could not build node '%'.", nid));
292
}
293
}
294
// set node information
295
setNodeSecure(nb.getNodeCont(), *e, l.elementID, l.linkType, joinedNodeIDs);
296
continue;
297
}
298
if (edge2junction.find(l.elementID) != edge2junction.end()) {
299
// set node information of an internal road
300
setNodeSecure(nb.getNodeCont(), *e, edge2junction[l.elementID], l.linkType, joinedNodeIDs);
301
continue;
302
}
303
}
304
}
305
// we should now have all nodes set for links which are not outer edge-to-outer edge links
306
307
308
// build nodes#2
309
// build nodes for all outer edge-to-outer edge connections
310
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
311
OpenDriveEdge* e = (*i).second;
312
for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
313
OpenDriveLink& l = *j;
314
if (l.elementType != OPENDRIVE_ET_ROAD || edge2junction.find(l.elementID) != edge2junction.end()) {
315
// is a connection to an internal edge, or a node, skip
316
continue;
317
}
318
// we have a direct connection between to external edges
319
std::string id1 = e->id;
320
std::string id2 = l.elementID;
321
if (id1 < id2) {
322
std::swap(id1, id2);
323
}
324
std::string nid = id1 + "." + id2;
325
if (nb.getNodeCont().retrieve(nid) == nullptr) {
326
// not yet seen, build
327
Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
328
if (!nb.getNodeCont().insert(nid, pos)) {
329
throw ProcessError(TLF("Could not build node '%'.", nid));
330
}
331
}
332
/* debug-stuff
333
else {
334
Position pos = l.linkType==OPENDRIVE_LT_SUCCESSOR ? e.geom[e.geom.size()-1] : e.geom[0];
335
cout << nid << " " << pos << " " << nb.getNodeCont().retrieve(nid)->getPosition() << endl;
336
}
337
*/
338
setNodeSecure(nb.getNodeCont(), *e, nid, l.linkType, joinedNodeIDs);
339
}
340
}
341
// we should now have start/end nodes for all outer edge-to-outer edge connections
342
343
344
// build nodes#3
345
// assign further nodes generated from inner-edges
346
// these nodes have not been assigned earlier, because the connections are referenced in inner-edges
347
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
348
OpenDriveEdge* e = (*i).second;
349
if (e->to != nullptr && e->from != nullptr) {
350
continue;
351
}
352
for (std::map<std::string, OpenDriveEdge*>::iterator j = innerEdges.begin(); j != innerEdges.end(); ++j) {
353
OpenDriveEdge* ie = (*j).second;
354
for (std::vector<OpenDriveLink>::iterator k = ie->links.begin(); k != ie->links.end(); ++k) {
355
OpenDriveLink& il = *k;
356
if (il.elementType != OPENDRIVE_ET_ROAD || il.elementID != e->id) {
357
// not conneted to the currently investigated outer edge
358
continue;
359
}
360
std::string nid = edge2junction[ie->id];
361
if (il.contactPoint == OPENDRIVE_CP_START) {
362
setNodeSecure(nb.getNodeCont(), *e, nid, OPENDRIVE_LT_PREDECESSOR, joinedNodeIDs);
363
} else {
364
setNodeSecure(nb.getNodeCont(), *e, nid, OPENDRIVE_LT_SUCCESSOR, joinedNodeIDs);
365
}
366
}
367
}
368
369
}
370
371
// build start/end nodes which were not defined previously
372
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
373
OpenDriveEdge* e = (*i).second;
374
if ((e->from == nullptr || e->to == nullptr) && e->geom.size() == 0) {
375
continue;
376
}
377
if (e->from == nullptr) {
378
const std::string nid = e->id + ".begin";
379
e->from = getOrBuildNode(nid, e->geom.front(), nb.getNodeCont());
380
}
381
if (e->to == nullptr) {
382
const std::string nid = e->id + ".end";
383
e->to = getOrBuildNode(nid, e->geom.back(), nb.getNodeCont());
384
}
385
}
386
387
std::map<NBNode*, NBNode*> joinedNodes;
388
for (NodeSet& joined : joinedNodeIDs) {
389
Position joinedPos(0, 0);
390
for (NBNode* j : joined) {
391
joinedPos.add(j->getPosition());
392
}
393
joinedPos.mul(1. / (double)joined.size());
394
const std::string joinedID = nc.createClusterId(joined);
395
if (!nc.insert(joinedID, joinedPos)) {
396
throw ProcessError(TLF("Could not add node '%'.", joinedID));
397
}
398
NBNode* n = nc.retrieve(joinedID);
399
for (NBNode* j : joined) {
400
joinedNodes[j] = n;
401
}
402
}
403
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
404
OpenDriveEdge* e = (*i).second;
405
if (joinedNodes.count(e->from) != 0) {
406
nc.extract(e->from, true);
407
e->from = joinedNodes[e->from];
408
}
409
if (joinedNodes.count(e->to) != 0) {
410
nc.extract(e->to, true);
411
e->to = joinedNodes[e->to];
412
}
413
}
414
415
416
// -------------------------
417
// edge building
418
// -------------------------
419
const double defaultSpeed = tc.getEdgeTypeSpeed("");
420
const bool saveOrigIDs = OptionsCont::getOptions().getBool("output.original-names");
421
const bool positionIDs = OptionsCont::getOptions().getBool("opendrive.position-ids");
422
// lane-id-map sumoEdge,sumoLaneIndex->odrLaneIndex
423
std::map<std::pair<NBEdge*, int>, int> laneIndexMap;
424
// build edges
425
for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
426
OpenDriveEdge* e = (*i).second;
427
if (e->geom.size() < 2) {
428
WRITE_WARNINGF(TL("Ignoring road '%' without geometry."), e->id);
429
continue;
430
}
431
bool lanesBuilt = false;
432
433
// go along the lane sections, build a node in between of each pair
434
435
/// @todo: One could think of determining whether lane sections may be joined when being equal in SUMO's sense
436
/// Their naming would have to be updated, too, also in TraCI
437
438
/// @todo: probably, the lane offsets to the center are not right
439
NBNode* sFrom = e->from;
440
NBNode* sTo = e->to;
441
int priorityR = e->getPriority(OPENDRIVE_TAG_RIGHT);
442
int priorityL = e->getPriority(OPENDRIVE_TAG_LEFT);
443
double sB = 0;
444
double sE = e->length;
445
// 0-length geometries are possible if only the inner points are represented
446
PositionVector geomWithOffset = e->geom;
447
if (e->laneOffsets.size() > 0) {
448
try {
449
geomWithOffset.move2sideCustom(e->laneOffsets);
450
//std::cout << " e=" << e->id << " offsets=" << e->laneOffsets << " geom=" << e->geom << " geom2=" << geomWithOffset << "\n";
451
} catch (InvalidArgument&) {
452
WRITE_WARNINGF(TL("Could not apply laneOffsets for edge '%'"), e->id);
453
}
454
}
455
#ifdef DEBUG_SHAPE
456
if (DEBUG_COND3(e->id)) {
457
std::cout << " geomWithOffset=" << geomWithOffset << "\n";
458
}
459
#endif
460
const double length2D = geomWithOffset.length2D();
461
double cF = length2D == 0 ? 1 : e->length / length2D;
462
NBEdge* prevRight = nullptr;
463
NBEdge* prevLeft = nullptr;
464
465
// starting at the same node as ending, and no lane sections?
466
if (sFrom == sTo && e->laneSections.size() == 1) {
467
// --> loop, split!
468
OpenDriveLaneSection ls = e->laneSections[0];
469
ls.s = e->length / 2.;
470
e->laneSections.push_back(ls);
471
WRITE_WARNING("Edge '" + e->id + "' has to be split as it connects same junctions.")
472
}
473
sanitizeWidths(e);
474
if (myMinWidth > 0) {
475
const double minDist = oc.getFloat("opendrive.curve-resolution");
476
splitMinWidths(e, tc, minDist);
477
}
478
479
// build along lane sections
480
int sectionIndex = 0;
481
for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
482
// add internal node if needed
483
if (j == e->laneSections.end() - 1) {
484
sTo = e->to;
485
sE = e->length / cF;
486
} else {
487
double nextS = (j + 1)->s;
488
const std::string nodeID = e->id + (positionIDs ? "." + toString(nextS) : "#" + toString(sectionIndex + 1));
489
sTo = new NBNode(nodeID, geomWithOffset.positionAtOffset(nextS));
490
if (!nb.getNodeCont().insert(sTo)) {
491
throw ProcessError(TLF("Could not add node '%'.", sTo->getID()));
492
}
493
sE = nextS / cF;
494
}
495
const PositionVector geom = geomWithOffset.getSubpart2D(sB, sE).simplified2(false);
496
std::string id = e->id;
497
if (positionIDs) {
498
if (sFrom != e->from || sTo != e->to) {
499
id = id + "." + toString((*j).s);
500
} else if (e->laneSections.size() == 1) {
501
id = id + ".0.00";
502
}
503
} else if (e->laneSections.size() > 1) {
504
id = id + "#" + toString(sectionIndex++);
505
}
506
#ifdef DEBUG_VARIABLE_WIDTHS
507
if (DEBUG_COND(e)) {
508
std::cout << " id=" << id << " sB=" << sB << " sE=" << sE << " geom=" << geom << "\n";
509
}
510
#endif
511
512
// build lanes to right
513
NBEdge* currRight = nullptr;
514
if ((*j).rightLaneNumber > 0) {
515
std::vector<double> offsets(geom.size(), 0);
516
bool useOffsets = false;
517
PositionVector rightGeom = geom;
518
#ifdef DEBUG_SHAPE
519
if (DEBUG_COND3(e->id)) {
520
gDebugFlag1 = true;
521
}
522
#endif
523
rightGeom.move2side((*j).discardedInnerWidthRight);
524
#ifdef DEBUG_SHAPE
525
if (DEBUG_COND3(e->id)) {
526
std::cout << " -" << id << "_geom=" << geom << " -" << id << "_rightGeom=" << rightGeom << "\n";
527
gDebugFlag1 = false;
528
}
529
#endif
530
PositionVector laneGeom = rightGeom;
531
currRight = new NBEdge("-" + id, sFrom, sTo, (*j).rightType, defaultSpeed, NBEdge::UNSPECIFIED_FRICTION, (*j).rightLaneNumber, priorityR,
532
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, rightGeom, LaneSpreadFunction::RIGHT, e->streetName, "", true);
533
lanesBuilt = true;
534
std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_RIGHT];
535
std::sort(lanes.begin(), lanes.end(), LaneSorter());
536
for (const OpenDriveLane& odl : lanes) {
537
std::map<int, int>::const_iterator lp = (*j).laneMap.find(odl.id);
538
if (lp != (*j).laneMap.end()) {
539
int sumoLaneIndex = lp->second;
540
setLaneAttributes(e, currRight->getLaneStruct(sumoLaneIndex), odl, saveOrigIDs, tc);
541
laneIndexMap[std::make_pair(currRight, sumoLaneIndex)] = odl.id;
542
if (useOffsets) {
543
PositionVector laneShape = laneGeom;
544
laneShape.move2sideCustom(offsets);
545
currRight->getLaneStruct(sumoLaneIndex).customShape = laneShape;
546
}
547
} else if (customLaneShapes) {
548
useOffsets = true;
549
}
550
if (customLaneShapes) {
551
addOffsets(false, laneGeom, odl.widthData, e->id + "_" + toString(odl.id), offsets);
552
}
553
}
554
if (!nb.getEdgeCont().insert(currRight, myImportAllTypes)) {
555
throw ProcessError(TLF("Could not add edge '%'.", currRight->getID()));
556
}
557
if (nb.getEdgeCont().wasIgnored("-" + id)) {
558
prevRight = nullptr;
559
} else {
560
// connect lane sections
561
if (prevRight != nullptr) {
562
std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_RIGHT, *(j - 1));
563
for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
564
#ifdef DEBUG_CONNECTIONS
565
if (DEBUG_COND(e)) {
566
std::cout << "addCon1 from=" << prevRight->getID() << "_" << (*k).first << " to=" << currRight->getID() << "_" << (*k).second << "\n";
567
}
568
#endif
569
prevRight->addLane2LaneConnection((*k).first, currRight, (*k).second, NBEdge::Lane2LaneInfoType::VALIDATED);
570
}
571
}
572
prevRight = currRight;
573
}
574
}
575
576
// build lanes to left
577
NBEdge* currLeft = nullptr;
578
if ((*j).leftLaneNumber > 0) {
579
std::vector<double> offsets(geom.size(), 0);
580
bool useOffsets = false;
581
PositionVector leftGeom = geom;
582
leftGeom.move2side(-(*j).discardedInnerWidthLeft);
583
PositionVector laneGeom = leftGeom;
584
#ifdef DEBUG_SHAPE
585
if (DEBUG_COND3(e->id)) {
586
std::cout << " " << id << "_geom=" << geom << " " << id << "_leftGeom=" << leftGeom << "\n";
587
}
588
#endif
589
currLeft = new NBEdge(id, sTo, sFrom, (*j).leftType, defaultSpeed, NBEdge::UNSPECIFIED_FRICTION, (*j).leftLaneNumber, priorityL,
590
NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, leftGeom.reverse(), LaneSpreadFunction::RIGHT, e->streetName, "", true);
591
lanesBuilt = true;
592
std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_LEFT];
593
std::sort(lanes.begin(), lanes.end(), LaneSorter());
594
for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
595
std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
596
if (lp != (*j).laneMap.end()) {
597
int sumoLaneIndex = lp->second;
598
setLaneAttributes(e, currLeft->getLaneStruct(sumoLaneIndex), *k, saveOrigIDs, tc);
599
laneIndexMap[std::make_pair(currLeft, sumoLaneIndex)] = (*k).id;
600
if (useOffsets) {
601
PositionVector laneShape = laneGeom;
602
laneShape.move2sideCustom(offsets);
603
currLeft->getLaneStruct(sumoLaneIndex).customShape = laneShape.reverse();
604
}
605
} else if (customLaneShapes) {
606
useOffsets = true;
607
}
608
if (customLaneShapes) {
609
addOffsets(true, laneGeom, (*k).widthData, e->id + "_" + toString((*k).id), offsets);
610
}
611
}
612
if (!nb.getEdgeCont().insert(currLeft, myImportAllTypes)) {
613
throw ProcessError(TLF("Could not add edge '%'.", currLeft->getID()));
614
}
615
if (nb.getEdgeCont().wasIgnored(id)) {
616
prevLeft = nullptr;
617
} else {
618
// connect lane sections
619
if (prevLeft != nullptr) {
620
std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_LEFT, *(j - 1));
621
for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
622
#ifdef DEBUG_CONNECTIONS
623
if (DEBUG_COND(e)) {
624
std::cout << "addCon2 from=" << currLeft->getID() << "_" << (*k).first << " to=" << prevLeft->getID() << "_" << (*k).second << "\n";
625
}
626
#endif
627
currLeft->addLane2LaneConnection((*k).first, prevLeft, (*k).second, NBEdge::Lane2LaneInfoType::VALIDATED);
628
}
629
}
630
prevLeft = currLeft;
631
}
632
}
633
(*j).sumoID = id;
634
635
636
sB = sE;
637
sFrom = sTo;
638
}
639
if (oc.isSet("polygon-output")) {
640
writeRoadObjects(e);
641
}
642
if (!lanesBuilt) {
643
WRITE_WARNINGF(TL("Edge '%' has no lanes."), e->id);
644
}
645
}
646
if (oc.isSet("polygon-output")) {
647
for (auto item : innerEdges) {
648
writeRoadObjects(item.second);
649
}
650
}
651
652
// -------------------------
653
// connections building
654
// -------------------------
655
// generate explicit lane-to-lane connections
656
for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
657
setEdgeLinks2(*(*i).second, edges);
658
}
659
// compute connections across intersections, if any
660
std::vector<Connection> connections2;
661
for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
662
const std::set<Connection>& conns = (*j).second->connections;
663
664
for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
665
if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
666
// connections starting at inner edges are processed by starting from outer edges
667
continue;
668
}
669
if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
670
std::set<Connection> seen;
671
buildConnectionsToOuter(*i, innerEdges, edges, tc, connections2, seen);
672
} else {
673
connections2.push_back(*i);
674
}
675
}
676
}
677
// set connections
678
for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
679
#ifdef DEBUG_CONNECTIONS
680
std::cout << "connections2 " << (*i).getDescription() << "\n";
681
#endif
682
std::string fromEdge = (*i).fromEdge;
683
if (edges.find(fromEdge) == edges.end()) {
684
WRITE_WARNINGF(TL("While setting connections: from-edge '%' is not known."), fromEdge);
685
continue;
686
}
687
OpenDriveEdge* odFrom = edges[fromEdge];
688
int fromLane = (*i).fromLane;
689
bool fromLast = ((*i).fromCP == OPENDRIVE_CP_END) && ((*i).fromLane < 0);
690
fromEdge = fromLast ? odFrom->laneSections.back().sumoID : odFrom->laneSections[0].sumoID;
691
692
std::string toEdge = (*i).toEdge;
693
if (edges.find(toEdge) == edges.end()) {
694
WRITE_WARNINGF(TL("While setting connections: to-edge '%' is not known."), toEdge);
695
continue;
696
}
697
698
OpenDriveEdge* odTo = edges[toEdge];
699
int toLane = (*i).toLane;
700
bool toLast = ((*i).toCP == OPENDRIVE_CP_END) || ((*i).toLane > 0);
701
toEdge = toLast ? odTo->laneSections.back().sumoID : odTo->laneSections[0].sumoID;
702
703
if (fromLane == UNSET_CONNECTION) {
704
continue;
705
}
706
if (fromLane < 0) {
707
fromEdge = reversedEdgeID(fromEdge);
708
}
709
if (toLane == UNSET_CONNECTION) {
710
continue;
711
}
712
if (toLane < 0) {
713
toEdge = reversedEdgeID(toEdge);
714
}
715
fromLane = fromLast ? odFrom->laneSections.back().laneMap[fromLane] : odFrom->laneSections[0].laneMap[fromLane];
716
toLane = toLast ? odTo->laneSections.back().laneMap[toLane] : odTo->laneSections[0].laneMap[toLane];
717
NBEdge* from = nb.getEdgeCont().retrieve(fromEdge);
718
NBEdge* to = nb.getEdgeCont().retrieve(toEdge);
719
if (from == nullptr) {
720
WRITE_WARNINGF(TL("Could not find fromEdge representation of '%' in connection '%'."), fromEdge, (*i).origID);
721
}
722
if (to == nullptr) {
723
WRITE_WARNINGF(TL("Could not find fromEdge representation of '%' in connection '%'."), toEdge, (*i).origID);
724
}
725
if (from == nullptr || to == nullptr) {
726
continue;
727
}
728
729
#ifdef DEBUG_CONNECTIONS
730
if (DEBUG_COND2(from->getID())) {
731
std::cout << "addCon3 from=" << from->getID() << "_" << fromLane << " to=" << to->getID() << "_" << toLane << "\n";
732
}
733
#endif
734
from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::Lane2LaneInfoType::USER, false, false,
735
KEEPCLEAR_UNSPECIFIED,
736
NBEdge::UNSPECIFIED_CONTPOS,
737
NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE,
738
NBEdge::UNSPECIFIED_SPEED,
739
NBEdge::UNSPECIFIED_FRICTION,
740
NBEdge::UNSPECIFIED_LOADED_LENGTH,
741
(*i).shape);
742
743
if ((*i).origID != "" && saveOrigIDs) {
744
// @todo: this is the most silly way to determine the connection
745
std::vector<NBEdge::Connection>& cons = from->getConnections();
746
for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
747
if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
748
(*k).setParameter(SUMO_PARAM_ORIGID, (*i).origID + "_" + toString((*i).origLane));
749
break;
750
}
751
}
752
}
753
}
754
755
756
// -------------------------
757
// traffic lights
758
// -------------------------
759
std::map<std::string, std::string> signal2junction;
760
std::map<std::string, OpenDriveController>& controllers = handler.getControllers();
761
762
for (const auto& it : edges) {
763
const OpenDriveEdge* e = it.second;
764
for (const OpenDriveSignal& signal : e->signals) { // signal for which junction?
765
if (signal.controller.size() == 0) {
766
continue;
767
}
768
std::string junctionID;
769
for (auto connection : e->connections) {
770
if ((connection.fromLane < 0 && signal.orientation < 0) || (connection.fromLane > 0 && signal.orientation > 0)) {
771
continue;
772
}
773
if ((signal.minLane == 0 && signal.maxLane == 0) || (signal.maxLane >= connection.fromLane && signal.minLane <= connection.fromLane)) {
774
const OpenDriveEdge* connectedEdge = edges[connection.toEdge];
775
if (controllers[signal.controller].junction.size() > 0 && controllers[signal.controller].junction != connectedEdge->junction) {
776
WRITE_WARNINGF(TL("Controlling multiple junctions by the same controller '%' is currently not implemented."), signal.controller);
777
}
778
controllers[signal.controller].junction = connectedEdge->junction;
779
}
780
}
781
}
782
}
783
784
const bool importSignalGroups = oc.getBool("opendrive.signal-groups");
785
for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
786
OpenDriveEdge* e = (*i).second;
787
for (const OpenDriveSignal& signal : e->signals) {
788
int intType = -1;
789
try {
790
intType = StringUtils::toInt(signal.type);
791
} catch (NumberFormatException&) {}
792
if (intType < 1000001 || (intType > 1000013 && intType != 1000020) || intType == 1000008) {
793
// not a traffic_light (Section 6.11)
794
continue;
795
}
796
if (e->laneSections.size() == 0) {
797
WRITE_WARNINGF(TL("Edge '%' has signals but no lane sections."), e->id);
798
continue;
799
}
800
std::vector<OpenDriveLaneSection>::iterator k = e->laneSections.begin();
801
bool found = false;
802
for (; k != e->laneSections.end() - 1 && !found;) {
803
if (signal.s > (*k).s && signal.s <= (*(k + 1)).s) {
804
found = true;
805
} else {
806
++k;
807
}
808
}
809
810
std::string id = (*k).sumoID;
811
if (id == "") {
812
// traffic light on connecting road
813
if (e->junction != "") {
814
//WRITE_WARNINGF(TL("Found a traffic light signal on an internal edge; will not build it (original edge id='%')."), e->id);
815
std::string fromID, toID;
816
for (std::vector<OpenDriveLink>::const_iterator l = e->links.begin(); l != e->links.end(); ++l) {
817
if ((*l).linkType == OPENDRIVE_LT_PREDECESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
818
if (fromID != "") {
819
WRITE_WARNING(TL("Ambiguous start of connection."));
820
}
821
const OpenDriveEdge* const ode = edges[(*l).elementID];
822
if ((*l).contactPoint == OPENDRIVE_CP_START) {
823
fromID = ode->laneSections[0].sumoID;
824
if (signal.orientation < 0) {
825
fromID = "-" + fromID;
826
}
827
} else {
828
fromID = ode->laneSections.back().sumoID;
829
if (signal.orientation > 0) {
830
fromID = "-" + fromID;
831
}
832
}
833
}
834
if ((*l).linkType == OPENDRIVE_LT_SUCCESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
835
if (toID != "") {
836
WRITE_WARNING(TL("Ambiguous end of connection."));
837
}
838
const OpenDriveEdge* const ode = edges[(*l).elementID];
839
toID = (*l).contactPoint == OPENDRIVE_CP_START ? ode->laneSections[0].sumoID : ode->laneSections.back().sumoID;
840
}
841
}
842
// figure out the correct combination of directions
843
NBEdge* from;
844
NBEdge* to;
845
auto fromTo = retrieveSignalEdges(nb, fromID, toID, signal.minLane);
846
from = fromTo.first;
847
to = fromTo.second;
848
if (from == nullptr) {
849
WRITE_WARNINGF(TL("Could not find edge '%' for signal '%'."), fromID, signal.id);
850
continue;
851
}
852
853
// consider signal validity to determine direction
854
if (signal.maxLane != 0) {
855
bool fromForward = from->getID()[0] == '-';
856
bool lanesForward = signal.maxLane < 0;
857
if (fromForward != lanesForward) {
858
std::swap(fromID, toID);
859
860
const auto& signalFromTo = retrieveSignalEdges(nb, fromID, toID, signal.minLane);
861
from = signalFromTo.first;
862
to = signalFromTo.second;
863
if (from == nullptr) {
864
WRITE_WARNINGF(TL("Could not find edge '%' for signal '%'."), fromID, signal.id);
865
continue;
866
}
867
}
868
}
869
for (NBEdge::Connection& c : from->getConnections()) {
870
if (c.toEdge == to) {
871
int odLane = laneIndexMap[std::make_pair(from, c.fromLane)];
872
//std::cout << " e=" << e->id << " from=" << from->getID() << " fromLane=" << c.fromLane << " odLane=" << odLane << " sMin=" << signal.minLane << " sMax=" << signal.maxLane << "\n";
873
if (signal.minLane == 0 || (signal.minLane <= odLane && signal.maxLane >= odLane)) {
874
if (c.hasParameter("signalID")) {
875
c.setParameter("signalID", c.getParameter("signalID") + " " + signal.id);
876
} else {
877
c.setParameter("signalID", signal.id);
878
}
879
}
880
// set tlIndex to allow signal groups (defined in OpenDRIVE controller elements)
881
if (importSignalGroups) {
882
const OpenDriveController& controller = handler.getController(signal.id);
883
if (controller.id != "") {
884
if (c.getParameter("controllerID") != "") {
885
WRITE_WARNINGF(TL("The signaling of the connection from '%' to '%' (controller '%') is ambiguous because it is overwritten signal '%' and with controller '%'."), from->getID(), c.toEdge->getID(), c.getParameter("controllerID"), signal.id, controller.id);
886
}
887
//junctionsWithControllers.insert(from->getToNode()->getID());
888
int tlIndex = handler.getTLIndexForController(controller.id);
889
c.tlLinkIndex = tlIndex;
890
c.setParameter("controllerID", controller.id);
891
}
892
}
893
}
894
}
895
getTLSSecure(from, nb);
896
897
//std::cout << "odrEdge=" << e->id << " fromID=" << fromID << " toID=" << toID << " from=" << from->getID() << " to=" << to->getID()
898
// << " signal=" << signal.id << " minLane=" << signal.minLane << " maxLane=" << signal.maxLane << "\n";
899
} else {
900
WRITE_WARNINGF(TL("Found a traffic light signal on an unknown edge (original edge id='%')."), e->id);
901
continue;
902
}
903
} else {
904
// traffic light on normal road
905
if (signal.orientation == 1) {
906
// forward direction has negative lane indices and gets a negative prefix in sumo
907
id = "-" + id;
908
}
909
NBEdge* edge = nb.getEdgeCont().retrieve(id);
910
if (edge == nullptr) {
911
WRITE_WARNINGF(TL("Could not find edge '%' for signal '%'."), id, signal.id);
912
continue;
913
}
914
915
/// XXX consider lane validity
916
for (NBEdge::Connection& c : edge->getConnections()) {
917
int odLane = laneIndexMap[std::make_pair(edge, c.fromLane)];
918
if (signal.minLane == 0 || (signal.minLane <= odLane && signal.maxLane >= odLane)) {
919
if (c.hasParameter("signalID")) {
920
c.setParameter("signalID", c.getParameter("signalID") + " " + signal.id);
921
} else {
922
c.setParameter("signalID", signal.id);
923
}
924
}
925
926
// set tlIndex to allow signal groups (defined in OpenDRIVE controller elements)
927
if (importSignalGroups) {
928
const OpenDriveController& controller = handler.getController(signal.id);
929
if (controller.id != "") {
930
if (c.getParameter("controllerID") != "") {
931
WRITE_WARNINGF(TL("The signaling of the connection from '%' to '%' (controller '%') is ambiguous because it is overwritten with signal '%' and controller '%'."), edge->getID(), c.toEdge->getID(), c.getParameter("controllerID"), signal.id, controller.id);
932
}
933
//junctionsWithControllers.insert(edge->getToNode()->getID());
934
int tlIndex = handler.getTLIndexForController(controller.id);
935
c.tlLinkIndex = tlIndex;
936
c.setParameter("controllerID", controller.id);
937
}
938
}
939
}
940
getTLSSecure(edge, nb);
941
//std::cout << "odrEdge=" << e->id << " sumoID=" << (*k).sumoID << " sumoEdge=" << edge->getID()
942
// << " signal=" << signal.id << " minLane=" << signal.minLane << " maxLane=" << signal.maxLane << "\n";
943
}
944
// @note: tls 'signalID' parameters are set via NBTrafficLightLogicCont::setOpenDriveSignalParameters
945
// @note: OpenDRIVE controllers are applied to the signal programs in NBTrafficLightLogicCont::applyOpenDriveControllers
946
}
947
}
948
949
// -------------------------
950
// clean up
951
// -------------------------
952
for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
953
delete (*i).second;
954
}
955
}
956
957
958
void
959
NIImporter_OpenDrive::writeRoadObjects(const OpenDriveEdge* e) {
960
OptionsCont& oc = OptionsCont::getOptions();
961
const bool writeGeo = GeoConvHelper::getLoaded().usingGeoProjection() && (
962
oc.isDefault("proj.plain-geo") || oc.getBool("proj.plain-geo"));
963
OutputDevice& dev = OutputDevice::getDevice(oc.getString("polygon-output"));
964
dev.writeXMLHeader("additional", "additional_file.xsd");
965
//SUMOPolygon poly("road_" + e->id, "road", RGBColor::BLUE, e->geom, true, false);
966
//poly.writeXML(dev, false);
967
for (auto& o : e->objects) {
968
Position ref = e->geom.positionAtOffset2D(o.s, -o.t);
969
if (o.radius >= 0) {
970
// cicrular shape
971
// GeoConvHelper::getFinal is not ready yet
972
GeoConvHelper::getLoaded().cartesian2geo(ref);
973
PointOfInterest POI(o.id, o.type, RGBColor::YELLOW, ref, true, "", -1, false, 0, SUMOXMLDefinitions::POIIcons.getString(POIIcon::NONE));
974
POI.setParameter("name", o.name);
975
POI.writeXML(dev, writeGeo);
976
} else {
977
// rectangular shape
978
PositionVector centerLine;
979
centerLine.push_back(Position(-o.length / 2, 0));
980
centerLine.push_back(Position(o.length / 2, 0));
981
double roadHdg = e->geom.rotationAtOffset(o.s);
982
centerLine.rotate2D(roadHdg + o.hdg);
983
//PointOfInterest poiRef("ref_" + o.id, "", RGBColor::CYAN, ref, false, "", 0, 0, Shape::DEFAULT_LAYER + 2);
984
//poiRef.writeXML(dev, false);
985
centerLine.add(ref);
986
//SUMOPolygon polyCenter("center_" + o.id, "", RGBColor::MAGENTA, centerLine, true, false, Shape::DEFAULT_LAYER + 1);
987
//polyCenter.writeXML(dev, false);
988
centerLine.move2side(o.width / 2);
989
PositionVector shape = centerLine;
990
centerLine.move2side(-o.width);
991
shape.append(centerLine.reverse(), POSITION_EPS);
992
if (writeGeo) {
993
// GeoConvHelper::getFinal is not ready yet
994
for (Position& p : shape) {
995
GeoConvHelper::getLoaded().cartesian2geo(p);
996
}
997
}
998
SUMOPolygon poly(o.id, o.type, RGBColor::YELLOW, shape, true, true, 1, 7);
999
poly.setParameter("name", o.name);
1000
poly.writeXML(dev, writeGeo);
1001
}
1002
}
1003
}
1004
1005
1006
1007
std::pair<NBEdge*, NBEdge*>
1008
NIImporter_OpenDrive::retrieveSignalEdges(NBNetBuilder& nb, const std::string& fromID, const std::string& toID, int signalMinLane) {
1009
NBEdge* from;
1010
NBEdge* to;
1011
NBEdge* fromReverse;
1012
NBEdge* toReverse;
1013
from = nb.getEdgeCont().retrieve(fromID);
1014
to = nb.getEdgeCont().retrieve(toID);
1015
fromReverse = nb.getEdgeCont().retrieve(reversedEdgeID(fromID));
1016
toReverse = nb.getEdgeCont().retrieve(reversedEdgeID(toID));
1017
1018
if (from == nullptr) {
1019
from = fromReverse;
1020
}
1021
if (to == nullptr) {
1022
to = toReverse;
1023
}
1024
if (from != nullptr && to != nullptr && from->getToNode() != to->getFromNode()) {
1025
if (from->getFromNode() == to->getToNode() && signalMinLane >= 0) {
1026
std::swap(from, to);
1027
} else if (fromReverse != nullptr && toReverse != nullptr && fromReverse->getToNode() == toReverse->getFromNode() && signalMinLane <= 0) {
1028
from = fromReverse;
1029
to = toReverse;
1030
} else {
1031
if (from->getFromNode() == to->getFromNode()
1032
&& fromReverse != nullptr && fromReverse->getToNode() == to->getFromNode()) {
1033
from = fromReverse;
1034
}
1035
if (to->getToNode() == from->getToNode()
1036
&& toReverse != nullptr && toReverse->getFromNode() == from->getToNode()) {
1037
to = toReverse;
1038
}
1039
}
1040
}
1041
//std::cout << fromID << " " << toID << " from=" << Named::getIDSecure(from) << " to=" << Named::getIDSecure(to) << " sMin=" << signalMinLane << "\n";
1042
return std::make_pair(from, to);
1043
}
1044
1045
1046
NBTrafficLightDefinition*
1047
NIImporter_OpenDrive::getTLSSecure(NBEdge* inEdge, /*const NBEdge::Connection& conn,*/ NBNetBuilder& nb) {
1048
NBNode* toNode = inEdge->getToNode();
1049
if (!toNode->isTLControlled()) {
1050
TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
1051
NBOwnTLDef* tlDef = new NBOwnTLDef(toNode->getID(), toNode, 0, type);
1052
if (!nb.getTLLogicCont().insert(tlDef)) {
1053
// actually, nothing should fail here
1054
delete tlDef;
1055
throw ProcessError();
1056
}
1057
toNode->addTrafficLight(tlDef);
1058
//tlDef->setSinglePhase();
1059
}
1060
return *toNode->getControllingTLS().begin();
1061
}
1062
1063
void
1064
NIImporter_OpenDrive::setLaneAttributes(const OpenDriveEdge* e, NBEdge::Lane& sumoLane, const OpenDriveLane& odLane, bool saveOrigIDs, const NBTypeCont& tc) {
1065
if (saveOrigIDs) {
1066
sumoLane.setParameter(SUMO_PARAM_ORIGID, e->id + "_" + toString(odLane.id));
1067
}
1068
sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getEdgeTypeSpeed(odLane.type);
1069
sumoLane.permissions = odLane.permission > 0 ? odLane.permission : tc.getEdgeTypePermissions(odLane.type); // TODO: how to get the OD lane specific restrictions?
1070
sumoLane.width = myImportWidths && odLane.width != NBEdge::UNSPECIFIED_WIDTH ? odLane.width : tc.getEdgeTypeWidth(odLane.type);
1071
sumoLane.type = odLane.type;
1072
1073
const double widthResolution = tc.getEdgeTypeWidthResolution(odLane.type);
1074
const double maxWidth = tc.getEdgeTypeMaxWidth(odLane.type);
1075
1076
const bool forbiddenNarrow = (sumoLane.width < myMinWidth
1077
&& (sumoLane.permissions & ~SVC_VULNERABLE) != 0
1078
&& sumoLane.width < tc.getEdgeTypeWidth(odLane.type));
1079
1080
if (sumoLane.width >= 0 && widthResolution > 0) {
1081
sumoLane.width = floor(sumoLane.width / widthResolution + 0.5) * widthResolution;
1082
if (forbiddenNarrow && sumoLane.width >= myMinWidth) {
1083
sumoLane.width -= widthResolution;
1084
if (sumoLane.width <= 0) {
1085
sumoLane.width = MAX2(POSITION_EPS, myMinWidth - POSITION_EPS);
1086
}
1087
} else if (sumoLane.width == 0) {
1088
// round up when close to 0
1089
sumoLane.width = widthResolution;
1090
}
1091
}
1092
if (maxWidth > 0) {
1093
sumoLane.width = MIN2(sumoLane.width, maxWidth);
1094
}
1095
if (forbiddenNarrow) {
1096
// avoid narrow passenger car lanes (especially at sections with varying width)
1097
sumoLane.permissions = SVC_EMERGENCY | SVC_AUTHORITY;
1098
}
1099
}
1100
1101
void
1102
NIImporter_OpenDrive::buildConnectionsToOuter(const Connection& c,
1103
const std::map<std::string, OpenDriveEdge*>& innerEdges,
1104
const std::map<std::string, OpenDriveEdge*>& edges,
1105
const NBTypeCont& tc,
1106
std::vector<Connection>& into, std::set<Connection>& seen) {
1107
1108
OpenDriveEdge* dest = innerEdges.find(c.toEdge)->second;
1109
#ifdef DEBUG_CONNECTIONS
1110
if (DEBUG_COND3(c.fromEdge)) {
1111
std::cout << " buildConnectionsToOuter " << c.getDescription() << "\n";
1112
std::cout << " dest=" << (dest == nullptr ? "NULL" : dest->id) << " seenlist=";
1113
for (std::set<Connection>::const_iterator i = seen.begin(); i != seen.end(); ++i) {
1114
std::cout << " " << (*i).fromEdge << "," << (*i).toEdge << " ";
1115
}
1116
std::cout << "\n";
1117
}
1118
#endif
1119
if (dest == nullptr) {
1120
/// !!! should not, look in all?
1121
return;
1122
}
1123
seen.insert(c);
1124
for (const Connection& destCon : dest->connections) {
1125
auto innerEdgesIt = innerEdges.find(destCon.toEdge);
1126
#ifdef DEBUG_CONNECTIONS
1127
if (DEBUG_COND3(c.fromEdge)) {
1128
std::cout << " toInner=" << (innerEdgesIt != innerEdges.end()) << " destCon " << destCon.getDescription() << "\n";
1129
}
1130
#endif
1131
if (innerEdgesIt != innerEdges.end()) {
1132
std::vector<Connection> t;
1133
if (seen.count(destCon) == 0) {
1134
buildConnectionsToOuter(destCon, innerEdges, edges, tc, t, seen);
1135
for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
1136
// @todo this section is unverified
1137
Connection cn = (*j);
1138
cn.fromEdge = c.fromEdge;
1139
cn.fromLane = c.fromLane;
1140
cn.fromCP = c.fromCP;
1141
cn.all = c.all; // @todo "all" is a hack trying to avoid the "from is zero" problem;
1142
if (myImportInternalShapes) {
1143
cn.shape = innerEdgesIt->second->geom + c.shape;
1144
}
1145
into.push_back(cn);
1146
}
1147
} else {
1148
WRITE_WARNING("Circular connections in junction including roads '" + c.fromEdge + "' and '" + c.toEdge + "', loop size " + toString(seen.size()));
1149
}
1150
} else {
1151
int in = c.toLane;
1152
int out = destCon.fromLane;
1153
if (c.toCP == OPENDRIVE_CP_END) {
1154
// inner edge runs in reverse direction
1155
std::swap(in, out);
1156
}
1157
#ifdef DEBUG_CONNECTIONS
1158
if (DEBUG_COND3(c.fromEdge)) {
1159
std::cout << " laneSectionsConnected dest=" << dest->id << " in=" << in << " out=" << out
1160
<< " connected=" << laneSectionsConnected(dest, in, out) << "\n";
1161
}
1162
#endif
1163
1164
if (laneSectionsConnected(dest, in, out)) {
1165
Connection cn = destCon;
1166
cn.fromEdge = c.fromEdge;
1167
cn.fromLane = c.fromLane;
1168
cn.fromCP = c.fromCP;
1169
cn.all = c.all;
1170
cn.origID = c.toEdge;
1171
cn.origLane = c.toLane;
1172
if (myImportInternalShapes) {
1173
OpenDriveXMLTag lanesDir;
1174
cn.shape = dest->geom;
1175
// determine which lane of dest belongs to this connection
1176
int referenceLane = 0;
1177
int offsetFactor = 1;
1178
if (c.toCP == OPENDRIVE_CP_END) {
1179
offsetFactor = -1;
1180
lanesDir = OPENDRIVE_TAG_LEFT;
1181
for (const auto& destLane : dest->laneSections.front().lanesByDir[lanesDir]) {
1182
if (destLane.successor == c.fromLane) {
1183
referenceLane = destLane.id;
1184
break;
1185
}
1186
}
1187
} else {
1188
lanesDir = OPENDRIVE_TAG_RIGHT;
1189
for (const auto& destLane : dest->laneSections.front().lanesByDir[lanesDir]) {
1190
if (destLane.predecessor == c.fromLane) {
1191
referenceLane = destLane.id;
1192
break;
1193
}
1194
}
1195
}
1196
// compute offsets
1197
//if (cn.fromEdge == "1014000" && dest->id == "3001022") {
1198
// std::cout << "computeOffsets\n";
1199
//}
1200
std::vector<double> offsets(dest->geom.size(), 0);
1201
if (dest->laneOffsets.size() > 0) {
1202
offsets = dest->laneOffsets;
1203
}
1204
#ifdef DEBUG_INTERNALSHAPES
1205
std::string destPred;
1206
#endif
1207
double s = 0;
1208
int iShape = 0;
1209
for (int laneSectionIndex = 0; laneSectionIndex < (int)dest->laneSections.size(); laneSectionIndex++) {
1210
OpenDriveLaneSection& laneSection = dest->laneSections[laneSectionIndex];
1211
const double nextS = laneSectionIndex + 1 < (int)dest->laneSections.size() ? dest->laneSections[laneSectionIndex + 1].s : std::numeric_limits<double>::max();
1212
double sStart = s; // distance offset a the start of the current lane section
1213
double finalS = s; // final distance value after processing this segment
1214
int finalI = iShape;
1215
for (const OpenDriveLane& destLane : laneSection.lanesByDir[lanesDir]) {
1216
// each lane of the current segment repeats the same section of shape points and distance offsets
1217
double sectionS = 0;
1218
int i = iShape; // shape index at the start of the current lane section
1219
s = sStart;
1220
#ifdef DEBUG_INTERNALSHAPES
1221
destPred += " lane=" + toString(destLane.id)
1222
+ " pred=" + toString(destLane.predecessor)
1223
+ " succ=" + toString(destLane.successor)
1224
+ " wStart=" + (destLane.widthData.empty() ? "?" : toString(destLane.widthData.front().computeAt(0)))
1225
+ " wEnd=" + (destLane.widthData.empty() ? "?" : toString(destLane.widthData.front().computeAt(cn.shape.length2D())))
1226
+ " width=" + toString(destLane.width) + "\n";
1227
#endif
1228
if (abs(destLane.id) <= abs(referenceLane) || abs(destLane.id) == abs(c.toLane)) {
1229
const double multiplier = offsetFactor * (destLane.id == referenceLane ? 0.5 : 1);
1230
#ifdef DEBUG_INTERNALSHAPES
1231
destPred += " multiplier=" + toString(multiplier) + "\n";
1232
#endif
1233
int widthDataIndex = 0;
1234
while (s < nextS && i < (int)cn.shape.size()) {
1235
if (i > 0) {
1236
const double dist = cn.shape[i - 1].distanceTo2D(cn.shape[i]);
1237
s += dist;
1238
sectionS += dist;
1239
1240
}
1241
while (widthDataIndex + 1 < (int)destLane.widthData.size()
1242
&& sectionS >= destLane.widthData[widthDataIndex + 1].s) {
1243
widthDataIndex++;
1244
}
1245
double width = tc.getEdgeTypeWidth(destLane.type);
1246
if (destLane.widthData.size() > 0) {
1247
width = destLane.widthData[widthDataIndex].computeAt(sectionS);
1248
} else {
1249
#ifdef DEBUG_INTERNALSHAPES
1250
std::cout << " missing width data at inner edge " << dest->id << " to=" << cn.toEdge << "_" << cn.toLane << " cp=" << cn.toCP << "\n";
1251
#endif
1252
// use first width of the target lane
1253
OpenDriveEdge* const outerToEdge = edges.find(cn.toEdge)->second;
1254
OpenDriveLaneSection& toLaneSection = cn.toCP == OPENDRIVE_CP_END ? outerToEdge->laneSections.front() : outerToEdge->laneSections.back();
1255
const OpenDriveXMLTag laneDir = cn.toLane < 0 ? OPENDRIVE_TAG_RIGHT : OPENDRIVE_TAG_LEFT;
1256
for (const OpenDriveLane& outerToLane : toLaneSection.lanesByDir[laneDir]) {
1257
if (outerToLane.id == cn.toLane && outerToLane.width > 0) {
1258
#ifdef DEBUG_INTERNALSHAPES
1259
std::cout << " using toLane width " << width << "\n";
1260
#endif
1261
break;
1262
}
1263
}
1264
}
1265
offsets[i] += width * multiplier;
1266
//if (cn.fromEdge == "1014000" && dest->id == "3001022") {
1267
// std::cout << " i=" << i << " s=" << s << " lane=" << destLane.id << " rlane=" << referenceLane /*<< " nextS=" << nextS << */ << " lsIndex=" << laneSectionIndex << " wI=" << widthDataIndex << " wSize=" << destLane.widthData.size() << " m=" << multiplier << " o=" << offsets[i] << "\n";
1268
//}
1269
i++;
1270
}
1271
finalS = s;
1272
finalI = i;
1273
} else if (finalS == s) {
1274
// update finalS without changing offsets
1275
while (s < nextS && i < (int)cn.shape.size()) {
1276
if (i > 0) {
1277
const double dist = cn.shape[i - 1].distanceTo2D(cn.shape[i]);
1278
s += dist;
1279
finalS += dist;
1280
1281
}
1282
i++;
1283
}
1284
finalI = i;
1285
1286
}
1287
}
1288
// advance values for the next lane section
1289
iShape = finalI;
1290
s = finalS;
1291
}
1292
try {
1293
cn.shape.move2sideCustom(offsets);
1294
} catch (InvalidArgument&) {
1295
WRITE_WARNING("Could not import internal lane shape from edge '" + c.fromEdge + "' to edge '" + c.toEdge);
1296
cn.shape.clear();
1297
}
1298
#ifdef DEBUG_INTERNALSHAPES
1299
std::cout << "internalShape "
1300
<< c.getDescription()
1301
<< " dest=" << dest->id
1302
<< " refLane=" << referenceLane
1303
<< "\n destPred=" << destPred
1304
<< "\n offsets=" << offsets
1305
<< "\n shape=" << dest->geom
1306
<< "\n shape2=" << cn.shape
1307
<< "\n";
1308
#endif
1309
if (c.toCP == OPENDRIVE_CP_END) {
1310
cn.shape = cn.shape.reverse();
1311
}
1312
}
1313
#ifdef DEBUG_CONNECTIONS
1314
if (DEBUG_COND3(c.fromEdge)) {
1315
std::cout << " added connection\n";
1316
}
1317
#endif
1318
into.push_back(cn);
1319
}
1320
}
1321
}
1322
}
1323
1324
1325
bool
1326
NIImporter_OpenDrive::laneSectionsConnected(OpenDriveEdge* edge, int in, int out) {
1327
if (edge->laneSections.size() == 1) {
1328
return in == out;
1329
} else {
1330
// there could be spacing lanes (type 'none') that lead to a shift in lane index
1331
for (auto it = edge->laneSections.begin(); it + 1 < edge->laneSections.end(); it++) {
1332
OpenDriveLaneSection& laneSection = *it;
1333
if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
1334
for (OpenDriveLane& lane : laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second) {
1335
if (lane.id == in) {
1336
in = lane.successor;
1337
break;
1338
}
1339
}
1340
}
1341
if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
1342
for (OpenDriveLane& lane : laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second) {
1343
if (lane.id == in) {
1344
in = lane.successor;
1345
break;
1346
}
1347
}
1348
}
1349
}
1350
return in == out;
1351
}
1352
}
1353
1354
1355
void
1356
NIImporter_OpenDrive::setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges) {
1357
for (std::vector<OpenDriveLink>::iterator i = e.links.begin(); i != e.links.end(); ++i) {
1358
OpenDriveLink& l = *i;
1359
if (l.elementType != OPENDRIVE_ET_ROAD) {
1360
// we assume that links to nodes are later given as connections to edges
1361
continue;
1362
}
1363
// get the right direction of the connected edge
1364
std::string connectedEdge = l.elementID;
1365
std::string edgeID = e.id;
1366
1367
OpenDriveLaneSection& laneSection = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e.laneSections.back() : e.laneSections[0];
1368
const std::map<int, int>& laneMap = laneSection.laneMap;
1369
#ifdef DEBUG_CONNECTIONS
1370
if (DEBUG_COND(&e)) {
1371
std::cout << "edge=" << e.id << " eType=" << l.elementType << " lType=" << l.linkType << " connectedEdge=" << connectedEdge << " laneSection=" << laneSection.s << " map:\n";
1372
std::cout << joinToString(laneMap, "\n", ":") << "\n";
1373
}
1374
#endif
1375
if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
1376
const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
1377
for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
1378
if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
1379
continue;
1380
}
1381
Connection c; // @todo: give Connection a new name and a constructor
1382
c.fromEdge = e.id;
1383
c.fromLane = (*j).id;
1384
c.fromCP = OPENDRIVE_CP_END;
1385
c.toLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
1386
c.toEdge = connectedEdge;
1387
c.toCP = l.contactPoint;
1388
c.all = false;
1389
if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
1390
std::swap(c.fromEdge, c.toEdge);
1391
std::swap(c.fromLane, c.toLane);
1392
c.fromCP = c.toCP;
1393
c.toCP = OPENDRIVE_CP_START;
1394
}
1395
if (edges.find(c.fromEdge) == edges.end()) {
1396
WRITE_ERRORF(TL("While setting connections: incoming road '%' is not known."), c.fromEdge);
1397
} else {
1398
OpenDriveEdge* src = edges.find(c.fromEdge)->second;
1399
src->connections.insert(c);
1400
#ifdef DEBUG_CONNECTIONS
1401
if (DEBUG_COND(src)) {
1402
std::cout << "insertConRight from=" << src->id << "_" << c.fromLane << " to=" << c.toEdge << "_" << c.toLane << "\n";
1403
}
1404
#endif
1405
}
1406
}
1407
}
1408
if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
1409
const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
1410
for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
1411
if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
1412
continue;
1413
}
1414
Connection c;
1415
c.toEdge = e.id;
1416
c.toLane = (*j).id;
1417
c.toCP = OPENDRIVE_CP_END;
1418
c.fromLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
1419
c.fromEdge = connectedEdge;
1420
c.fromCP = l.contactPoint;
1421
c.all = false;
1422
if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
1423
std::swap(c.fromEdge, c.toEdge);
1424
std::swap(c.fromLane, c.toLane);
1425
c.fromCP = c.toCP;
1426
c.toCP = OPENDRIVE_CP_START;
1427
}
1428
if (edges.find(c.fromEdge) == edges.end()) {
1429
WRITE_ERRORF(TL("While setting connections: incoming road '%' is not known."), c.fromEdge);
1430
} else {
1431
OpenDriveEdge* src = edges.find(c.fromEdge)->second;
1432
src->connections.insert(c);
1433
#ifdef DEBUG_CONNECTIONS
1434
if (DEBUG_COND(src)) {
1435
std::cout << "insertConLeft from=" << src->id << "_" << c.fromLane << " to=" << c.toEdge << "_" << c.toLane << "\n";
1436
}
1437
#endif
1438
}
1439
}
1440
}
1441
}
1442
}
1443
1444
1445
std::string
1446
NIImporter_OpenDrive::reversedEdgeID(const std::string& edgeID) {
1447
return edgeID[0] == '-' ? edgeID.substr(1) : "-" + edgeID;
1448
}
1449
1450
1451
NBNode*
1452
NIImporter_OpenDrive::getOrBuildNode(const std::string& id, const Position& pos,
1453
NBNodeCont& nc) {
1454
if (nc.retrieve(id) == nullptr) {
1455
// not yet built; build now
1456
if (!nc.insert(id, pos)) {
1457
// !!! clean up
1458
throw ProcessError(TLF("Could not add node '%'.", id));
1459
}
1460
}
1461
return nc.retrieve(id);
1462
}
1463
1464
1465
void
1466
NIImporter_OpenDrive::setNodeSecure(NBNodeCont& nc, OpenDriveEdge& e,
1467
const std::string& nodeID, NIImporter_OpenDrive::LinkType lt, std::vector<NodeSet>& joinedNodeIDs) {
1468
NBNode* n = nc.retrieve(nodeID);
1469
if (n == nullptr) {
1470
throw ProcessError(TLF("Could not find node '%'.", nodeID));
1471
}
1472
NBNode* toJoin = nullptr;
1473
if (lt == OPENDRIVE_LT_SUCCESSOR) {
1474
if (e.to != nullptr && e.to != n) {
1475
toJoin = e.to;
1476
}
1477
e.to = n;
1478
} else {
1479
if (e.from != nullptr && e.from != n) {
1480
toJoin = e.from;
1481
}
1482
e.from = n;
1483
}
1484
if (toJoin != nullptr) {
1485
// join nodes
1486
NodeSet* set1 = nullptr;
1487
NodeSet* set2 = nullptr;
1488
for (NodeSet& joined : joinedNodeIDs) {
1489
if (joined.count(toJoin) != 0) {
1490
set1 = &joined;
1491
}
1492
if (joined.count(n) != 0) {
1493
set2 = &joined;
1494
}
1495
}
1496
if (set1 == nullptr && set2 == nullptr) {
1497
joinedNodeIDs.push_back(NodeSet());
1498
joinedNodeIDs.back().insert(n);
1499
joinedNodeIDs.back().insert(toJoin);
1500
} else if (set1 == nullptr && set2 != nullptr) {
1501
set2->insert(toJoin);
1502
} else if (set1 != nullptr && set2 == nullptr) {
1503
set1->insert(n);
1504
} else {
1505
set1->insert(set2->begin(), set2->end());
1506
joinedNodeIDs.erase(std::find(joinedNodeIDs.begin(), joinedNodeIDs.end(), *set2));
1507
}
1508
}
1509
}
1510
1511
bool
1512
NIImporter_OpenDrive::hasNonLinearElevation(const OpenDriveEdge& e) {
1513
if (e.elevations.size() > 1) {
1514
return true;
1515
}
1516
for (const OpenDriveElevation& el : e.elevations) {
1517
if (el.c != 0 || el.d != 0) {
1518
return true;
1519
}
1520
}
1521
return false;
1522
}
1523
1524
void
1525
NIImporter_OpenDrive::computeShapes(std::map<std::string, OpenDriveEdge*>& edges) {
1526
OptionsCont& oc = OptionsCont::getOptions();
1527
const double res = oc.getFloat("opendrive.curve-resolution");
1528
for (const auto& i : edges) {
1529
OpenDriveEdge& e = *i.second;
1530
GeometryType prevType = OPENDRIVE_GT_UNKNOWN;
1531
const double lineRes = hasNonLinearElevation(e) ? res : -1;
1532
Position last;
1533
int index = 0;
1534
for (const OpenDriveGeometry& g : e.geometries) {
1535
PositionVector geom;
1536
switch (g.type) {
1537
case OPENDRIVE_GT_UNKNOWN:
1538
break;
1539
case OPENDRIVE_GT_LINE:
1540
geom = geomFromLine(e, g, lineRes);
1541
break;
1542
case OPENDRIVE_GT_SPIRAL:
1543
geom = geomFromSpiral(e, g, res);
1544
break;
1545
case OPENDRIVE_GT_ARC:
1546
geom = geomFromArc(e, g, res);
1547
break;
1548
case OPENDRIVE_GT_POLY3:
1549
geom = geomFromPoly(e, g, res);
1550
break;
1551
case OPENDRIVE_GT_PARAMPOLY3:
1552
geom = geomFromParamPoly(e, g, res);
1553
break;
1554
default:
1555
break;
1556
}
1557
if (e.geom.size() > 0 && prevType == OPENDRIVE_GT_LINE) {
1558
// remove redundant end point of the previous geometry segment
1559
// (the start point of the current segment should have the same value)
1560
// this avoids geometry errors due to imprecision
1561
if (!e.geom.back().almostSame(geom.front())) {
1562
WRITE_WARNINGF(TL("Mismatched geometry for edge '%' between geometry segments % and %."), e.id, index - 1, index);
1563
}
1564
e.geom.pop_back();
1565
}
1566
//std::cout << " adding geometry to road=" << e.id << " old=" << e.geom << " new=" << geom << "\n";
1567
for (PositionVector::iterator k = geom.begin(); k != geom.end(); ++k) {
1568
last = *k;
1569
e.geom.push_back_noDoublePos(*k);
1570
}
1571
prevType = g.type;
1572
index++;
1573
}
1574
if (e.geom.size() == 1 && e.geom.front() != last) {
1575
// avoid length-1 geometry due to almostSame check
1576
e.geom.push_back(last);
1577
}
1578
#ifdef DEBUG_SHAPE
1579
if (DEBUG_COND3(e.id)) {
1580
std::cout << e.id << " initialGeom=" << e.geom << "\n";
1581
}
1582
#endif
1583
if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
1584
// simplify geometry for both directions consistently but ensure
1585
// that start and end angles are preserved
1586
if (e.geom.size() > 4) {
1587
e.geom.removeDoublePoints(oc.getFloat("geometry.min-dist"), true, 1, 1, true);
1588
}
1589
}
1590
#ifdef DEBUG_SHAPE
1591
if (DEBUG_COND3(e.id)) {
1592
std::cout << e.id << " reducedGeom=" << e.geom << "\n";
1593
}
1594
#endif
1595
if (!NBNetBuilder::transformCoordinates(e.geom)) {
1596
WRITE_ERRORF(TL("Unable to project coordinates for edge '%'."), e.id);
1597
}
1598
// add z-data
1599
int k = 0;
1600
double pos = 0;
1601
//std::cout << " edge=" << e.id << " geom.size=" << e.geom.size() << " geom.len=" << e.geom.length2D() << " ele.size=" << e.elevations.size() << "\n";
1602
if (!oc.getBool("flatten")) {
1603
for (std::vector<OpenDriveElevation>::iterator j = e.elevations.begin(); j != e.elevations.end(); ++j) {
1604
const OpenDriveElevation& el = *j;
1605
const double sNext = (j + 1) == e.elevations.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1606
while (k < (int)e.geom.size() && pos < sNext) {
1607
const double z = el.computeAt(pos);
1608
//std::cout << " edge=" << e.id << " k=" << k << " sNext=" << sNext << " pos=" << pos << " z=" << z << " el.s=" << el.s << " el.a=" << el.a << " el.b=" << el.b << " el.c=" << el.c << " el.d=" << el.d << "\n";
1609
e.geom[k].add(0, 0, z);
1610
k++;
1611
if (k < (int)e.geom.size()) {
1612
// XXX pos understimates the actual position since the
1613
// actual geometry between k-1 and k could be curved
1614
pos += e.geom[k - 1].distanceTo2D(e.geom[k]);
1615
}
1616
}
1617
}
1618
}
1619
e.geom = e.geom.simplified2(false);
1620
// add laneoffset
1621
if (e.offsets.size() > 0) {
1622
e.laneOffsets = discretizeOffsets(e.geom, e.offsets, e.id);
1623
}
1624
//std::cout << " loaded geometry " << e.id << "=" << e.geom << "\n";
1625
}
1626
}
1627
1628
1629
std::vector<double>
1630
NIImporter_OpenDrive::discretizeOffsets(PositionVector& geom, const std::vector<OpenDriveLaneOffset>& offsets, const std::string& id) {
1631
UNUSED_PARAMETER(id);
1632
std::vector<double> laneOffsets;
1633
// make sure there are intermediate points for each offset-section
1634
for (const OpenDriveLaneOffset& el : offsets) {
1635
// check wether we need to insert a new point at dist
1636
Position pS = geom.positionAtOffset2D(el.s);
1637
int iS = geom.indexOfClosest(pS);
1638
// prevent close spacing to reduce impact of rounding errors in z-axis
1639
if (pS.distanceTo2D(geom[iS]) > POSITION_EPS) {
1640
geom.insertAtClosest(pS, false);
1641
//std::cout << " edge=" << e.id << " inserting pos=" << pS << " s=" << el.s << " iS=" << iS << " dist=" << pS.distanceTo2D(geom[iS]) << "\n";
1642
}
1643
}
1644
// XXX add further points for sections with non-constant offset
1645
// shift each point orthogonally by the specified offset
1646
int kk = 0;
1647
double ppos = 0;
1648
for (auto j = offsets.begin(); j != offsets.end(); ++j) {
1649
const OpenDriveLaneOffset& el = *j;
1650
const double sNext = (j + 1) == offsets.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1651
while (kk < (int)geom.size() && ppos < sNext) {
1652
const double offset = el.computeAt(ppos);
1653
laneOffsets.push_back(fabs(offset) > POSITION_EPS ? -offset : 0);
1654
kk++;
1655
if (kk < (int)geom.size()) {
1656
// XXX pos understimates the actual position since the
1657
// actual geometry between k-1 and k could be curved
1658
ppos += geom[kk - 1].distanceTo2D(geom[kk]);
1659
}
1660
}
1661
}
1662
return laneOffsets;
1663
}
1664
1665
1666
void
1667
NIImporter_OpenDrive::addOffsets(bool left, PositionVector& geom, const std::vector<OpenDriveWidth>& offsets, const std::string& id, std::vector<double>& result) {
1668
UNUSED_PARAMETER(id);
1669
// make sure there are intermediate points for each offset-section
1670
for (const OpenDriveLaneOffset& el : offsets) {
1671
// check wether we need to insert a new point at dist
1672
Position pS = geom.positionAtOffset2D(el.s);
1673
int iS = geom.indexOfClosest(pS);
1674
// prevent close spacing to reduce impact of rounding errors in z-axis
1675
if (pS.distanceTo2D(geom[iS]) > POSITION_EPS) {
1676
//std::cout << " edge=" << id << " inserting pos=" << pS << " s=" << el.s << " iS=" << iS << " dist=" << pS.distanceTo2D(geom[iS]) << "\n";
1677
int at = geom.insertAtClosest(pS, false);
1678
double interpolatedOffset = 0;
1679
if (at == 0) {
1680
interpolatedOffset = result.front();
1681
} else if (at == (int)geom.size() - 1) {
1682
interpolatedOffset = result.back();
1683
} else {
1684
interpolatedOffset = (result[at - 1] + result[at]) / 2;
1685
}
1686
result.insert(result.begin() + at, interpolatedOffset);
1687
}
1688
}
1689
// shift each point orthogonally by the specified offset
1690
int kk = 0;
1691
double ppos = 0;
1692
const int sign = left ? -1 : 1;
1693
for (auto j = offsets.begin(); j != offsets.end(); ++j) {
1694
const OpenDriveWidth& el = *j;
1695
const double sNext = (j + 1) == offsets.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1696
while (kk < (int)geom.size() && ppos < sNext) {
1697
const double offset = el.computeAt(ppos);
1698
result[kk] += fabs(offset) > POSITION_EPS ? sign * offset : 0;
1699
kk++;
1700
if (kk < (int)geom.size()) {
1701
// XXX pos understimates the actual position since the
1702
// actual geometry between k-1 and k could be curved
1703
ppos += geom[kk - 1].distanceTo2D(geom[kk]);
1704
}
1705
}
1706
}
1707
}
1708
1709
1710
void
1711
NIImporter_OpenDrive::revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges) {
1712
for (const auto& i : edges) {
1713
OpenDriveEdge& e = *i.second;
1714
#ifdef DEBUG_VARIABLE_SPEED
1715
if (DEBUG_COND(&e)) {
1716
gDebugFlag1 = true;
1717
std::cout << "revisitLaneSections e=" << e.id << "\n";
1718
}
1719
#endif
1720
// split by speed limits or by access restrictions
1721
std::vector<OpenDriveLaneSection> newSections;
1722
for (OpenDriveLaneSection& section : e.laneSections) {
1723
std::vector<OpenDriveLaneSection> splitSections;
1724
const bool splitByAttrChange = section.buildAttributeChanges(tc, splitSections);
1725
if (!splitByAttrChange) {
1726
newSections.push_back(section);
1727
} else {
1728
std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
1729
}
1730
}
1731
1732
e.laneSections = newSections;
1733
double lastS = -1.;
1734
// check whether the lane sections are in the right order
1735
bool sorted = true;
1736
for (const OpenDriveLaneSection& section : e.laneSections) {
1737
if (section.s <= lastS) {
1738
sorted = false;
1739
break;
1740
}
1741
lastS = section.s;
1742
}
1743
if (!sorted) {
1744
WRITE_WARNINGF(TL("The sections of edge '%' are not sorted properly."), e.id);
1745
sort(e.laneSections.begin(), e.laneSections.end(), sections_by_s_sorter());
1746
}
1747
// check whether duplicate s-values occur
1748
// but keep all lane sections for connecting roads because they are
1749
// needed to establish connectivity (laneSectionsConnected)
1750
// TODO recheck whether removing short sections is a good idea at all: once we parse linkage info, it will be lost.
1751
if (e.laneSections.size() > 1 && !e.isInner) {
1752
for (std::vector<OpenDriveLaneSection>::iterator j = e.laneSections.begin(); j != e.laneSections.end() - 1;) {
1753
if ((j + 1)->s - j->s < POSITION_EPS) {
1754
WRITE_WARNINGF(TL("Almost duplicate s-value '%' for lane sections occurred at edge '%'; first entry was removed."), toString(j->s), e.id);
1755
j = e.laneSections.erase(j);
1756
} else {
1757
++j;
1758
}
1759
}
1760
}
1761
#ifdef DEBUG_VARIABLE_SPEED
1762
gDebugFlag1 = false;
1763
#endif
1764
}
1765
}
1766
1767
1768
PositionVector
1769
NIImporter_OpenDrive::geomFromLine(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution) {
1770
UNUSED_PARAMETER(e);
1771
PositionVector ret;
1772
Position start(g.x, g.y);
1773
Position end = calculateStraightEndPoint(g.hdg, g.length, start);
1774
if (resolution > 0 && g.length > 0) {
1775
const int numPoints = (int)ceil(g.length / resolution) + 1;
1776
double dx = (end.x() - start.x()) / (numPoints - 1);
1777
double dy = (end.y() - start.y()) / (numPoints - 1);
1778
for (int i = 0; i < numPoints; i++) {
1779
ret.push_back(Position(g.x + i * dx, g.y + i * dy));
1780
}
1781
} else {
1782
ret.push_back(start);
1783
ret.push_back(end);
1784
}
1785
return ret;
1786
}
1787
1788
1789
PositionVector
1790
NIImporter_OpenDrive::geomFromSpiral(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution) {
1791
UNUSED_PARAMETER(e);
1792
PositionVector ret;
1793
double curveStart = g.params[0];
1794
double curveEnd = g.params[1];
1795
try {
1796
double cDot = (curveEnd - curveStart) / g.length;
1797
if (cDot == 0 || g.length == 0) {
1798
WRITE_WARNINGF(TL("Could not compute spiral geometry for edge '%' (cDot=% length=%)."), e.id, toString(cDot), toString(g.length));
1799
ret.push_back(Position(g.x, g.y));
1800
return ret;
1801
}
1802
double sStart = curveStart / cDot;
1803
double sEnd = curveEnd / cDot;
1804
double x = 0;
1805
double y = 0;
1806
double t = 0;
1807
double tStart = 0;
1808
double s;
1809
odrSpiral(sStart, cDot, &x, &y, &tStart);
1810
for (s = sStart; s <= sEnd; s += resolution) {
1811
odrSpiral(s, cDot, &x, &y, &t);
1812
ret.push_back(Position(x, y));
1813
}
1814
if (s != sEnd /*&& ret.size() == 1*/) {
1815
odrSpiral(sEnd, cDot, &x, &y, &t);
1816
ret.push_back(Position(x, y));
1817
}
1818
//if (s != sEnd && ret.size() > 2) {
1819
// ret.pop_back();
1820
//}
1821
assert(ret.size() >= 2);
1822
assert(ret[0] != ret[1]);
1823
// shift start to coordinate origin
1824
PositionVector ret1 = ret;
1825
ret.add(ret.front() * -1);
1826
// rotate
1827
PositionVector ret2 = ret;
1828
ret.rotate2D(g.hdg - tStart);
1829
#ifdef DEBUG_SPIRAL
1830
std::cout
1831
<< std::setprecision(4)
1832
<< "edge=" << e.id << " s=" << g.s
1833
<< " cStart=" << curveStart
1834
<< " cEnd=" << curveEnd
1835
<< " cDot=" << cDot
1836
<< " sStart=" << sStart
1837
<< " sEnd=" << sEnd
1838
<< " g.hdg=" << GeomHelper::naviDegree(g.hdg)
1839
<< " tStart=" << GeomHelper::naviDegree(tStart)
1840
<< "\n beforeShift=" << ret1
1841
<< "\n beforeRot=" << ret2
1842
<< "\n";
1843
#endif
1844
// shift to geometry start
1845
ret.add(g.x, g.y, 0);
1846
} catch (const std::runtime_error& error) {
1847
WRITE_WARNINGF(TL("Could not compute spiral geometry for edge '%' (%)."), e.id, error.what());
1848
ret.push_back(Position(g.x, g.y));
1849
}
1850
return ret.getSubpart2D(0, g.length);
1851
}
1852
1853
1854
PositionVector
1855
NIImporter_OpenDrive::geomFromArc(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution) {
1856
UNUSED_PARAMETER(e);
1857
PositionVector ret;
1858
double centerX = g.x;
1859
double centerY = g.y;
1860
// left: positive value
1861
double curvature = g.params[0];
1862
double radius = 1. / curvature;
1863
// center point
1864
calculateCurveCenter(&centerX, &centerY, radius, g.hdg);
1865
double endX = g.x;
1866
double endY = g.y;
1867
double startX = g.x;
1868
double startY = g.y;
1869
double geo_posS = g.s;
1870
double geo_posE = g.s;
1871
bool end = false;
1872
do {
1873
geo_posE += resolution;
1874
if (geo_posE - g.s > g.length) {
1875
geo_posE = g.s + g.length;
1876
}
1877
if (geo_posE - g.s > g.length) {
1878
geo_posE = g.s + g.length;
1879
}
1880
calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
1881
ret.push_back(Position(startX, startY));
1882
1883
startX = endX;
1884
startY = endY;
1885
geo_posS = geo_posE;
1886
1887
if (geo_posE - (g.s + g.length) < 0.001 && geo_posE - (g.s + g.length) > -0.001) {
1888
end = true;
1889
}
1890
} while (!end);
1891
ret.push_back(Position(startX, startY));
1892
return ret.getSubpart2D(0, g.length);
1893
}
1894
1895
1896
PositionVector
1897
NIImporter_OpenDrive::geomFromPoly(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution) {
1898
UNUSED_PARAMETER(e);
1899
const double s = sin(g.hdg);
1900
const double c = cos(g.hdg);
1901
PositionVector ret;
1902
for (double off = 0; off < g.length + 2.; off += resolution) {
1903
double x = off;
1904
double y = g.params[0] + g.params[1] * off + g.params[2] * pow(off, 2.) + g.params[3] * pow(off, 3.);
1905
double xnew = x * c - y * s;
1906
double ynew = x * s + y * c;
1907
ret.push_back(Position(g.x + xnew, g.y + ynew));
1908
}
1909
return ret.getSubpart2D(0, g.length);
1910
}
1911
1912
1913
PositionVector
1914
NIImporter_OpenDrive::geomFromParamPoly(const OpenDriveEdge& e, const OpenDriveGeometry& g, double resolution) {
1915
UNUSED_PARAMETER(e);
1916
const double s = sin(g.hdg);
1917
const double c = cos(g.hdg);
1918
const double pMax = g.params[8] <= 0 ? g.length : g.params[8];
1919
const double pStep = pMax / ceil(g.length / resolution);
1920
PositionVector ret;
1921
for (double p = 0; p <= pMax + pStep; p += pStep) {
1922
double x = g.params[0] + g.params[1] * p + g.params[2] * pow(p, 2.) + g.params[3] * pow(p, 3.);
1923
double y = g.params[4] + g.params[5] * p + g.params[6] * pow(p, 2.) + g.params[7] * pow(p, 3.);
1924
double xnew = x * c - y * s;
1925
double ynew = x * s + y * c;
1926
ret.push_back(Position(g.x + xnew, g.y + ynew));
1927
}
1928
return ret.getSubpart2D(0, g.length);
1929
}
1930
1931
1932
Position
1933
NIImporter_OpenDrive::calculateStraightEndPoint(double hdg, double length, const Position& start) {
1934
double normx = 1.0f;
1935
double normy = 0.0f;
1936
double x2 = normx * cos(hdg) - normy * sin(hdg);
1937
double y2 = normx * sin(hdg) + normy * cos(hdg);
1938
normx = x2 * length;
1939
normy = y2 * length;
1940
return Position(start.x() + normx, start.y() + normy);
1941
}
1942
1943
1944
void
1945
NIImporter_OpenDrive::calculateCurveCenter(double* ad_x, double* ad_y, double ad_radius, double ad_hdg) {
1946
double normX = 1.0;
1947
double normY = 0.0;
1948
double tmpX;
1949
double turn;
1950
if (ad_radius > 0) {
1951
turn = -1.0;
1952
} else {
1953
turn = 1.0;
1954
}
1955
1956
tmpX = normX;
1957
normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
1958
normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
1959
1960
tmpX = normX;
1961
normX = turn * normY;
1962
normY = -turn * tmpX;
1963
1964
normX = fabs(ad_radius) * normX;
1965
normY = fabs(ad_radius) * normY;
1966
1967
*ad_x += normX;
1968
*ad_y += normY;
1969
}
1970
1971
1972
void
1973
NIImporter_OpenDrive::calcPointOnCurve(double* ad_x, double* ad_y, double ad_centerX, double ad_centerY,
1974
double ad_r, double ad_length) {
1975
double rotAngle = ad_length / fabs(ad_r);
1976
double vx = *ad_x - ad_centerX;
1977
double vy = *ad_y - ad_centerY;
1978
double tmpx;
1979
1980
double turn;
1981
if (ad_r > 0) {
1982
turn = -1; //left
1983
} else {
1984
turn = 1; //right
1985
}
1986
tmpx = vx;
1987
vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
1988
vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
1989
*ad_x = vx + ad_centerX;
1990
*ad_y = vy + ad_centerY;
1991
}
1992
1993
1994
// ---------------------------------------------------------------------------
1995
// section
1996
// ---------------------------------------------------------------------------
1997
NIImporter_OpenDrive::OpenDriveLaneSection::OpenDriveLaneSection(double sArg) : s(sArg), sOrig(sArg) {
1998
lanesByDir[OPENDRIVE_TAG_LEFT] = std::vector<OpenDriveLane>();
1999
lanesByDir[OPENDRIVE_TAG_RIGHT] = std::vector<OpenDriveLane>();
2000
lanesByDir[OPENDRIVE_TAG_CENTER] = std::vector<OpenDriveLane>();
2001
}
2002
2003
2004
void
2005
NIImporter_OpenDrive::OpenDriveLaneSection::buildLaneMapping(const NBTypeCont& tc) {
2006
discardedInnerWidthRight = 0;
2007
int sumoLane = 0;
2008
bool singleType = true;
2009
std::vector<std::string> types;
2010
const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
2011
for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
2012
if (myImportAllTypes || (tc.knows((*i).type) && !tc.getEdgeTypeShallBeDiscarded((*i).type))) {
2013
discardedInnerWidthRight = 0;
2014
laneMap[(*i).id] = sumoLane++;
2015
types.push_back((*i).type);
2016
if (types.front() != types.back()) {
2017
singleType = false;
2018
}
2019
} else {
2020
discardedInnerWidthRight += (*i).width;
2021
}
2022
}
2023
discardedInnerWidthLeft = 0;
2024
rightLaneNumber = sumoLane;
2025
rightType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
2026
sumoLane = 0;
2027
singleType = true;
2028
types.clear();
2029
const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
2030
for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
2031
if (myImportAllTypes || (tc.knows((*i).type) && !tc.getEdgeTypeShallBeDiscarded((*i).type))) {
2032
discardedInnerWidthLeft = 0;
2033
laneMap[(*i).id] = sumoLane++;
2034
types.push_back((*i).type);
2035
if (types.front() != types.back()) {
2036
singleType = false;
2037
}
2038
} else {
2039
discardedInnerWidthLeft += (*i).width;
2040
}
2041
}
2042
leftLaneNumber = sumoLane;
2043
leftType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
2044
}
2045
2046
2047
std::map<int, int>
2048
NIImporter_OpenDrive::OpenDriveLaneSection::getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection& prev) {
2049
std::map<int, int> ret;
2050
const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
2051
for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
2052
std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
2053
if (toP == laneMap.end()) {
2054
// the current lane is not available in SUMO
2055
continue;
2056
}
2057
int to = (*toP).second;
2058
int from = UNSET_CONNECTION;
2059
if ((*i).predecessor != UNSET_CONNECTION) {
2060
from = (*i).predecessor;
2061
}
2062
if (from != UNSET_CONNECTION) {
2063
std::map<int, int>::const_iterator fromP = prev.laneMap.find(from);
2064
if (fromP != prev.laneMap.end()) {
2065
from = (*fromP).second;
2066
} else {
2067
from = UNSET_CONNECTION;
2068
}
2069
}
2070
if (from != UNSET_CONNECTION && to != UNSET_CONNECTION) {
2071
if (ret.find(from) != ret.end()) {
2072
// WRITE_WARNING(TL("double connection"));
2073
}
2074
if (dir == OPENDRIVE_TAG_LEFT) {
2075
std::swap(from, to);
2076
}
2077
ret[from] = to;
2078
} else {
2079
// WRITE_WARNING(TL("missing connection"));
2080
}
2081
}
2082
return ret;
2083
}
2084
2085
2086
NIImporter_OpenDrive::OpenDriveLaneSection
2087
NIImporter_OpenDrive::OpenDriveLaneSection::buildLaneSection(const NBTypeCont& tc, double startPos) {
2088
OpenDriveLaneSection ret(*this);
2089
ret.s += startPos;
2090
for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_RIGHT].size(); ++k) {
2091
OpenDriveLane& l = ret.lanesByDir[OPENDRIVE_TAG_RIGHT][k];
2092
l.speed = 0;
2093
l.permission = 0;
2094
std::vector<std::pair<double, LaneAttributeChange> >::const_iterator it = std::find_if(l.attributeChanges.begin(), l.attributeChanges.end(), same_position_finder(startPos));
2095
if (it != l.attributeChanges.end()) {
2096
l.speed = (*it).second.speed;
2097
l.permission = l.computePermission(tc, (*it).second.allowed, (*it).second.denied);
2098
}
2099
}
2100
for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_LEFT].size(); ++k) {
2101
OpenDriveLane& l = ret.lanesByDir[OPENDRIVE_TAG_LEFT][k];
2102
l.speed = 0;
2103
l.permission = 0;
2104
std::vector<std::pair<double, LaneAttributeChange> >::const_iterator it = std::find_if(l.attributeChanges.begin(), l.attributeChanges.end(), same_position_finder(startPos));
2105
if (it != l.attributeChanges.end()) {
2106
l.speed = (*it).second.speed;
2107
l.permission = l.computePermission(tc, (*it).second.allowed, (*it).second.denied);
2108
}
2109
}
2110
return ret;
2111
}
2112
2113
2114
SVCPermissions
2115
NIImporter_OpenDrive::OpenDriveLane::computePermission(const NBTypeCont& tc, const std::vector<std::string>& allowed,
2116
const std::vector<std::string>& denied) const {
2117
SVCPermissions perms = tc.getEdgeTypePermissions(type);
2118
if (allowed.size() > 0 && denied.size() > 0) {
2119
WRITE_WARNING(TL("Will discard access settings as both denied and allowed classes have been specified."));
2120
} else if (allowed.size() > 0) {
2121
perms = SVC_IGNORING;
2122
for (const std::string& allow : allowed) {
2123
if (allow == "simulator") {
2124
perms = SVC_IGNORING;
2125
break;
2126
} else if (allow == "autonomousTraffic" || allow == "autonomous traffic" || allow == "throughTraffic") {
2127
perms = tc.getEdgeTypePermissions(type);
2128
break;
2129
} else if (allow == "pedestrian") {
2130
perms |= SVC_PEDESTRIAN;
2131
} else if (allow == "passengerCar") {
2132
perms |= SVC_PASSENGER;
2133
} else if (allow == "bus") {
2134
perms |= SVC_BUS;
2135
} else if (allow == "delivery") {
2136
perms |= SVC_DELIVERY;
2137
} else if (allow == "emergency") {
2138
perms |= SVC_EMERGENCY;
2139
} else if (allow == "taxi") {
2140
perms |= SVC_TAXI;
2141
} else if (allow == "bicycle") {
2142
perms |= SVC_BICYCLE;
2143
} else if (allow == "motorcycle") {
2144
perms |= SVC_MOTORCYCLE;
2145
} else if (allow == "truck" || allow == "trucks") {
2146
perms |= SVC_TRUCK;
2147
perms |= SVC_TRAILER;
2148
}
2149
}
2150
} else if (denied.size() > 0) {
2151
for (const std::string& deny : denied) {
2152
if (deny == "none") {
2153
perms = tc.getEdgeTypePermissions(type);
2154
break;
2155
} else if (deny == "autonomousTraffic" || deny == "autonomous traffic" || deny == "throughTraffic") {
2156
perms = SVC_IGNORING;
2157
break;
2158
} else if (deny == "pedestrian") {
2159
perms &= ~SVC_PEDESTRIAN;
2160
} else if (deny == "passengerCar") {
2161
perms &= ~SVC_PASSENGER;
2162
} else if (deny == "bus") {
2163
perms &= ~SVC_BUS;
2164
} else if (deny == "delivery") {
2165
perms &= ~SVC_DELIVERY;
2166
} else if (deny == "emergency") {
2167
perms &= ~SVC_EMERGENCY;
2168
} else if (deny == "taxi") {
2169
perms &= ~SVC_TAXI;
2170
} else if (deny == "bicycle") {
2171
perms &= ~SVC_BICYCLE;
2172
} else if (deny == "motorcycle") {
2173
perms &= ~SVC_MOTORCYCLE;
2174
} else if (deny == "truck" || deny == "trucks") {
2175
perms &= ~SVC_TRUCK;
2176
perms &= ~SVC_TRAILER;
2177
}
2178
}
2179
}
2180
return perms;
2181
}
2182
2183
2184
bool
2185
NIImporter_OpenDrive::OpenDriveLaneSection::buildAttributeChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections) {
2186
std::set<double> attributeChangePositions;
2187
// collect speed change and access restriction positions and apply initial values to the begin
2188
for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_RIGHT].begin(); k != lanesByDir[OPENDRIVE_TAG_RIGHT].end(); ++k) {
2189
for (std::vector<std::pair<double, LaneAttributeChange> >::const_iterator l = (*k).attributeChanges.begin(); l != (*k).attributeChanges.end(); ++l) {
2190
attributeChangePositions.insert((*l).first);
2191
if ((*l).first == 0) {
2192
(*k).speed = (*l).second.speed;
2193
(*k).permission = (*k).computePermission(tc, (*l).second.allowed, (*l).second.denied);
2194
}
2195
}
2196
}
2197
for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_LEFT].begin(); k != lanesByDir[OPENDRIVE_TAG_LEFT].end(); ++k) {
2198
for (std::vector<std::pair<double, LaneAttributeChange> >::const_iterator l = (*k).attributeChanges.begin(); l != (*k).attributeChanges.end(); ++l) {
2199
attributeChangePositions.insert((*l).first);
2200
if ((*l).first == 0) {
2201
(*k).speed = (*l).second.speed;
2202
(*k).permission = (*k).computePermission(tc, (*l).second.allowed, (*l).second.denied);
2203
}
2204
}
2205
}
2206
2207
// do nothing if there is none
2208
if (attributeChangePositions.size() == 0) {
2209
return false;
2210
}
2211
2212
if (*attributeChangePositions.begin() > 0) {
2213
attributeChangePositions.insert(0);
2214
}
2215
#ifdef DEBUG_VARIABLE_SPEED
2216
if (gDebugFlag1) std::cout
2217
<< " buildSpeedChanges sectionStart=" << s
2218
<< " speedChangePositions=" << joinToString(speedChangePositions, ", ")
2219
<< "\n";
2220
#endif
2221
for (std::set<double>::iterator i = attributeChangePositions.begin(); i != attributeChangePositions.end(); ++i) {
2222
if (i == attributeChangePositions.begin()) {
2223
newSections.push_back(*this);
2224
} else {
2225
newSections.push_back(buildLaneSection(tc, *i));
2226
}
2227
}
2228
// propagate speeds and access restrictions
2229
for (int i = 0; i != (int)newSections.size(); ++i) {
2230
for (auto& k : newSections[i].lanesByDir) {
2231
for (int j = 0; j != (int)k.second.size(); ++j) {
2232
OpenDriveLane& l = k.second[j];
2233
if (l.speed == 0) {
2234
if (i > 0) {
2235
l.speed = newSections[i - 1].lanesByDir[k.first][j].speed;
2236
} else {
2237
tc.getEdgeTypeSpeed(l.type);
2238
}
2239
}
2240
if (l.permission == 0) {
2241
if (i > 0) {
2242
l.permission = newSections[i - 1].lanesByDir[k.first][j].permission;
2243
l.type = newSections[i - 1].lanesByDir[k.first][j].type;
2244
} else {
2245
tc.getEdgeTypePermissions(l.type);
2246
}
2247
}
2248
}
2249
}
2250
}
2251
return true;
2252
}
2253
2254
2255
2256
// ---------------------------------------------------------------------------
2257
// edge
2258
// ---------------------------------------------------------------------------
2259
int
2260
NIImporter_OpenDrive::OpenDriveEdge::getPriority(OpenDriveXMLTag dir) const {
2261
// for signal interpretations see https://de.wikipedia.org/wiki/Bildtafel_der_Verkehrszeichen_in_der_Bundesrepublik_Deutschland_seit_2013
2262
int prio = 1;
2263
for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
2264
int tmp = 1;
2265
if ((*i).type == "301" || (*i).type == "306") { // priority road or local priority
2266
tmp = 2;
2267
}
2268
if ((*i).type == "205" /*|| (*i).type == "206"*/) { // yield or stop
2269
tmp = 0;
2270
}
2271
if (tmp != 1 && dir == OPENDRIVE_TAG_RIGHT && (*i).orientation > 0) {
2272
prio = tmp;
2273
}
2274
if (tmp != 1 && dir == OPENDRIVE_TAG_LEFT && (*i).orientation < 0) {
2275
prio = tmp;
2276
}
2277
2278
}
2279
return prio;
2280
}
2281
2282
2283
2284
// ---------------------------------------------------------------------------
2285
// loader methods
2286
// ---------------------------------------------------------------------------
2287
NIImporter_OpenDrive::NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges)
2288
: GenericSAXHandler(openDriveTags, OPENDRIVE_TAG_NOTHING, openDriveAttrs, OPENDRIVE_ATTR_NOTHING, "opendrive"),
2289
myTypeContainer(tc), myCurrentEdge("", "", "", -1), myCurrentController("", ""), myEdges(edges), myOffset(0, 0),
2290
myUseCurrentNode(false) {
2291
}
2292
2293
2294
NIImporter_OpenDrive::~NIImporter_OpenDrive() {
2295
}
2296
2297
2298
void
2299
NIImporter_OpenDrive::myStartElement(int element,
2300
const SUMOSAXAttributes& attrs) {
2301
if (myUseCurrentNode) { // skip the parent node repeated in the included file
2302
myUseCurrentNode = false;
2303
myElementStack.push_back(element);
2304
return;
2305
}
2306
bool ok = true;
2307
switch (element) {
2308
case OPENDRIVE_TAG_HEADER: {
2309
int majorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMAJOR, nullptr, ok);
2310
int minorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMINOR, nullptr, ok);
2311
if (majorVersion == 1 && minorVersion > 4) { // disable flags only used for old 1.4 standard
2312
NIImporter_OpenDrive::myIgnoreMisplacedSignals = false;
2313
}
2314
/*
2315
if (majorVersion != 1 || minorVersion != 2) {
2316
// TODO: leave note of exceptions
2317
WRITE_WARNINGF(TL("Given openDrive file '%' uses version %.%;\n Version 1.2 is supported."), getFileName(), toString(majorVersion), toString(minorVersion));
2318
}
2319
*/
2320
}
2321
break;
2322
case OPENDRIVE_TAG_OFFSET: {
2323
double x = attrs.get<double>(OPENDRIVE_ATTR_X, "offset", ok);
2324
double y = attrs.get<double>(OPENDRIVE_ATTR_Y, "offset", ok);
2325
double z = attrs.get<double>(OPENDRIVE_ATTR_Z, "offset", ok);
2326
myOffset.set(-x, -y, -z);
2327
if (GeoConvHelper::getNumLoaded()) {
2328
GeoConvHelper::getLoaded().moveConvertedBy(-x, -y);
2329
}
2330
}
2331
break;
2332
case OPENDRIVE_TAG_ROAD: {
2333
std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, nullptr, ok);
2334
std::string streetName = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, nullptr, ok, "", false);
2335
std::string junction = attrs.get<std::string>(OPENDRIVE_ATTR_JUNCTION, id.c_str(), ok);
2336
double length = attrs.get<double>(OPENDRIVE_ATTR_LENGTH, id.c_str(), ok);
2337
myCurrentEdge = OpenDriveEdge(id, streetName, junction, length);
2338
}
2339
break;
2340
case OPENDRIVE_TAG_PREDECESSOR: {
2341
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
2342
std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
2343
std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
2344
std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
2345
? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
2346
: "end";
2347
addLink(OPENDRIVE_LT_PREDECESSOR, elementType, elementID, contactPoint);
2348
}
2349
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
2350
int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
2351
OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
2352
l.predecessor = no;
2353
}
2354
}
2355
break;
2356
case OPENDRIVE_TAG_SUCCESSOR: {
2357
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
2358
std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
2359
std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
2360
std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
2361
? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
2362
: "start";
2363
addLink(OPENDRIVE_LT_SUCCESSOR, elementType, elementID, contactPoint);
2364
}
2365
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
2366
int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
2367
OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
2368
l.successor = no;
2369
}
2370
}
2371
break;
2372
case OPENDRIVE_TAG_GEOMETRY: {
2373
double length = attrs.get<double>(OPENDRIVE_ATTR_LENGTH, myCurrentEdge.id.c_str(), ok);
2374
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2375
double x = attrs.get<double>(OPENDRIVE_ATTR_X, myCurrentEdge.id.c_str(), ok);
2376
double y = attrs.get<double>(OPENDRIVE_ATTR_Y, myCurrentEdge.id.c_str(), ok);
2377
double hdg = attrs.get<double>(OPENDRIVE_ATTR_HDG, myCurrentEdge.id.c_str(), ok);
2378
myCurrentEdge.geometries.push_back(OpenDriveGeometry(length, s, x, y, hdg));
2379
}
2380
break;
2381
case OPENDRIVE_TAG_ELEVATION: {
2382
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2383
double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
2384
double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
2385
double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
2386
double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
2387
myCurrentEdge.elevations.push_back(OpenDriveElevation(s, a, b, c, d));
2388
}
2389
break;
2390
case OPENDRIVE_TAG_LINE: {
2391
if (myElementStack.size() > 0 && myElementStack.back() == OPENDRIVE_TAG_GEOMETRY) {
2392
std::vector<double> vals;
2393
addGeometryShape(OPENDRIVE_GT_LINE, vals);
2394
}
2395
}
2396
break;
2397
case OPENDRIVE_TAG_SPIRAL: {
2398
std::vector<double> vals;
2399
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVSTART, myCurrentEdge.id.c_str(), ok));
2400
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVEND, myCurrentEdge.id.c_str(), ok));
2401
addGeometryShape(OPENDRIVE_GT_SPIRAL, vals);
2402
}
2403
break;
2404
case OPENDRIVE_TAG_ARC: {
2405
std::vector<double> vals;
2406
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVATURE, myCurrentEdge.id.c_str(), ok));
2407
addGeometryShape(OPENDRIVE_GT_ARC, vals);
2408
}
2409
break;
2410
case OPENDRIVE_TAG_POLY3: {
2411
std::vector<double> vals;
2412
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok));
2413
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok));
2414
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok));
2415
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok));
2416
addGeometryShape(OPENDRIVE_GT_POLY3, vals);
2417
}
2418
break;
2419
case OPENDRIVE_TAG_PARAMPOLY3: {
2420
std::vector<double> vals;
2421
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_AU, myCurrentEdge.id.c_str(), ok));
2422
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_BU, myCurrentEdge.id.c_str(), ok));
2423
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CU, myCurrentEdge.id.c_str(), ok));
2424
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_DU, myCurrentEdge.id.c_str(), ok));
2425
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_AV, myCurrentEdge.id.c_str(), ok));
2426
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_BV, myCurrentEdge.id.c_str(), ok));
2427
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CV, myCurrentEdge.id.c_str(), ok));
2428
vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_DV, myCurrentEdge.id.c_str(), ok));
2429
const std::string pRange = attrs.getOpt<std::string>(OPENDRIVE_ATTR_PRANGE, myCurrentEdge.id.c_str(), ok, "normalized", false);
2430
if (pRange == "normalized") {
2431
vals.push_back(1.0);
2432
} else if (pRange == "arcLength") {
2433
vals.push_back(-1.0);
2434
} else {
2435
WRITE_WARNINGF(TL("Ignoring invalid pRange value '%' for road '%'."), pRange, myCurrentEdge.id);
2436
vals.push_back(1.0);
2437
}
2438
addGeometryShape(OPENDRIVE_GT_PARAMPOLY3, vals);
2439
}
2440
break;
2441
case OPENDRIVE_TAG_LANESECTION: {
2442
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2443
if (myCurrentEdge.laneSections.size() > 0) {
2444
myCurrentEdge.laneSections.back().length = s - myCurrentEdge.laneSections.back().s;
2445
}
2446
myCurrentEdge.laneSections.push_back(OpenDriveLaneSection(s));
2447
2448
// possibly updated by the next laneSection
2449
myCurrentEdge.laneSections.back().length = myCurrentEdge.length - s;
2450
}
2451
break;
2452
case OPENDRIVE_TAG_LANEOFFSET: {
2453
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2454
double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
2455
double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
2456
double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
2457
double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
2458
myCurrentEdge.offsets.push_back(OpenDriveLaneOffset(s, a, b, c, d));
2459
}
2460
break;
2461
case OPENDRIVE_TAG_LEFT:
2462
myCurrentLaneDirection = OPENDRIVE_TAG_LEFT;
2463
break;
2464
case OPENDRIVE_TAG_CENTER:
2465
myCurrentLaneDirection = OPENDRIVE_TAG_CENTER;
2466
break;
2467
case OPENDRIVE_TAG_RIGHT:
2468
myCurrentLaneDirection = OPENDRIVE_TAG_RIGHT;
2469
break;
2470
case OPENDRIVE_TAG_LANE: {
2471
std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
2472
int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
2473
std::string level = attrs.hasAttribute(OPENDRIVE_ATTR_LEVEL)
2474
? attrs.get<std::string>(OPENDRIVE_ATTR_LEVEL, myCurrentEdge.id.c_str(), ok)
2475
: "";
2476
OpenDriveLaneSection& ls = myCurrentEdge.laneSections.back();
2477
ls.lanesByDir[myCurrentLaneDirection].push_back(OpenDriveLane(id, level, type));
2478
}
2479
break;
2480
case OPENDRIVE_TAG_SIGNAL: {
2481
std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
2482
std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
2483
std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, myCurrentEdge.id.c_str(), ok, "", false);
2484
const std::string orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, id.c_str(), ok);
2485
int orientationCode = orientation == "-" ? -1 : orientation == "+" ? 1 : 0;
2486
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2487
bool dynamic = attrs.get<std::string>(OPENDRIVE_ATTR_DYNAMIC, myCurrentEdge.id.c_str(), ok) == "no" ? false : true;
2488
OpenDriveSignal signal = OpenDriveSignal(id, type, name, orientationCode, dynamic, s);
2489
myCurrentEdge.signals.push_back(signal);
2490
mySignals[id] = signal;
2491
}
2492
break;
2493
case OPENDRIVE_TAG_SIGNALREFERENCE: {
2494
std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
2495
const std::string orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, id.c_str(), ok);
2496
int orientationCode = orientation == "-" ? -1 : orientation == "+" ? 1 : 0;
2497
double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
2498
OpenDriveSignal signal = OpenDriveSignal(id, "", "", orientationCode, false, s);
2499
myCurrentEdge.signals.push_back(signal);
2500
}
2501
break;
2502
case OPENDRIVE_TAG_CONTROLLER: {
2503
std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, nullptr, ok);
2504
std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, nullptr, ok, "", false);
2505
myCurrentController = OpenDriveController(id, name);
2506
}
2507
break;
2508
case OPENDRIVE_TAG_CONTROL: {
2509
std::string signalID = attrs.get<std::string>(OPENDRIVE_ATTR_SIGNALID, myCurrentController.id.c_str(), ok);
2510
myCurrentController.signalIDs.push_back(signalID);
2511
if (mySignals.find(signalID) != mySignals.end()) {
2512
mySignals[signalID].controller = myCurrentController.id;
2513
} else {
2514
WRITE_WARNINGF(TL("Ignoring missing signal '%' in controller '%'."), signalID, myCurrentController.id);
2515
}
2516
}
2517
break;
2518
case OPENDRIVE_TAG_VALIDITY: {
2519
int fromLane = attrs.get<int>(OPENDRIVE_ATTR_FROMLANE, myCurrentEdge.id.c_str(), ok);
2520
int toLane = attrs.get<int>(OPENDRIVE_ATTR_TOLANE, myCurrentEdge.id.c_str(), ok);
2521
if (myElementStack.size() >= 1 && (myElementStack.back() == OPENDRIVE_TAG_SIGNAL
2522
|| myElementStack.back() == OPENDRIVE_TAG_SIGNALREFERENCE)) {
2523
myCurrentEdge.signals.back().minLane = fromLane;
2524
myCurrentEdge.signals.back().maxLane = toLane;
2525
}
2526
}
2527
break;
2528
case OPENDRIVE_TAG_PRIORITY: {
2529
if (myElementStack.size() >= 2
2530
&& myElementStack.back() == OPENDRIVE_TAG_SEMANTICS
2531
&& myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_SIGNAL) {
2532
auto& signal = myCurrentEdge.signals.back();
2533
signal.priority = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, signal.id.c_str(), ok);
2534
}
2535
}
2536
break;
2537
case OPENDRIVE_TAG_JUNCTION:
2538
myCurrentJunctionID = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
2539
break;
2540
case OPENDRIVE_TAG_CONNECTION: {
2541
std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
2542
myCurrentIncomingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_INCOMINGROAD, myCurrentJunctionID.c_str(), ok);
2543
myCurrentConnectingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_CONNECTINGROAD, myCurrentJunctionID.c_str(), ok);
2544
std::string cp = attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentJunctionID.c_str(), ok);
2545
myCurrentContactPoint = cp == "start" ? OPENDRIVE_CP_START : OPENDRIVE_CP_END;
2546
myConnectionWasEmpty = true;
2547
}
2548
break;
2549
case OPENDRIVE_TAG_LANELINK: {
2550
int from = attrs.get<int>(OPENDRIVE_ATTR_FROM, myCurrentJunctionID.c_str(), ok);
2551
int to = attrs.get<int>(OPENDRIVE_ATTR_TO, myCurrentJunctionID.c_str(), ok);
2552
Connection c;
2553
c.fromEdge = myCurrentIncomingRoad;
2554
c.toEdge = myCurrentConnectingRoad;
2555
c.fromLane = from;
2556
c.toLane = to;
2557
c.fromCP = OPENDRIVE_CP_END;
2558
c.toCP = myCurrentContactPoint;
2559
c.all = false;
2560
if (myEdges.find(c.fromEdge) == myEdges.end()) {
2561
WRITE_ERRORF(TL("In laneLink-element: incoming road '%' is not known."), c.fromEdge);
2562
} else {
2563
OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
2564
e->connections.insert(c);
2565
myConnectionWasEmpty = false;
2566
}
2567
}
2568
break;
2569
case OPENDRIVE_TAG_WIDTH: {
2570
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
2571
const double s = attrs.get<double>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
2572
const double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
2573
const double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
2574
const double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
2575
const double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
2576
OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
2577
l.width = MAX2(l.width, a);
2578
l.widthData.push_back(OpenDriveWidth(s, a, b, c, d));
2579
#ifdef DEBUG_VARIABLE_WIDTHS
2580
if (DEBUG_COND(&myCurrentEdge)) {
2581
std::cout << " road=" << myCurrentEdge.id
2582
<< std::setprecision(gPrecision)
2583
<< " junction=" << myCurrentEdge.junction
2584
<< " section=" << myCurrentEdge.laneSections.size() - 1
2585
<< " dir=" << myCurrentLaneDirection << " lane=" << l.id
2586
<< " type=" << l.type
2587
<< " width=" << l.width
2588
<< " a=" << a
2589
<< " b=" << b
2590
<< " c=" << c
2591
<< " d=" << d
2592
<< " s=" << s
2593
<< " entries=" << l.widthData.size()
2594
<< "\n";
2595
}
2596
#endif
2597
}
2598
}
2599
break;
2600
case OPENDRIVE_TAG_ACCESS: {
2601
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
2602
const double pos = attrs.get<double>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
2603
std::string rule = attrs.getOpt<std::string>(OPENDRIVE_ATTR_RULE, nullptr, ok, "allow", false); // OpenDRIVE 1.4 without rule value
2604
std::string vClass = attrs.get<std::string>(OPENDRIVE_ATTR_RESTRICTION, myCurrentEdge.id.c_str(), ok);
2605
2606
std::vector < std::pair<double, LaneAttributeChange >>& attributeChanges = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().attributeChanges;
2607
std::vector<std::pair<double, LaneAttributeChange> >::iterator i = std::find_if(attributeChanges.begin(), attributeChanges.end(), same_position_finder(pos));
2608
if (i != attributeChanges.end()) {
2609
if (rule == "allow") {
2610
(*i).second.allowed.push_back(vClass);
2611
} else if (rule == "deny") {
2612
(*i).second.denied.push_back(vClass);
2613
}
2614
} else {
2615
LaneAttributeChange lac = LaneAttributeChange(0);
2616
if (rule == "allow") {
2617
lac.allowed.push_back(vClass);
2618
} else if (rule == "deny") {
2619
lac.denied.push_back(vClass);
2620
}
2621
attributeChanges.push_back(std::make_pair(pos, lac));
2622
}
2623
}
2624
}
2625
break;
2626
case OPENDRIVE_TAG_SPEED: {
2627
if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
2628
double speed = attrs.get<double>(OPENDRIVE_ATTR_MAX, myCurrentEdge.id.c_str(), ok);
2629
double pos = attrs.get<double>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
2630
// required for xodr v1.4
2631
const std::string unit = attrs.getOpt<std::string>(OPENDRIVE_ATTR_UNIT, myCurrentEdge.id.c_str(), ok, "", false);
2632
// now convert the speed to reasonable default SI [m/s]
2633
if (!unit.empty()) {
2634
// something to be done at all ?
2635
if (unit == "km/h") {
2636
speed /= 3.6;
2637
}
2638
if (unit == "mph") {
2639
speed *= 1.609344 / 3.6;
2640
}
2641
// IGNORING unknown units.
2642
}
2643
std::vector < std::pair<double, LaneAttributeChange >>& attributeChanges = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().attributeChanges;
2644
std::vector<std::pair<double, LaneAttributeChange> >::iterator i = std::find_if(attributeChanges.begin(), attributeChanges.end(), same_position_finder(pos));
2645
if (i != attributeChanges.end()) {
2646
(*i).second.speed = speed;
2647
} else {
2648
LaneAttributeChange lac = LaneAttributeChange(speed);
2649
attributeChanges.push_back(std::make_pair(pos, lac));
2650
}
2651
}
2652
}
2653
break;
2654
case OPENDRIVE_TAG_OBJECT: {
2655
if (!attrs.hasAttribute(OPENDRIVE_ATTR_ID)) {
2656
WRITE_WARNINGF(TL("Ignoring object without id at edge '%'."), toString(myCurrentEdge.id));
2657
break;
2658
}
2659
OpenDriveObject o;
2660
o.id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, 0, ok);
2661
o.type = attrs.getOpt<std::string>(OPENDRIVE_ATTR_TYPE, o.id.c_str(), ok, "", false);
2662
o.name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, o.id.c_str(), ok, "", false);
2663
o.s = attrs.get<double>(OPENDRIVE_ATTR_S, o.id.c_str(), ok);
2664
o.t = attrs.get<double>(OPENDRIVE_ATTR_T, o.id.c_str(), ok);
2665
o.width = attrs.getOpt<double>(OPENDRIVE_ATTR_WIDTH, o.id.c_str(), ok, -1);
2666
o.length = attrs.getOpt<double>(OPENDRIVE_ATTR_LENGTH, o.id.c_str(), ok, -1);
2667
o.radius = attrs.getOpt<double>(OPENDRIVE_ATTR_RADIUS, o.id.c_str(), ok, -1);
2668
o.hdg = attrs.getOpt<double>(OPENDRIVE_ATTR_HDG, o.id.c_str(), ok, 0);
2669
myCurrentEdge.objects.push_back(o);
2670
}
2671
break;
2672
case OPENDRIVE_TAG_REPEAT: {
2673
if (myCurrentEdge.objects.empty()) {
2674
WRITE_ERRORF(TL("Repeat without object at edge '%'."), toString(myCurrentEdge.id));
2675
ok = false;
2676
} else {
2677
OpenDriveObject o = myCurrentEdge.objects.back();
2678
const std::string baseID = o.id;
2679
double dist = attrs.get<double>(OPENDRIVE_ATTR_DISTANCE, o.id.c_str(), ok);
2680
if (dist == 0) {
2681
// continuous feature. Split into parts (XXX exmport as a single polygon #5235)
2682
dist = OptionsCont::getOptions().getFloat("opendrive.curve-resolution");
2683
}
2684
2685
myCurrentEdge.objects.pop_back();
2686
const double length = attrs.get<double>(OPENDRIVE_ATTR_LENGTH, o.id.c_str(), ok);
2687
o.s = attrs.getOpt<double>(OPENDRIVE_ATTR_S, o.id.c_str(), ok, o.s);
2688
double wStart = attrs.getOpt<double>(OPENDRIVE_ATTR_WIDTHSTART, o.id.c_str(), ok, o.width);
2689
double wEnd = attrs.getOpt<double>(OPENDRIVE_ATTR_WIDTHEND, o.id.c_str(), ok, o.width);
2690
double tStart = attrs.getOpt<double>(OPENDRIVE_ATTR_TSTART, o.id.c_str(), ok, o.t);
2691
double tEnd = attrs.getOpt<double>(OPENDRIVE_ATTR_TEND, o.id.c_str(), ok, o.t);
2692
int index = 0;
2693
for (double x = 0; x <= length + NUMERICAL_EPS; x += dist) {
2694
o.id = baseID + "#" + toString(index++);
2695
const double a = x / length;
2696
o.width = wStart * (1 - a) + wEnd * a;
2697
o.t = tStart * (1 - a) + tEnd * a;
2698
myCurrentEdge.objects.push_back(o);
2699
o.s += dist;
2700
}
2701
}
2702
}
2703
break;
2704
case OPENDRIVE_TAG_INCLUDE: {
2705
std::string includedFile = attrs.get<std::string>(OPENDRIVE_ATTR_FILE, 0, ok);
2706
if (!FileHelpers::isAbsolute(includedFile)) {
2707
includedFile = FileHelpers::getConfigurationRelative(getFileName(), includedFile);
2708
}
2709
PROGRESS_BEGIN_MESSAGE("Parsing included opendrive from '" + includedFile + "'");
2710
myUseCurrentNode = true;
2711
XMLSubSys::runParser(*this, includedFile);
2712
PROGRESS_DONE_MESSAGE();
2713
}
2714
break;
2715
default:
2716
break;
2717
}
2718
myElementStack.push_back(element);
2719
}
2720
2721
2722
void
2723
NIImporter_OpenDrive::myCharacters(int element, const std::string& cdata) {
2724
if (element == OPENDRIVE_TAG_GEOREFERENCE) {
2725
size_t i = cdata.find("+proj");
2726
if (i != std::string::npos) {
2727
const std::string proj = cdata.substr(i);
2728
if (proj != "") {
2729
Boundary convBoundary;
2730
Boundary origBoundary;
2731
// XXX read values from the header
2732
convBoundary.add(Position(0, 0));
2733
origBoundary.add(Position(0, 0));
2734
try {
2735
GeoConvHelper::setLoaded(GeoConvHelper(proj, myOffset, origBoundary, convBoundary));
2736
} catch (ProcessError& e) {
2737
WRITE_ERRORF(TL("Could not set projection (%). This can be ignored with --ignore-errors."), std::string(e.what()));
2738
}
2739
}
2740
} else {
2741
WRITE_WARNINGF(TL("geoReference format '%' currently not supported"), cdata);
2742
}
2743
needsCharacterData(false);
2744
}
2745
}
2746
2747
2748
void
2749
NIImporter_OpenDrive::myEndElement(int element) {
2750
myElementStack.pop_back();
2751
switch (element) {
2752
case OPENDRIVE_TAG_ROAD:
2753
myEdges[myCurrentEdge.id] = new OpenDriveEdge(myCurrentEdge);
2754
break;
2755
case OPENDRIVE_TAG_CONNECTION:
2756
if (myConnectionWasEmpty) {
2757
Connection c;
2758
c.fromEdge = myCurrentIncomingRoad;
2759
c.toEdge = myCurrentConnectingRoad;
2760
c.fromLane = 0;
2761
c.toLane = 0;
2762
c.fromCP = OPENDRIVE_CP_END;
2763
c.toCP = myCurrentContactPoint;
2764
c.all = true;
2765
if (myEdges.find(c.fromEdge) == myEdges.end()) {
2766
WRITE_ERRORF(TL("In laneLink-element: incoming road '%' is not known."), c.fromEdge);
2767
} else {
2768
OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
2769
e->connections.insert(c);
2770
}
2771
}
2772
break;
2773
case OPENDRIVE_TAG_CONTROLLER: {
2774
myControllers.insert({ myCurrentController.id, myCurrentController });
2775
}
2776
break;
2777
case OPENDRIVE_TAG_LANESECTION: {
2778
myCurrentEdge.laneSections.back().buildLaneMapping(myTypeContainer);
2779
}
2780
break;
2781
case OPENDRIVE_TAG_SIGNAL:
2782
case OPENDRIVE_TAG_SIGNALREFERENCE: {
2783
if (NIImporter_OpenDrive::myIgnoreMisplacedSignals) {
2784
int intType = -1;
2785
try {
2786
intType = StringUtils::toInt(myCurrentEdge.signals.back().type);
2787
} catch (NumberFormatException&) {
2788
break;
2789
} catch (EmptyData&) {
2790
break;
2791
}
2792
if (intType < 1000001 || (intType > 1000013 && intType != 1000020) || intType == 1000008) {
2793
// not a traffic_light (Section 6.11)
2794
break;
2795
}
2796
double s = myCurrentEdge.signals.back().s;
2797
int minLane = myCurrentEdge.signals.back().minLane;
2798
int maxLane = myCurrentEdge.signals.back().maxLane;
2799
bool foundDrivingType = false;
2800
for (OpenDriveLaneSection ls : myCurrentEdge.laneSections) {
2801
if (ls.s <= s && ls.s + ls.length > s) {
2802
if (myCurrentEdge.signals.back().orientation < 0) {
2803
for (OpenDriveLane l : ls.lanesByDir[OPENDRIVE_TAG_LEFT]) {
2804
if ((minLane < 0 && l.id >= minLane && l.id <= maxLane) && l.type == "driving") {
2805
foundDrivingType = true;
2806
}
2807
}
2808
} else if (myCurrentEdge.signals.back().orientation > 0) { // 0 = center is never used for driving
2809
for (OpenDriveLane l : ls.lanesByDir[OPENDRIVE_TAG_RIGHT]) {
2810
if ((minLane > 0 && l.id >= minLane && l.id <= maxLane) && l.type == "driving") {
2811
foundDrivingType = true;
2812
}
2813
}
2814
}
2815
}
2816
}
2817
if (!foundDrivingType) { // reject signal / signal reference if not on driving lane
2818
myCurrentEdge.signals.pop_back();
2819
}
2820
}
2821
}
2822
break;
2823
default:
2824
break;
2825
}
2826
}
2827
2828
2829
2830
void
2831
NIImporter_OpenDrive::addLink(LinkType lt, const std::string& elementType,
2832
const std::string& elementID,
2833
const std::string& contactPoint) {
2834
OpenDriveLink l(lt, elementID);
2835
// elementType
2836
if (elementType == "road") {
2837
l.elementType = OPENDRIVE_ET_ROAD;
2838
} else if (elementType == "junction") {
2839
l.elementType = OPENDRIVE_ET_JUNCTION;
2840
}
2841
// contact point
2842
if (contactPoint == "start") {
2843
l.contactPoint = OPENDRIVE_CP_START;
2844
} else if (contactPoint == "end") {
2845
l.contactPoint = OPENDRIVE_CP_END;
2846
}
2847
// add
2848
myCurrentEdge.links.push_back(l);
2849
}
2850
2851
2852
void
2853
NIImporter_OpenDrive::addGeometryShape(GeometryType type, const std::vector<double>& vals) {
2854
// checks
2855
if (myCurrentEdge.geometries.size() == 0) {
2856
throw ProcessError(TLF("Mismatching parenthesis in geometry definition for road '%'", myCurrentEdge.id));
2857
}
2858
OpenDriveGeometry& last = myCurrentEdge.geometries.back();
2859
if (last.type != OPENDRIVE_GT_UNKNOWN) {
2860
throw ProcessError(TLF("Double geometry information for road '%'", myCurrentEdge.id));
2861
}
2862
// set
2863
last.type = type;
2864
last.params = vals;
2865
}
2866
2867
2868
bool
2869
operator<(const NIImporter_OpenDrive::Connection& c1, const NIImporter_OpenDrive::Connection& c2) {
2870
if (c1.fromEdge != c2.fromEdge) {
2871
return c1.fromEdge < c2.fromEdge;
2872
}
2873
if (c1.toEdge != c2.toEdge) {
2874
return c1.toEdge < c2.toEdge;
2875
}
2876
if (c1.fromLane != c2.fromLane) {
2877
return c1.fromLane < c2.fromLane;
2878
}
2879
return c1.toLane < c2.toLane;
2880
}
2881
2882
void
2883
NIImporter_OpenDrive::sanitizeWidths(OpenDriveEdge* e) {
2884
#ifdef DEBUG_VARIABLE_WIDTHS
2885
if (DEBUG_COND(e)) {
2886
gDebugFlag1 = true;
2887
std::cout << "sanitizeWidths e=" << e->id << " sections=" << e->laneSections.size() << "\n";
2888
}
2889
#endif
2890
for (OpenDriveLaneSection& sec : e->laneSections) {
2891
// filter widths within the current section (#5888).
2892
// @note, Short laneSections could also be worth filtering alltogether
2893
if (sec.rightLaneNumber > 0) {
2894
sanitizeWidths(sec.lanesByDir[OPENDRIVE_TAG_RIGHT], sec.length);
2895
}
2896
if (sec.leftLaneNumber > 0) {
2897
sanitizeWidths(sec.lanesByDir[OPENDRIVE_TAG_LEFT], sec.length);
2898
}
2899
}
2900
}
2901
2902
void
2903
NIImporter_OpenDrive::sanitizeWidths(std::vector<OpenDriveLane>& lanes, double length) {
2904
for (OpenDriveLane& l : lanes) {
2905
if (l.widthData.size() > 0) {
2906
auto& wd = l.widthData;
2907
const double threshold = POSITION_EPS;
2908
double maxNoShort = -std::numeric_limits<double>::max();
2909
double seen = 0;
2910
for (int i = 0; i < (int)wd.size(); i++) {
2911
const double wdLength = i < (int)wd.size() - 1 ? wd[i + 1].s - wd[i].s : length - seen;
2912
seen += wdLength;
2913
if (wdLength > threshold) {
2914
maxNoShort = MAX2(maxNoShort, wd[i].a);
2915
}
2916
}
2917
if (maxNoShort > 0) {
2918
l.width = maxNoShort;
2919
#ifdef DEBUG_VARIABLE_WIDTHS
2920
if (gDebugFlag1) {
2921
std::cout << " lane=" << l.id << " width=" << l.width << "\n";
2922
}
2923
#endif
2924
}
2925
}
2926
}
2927
}
2928
2929
2930
void
2931
NIImporter_OpenDrive::splitMinWidths(OpenDriveEdge* e, const NBTypeCont& tc, double minDist) {
2932
std::vector<OpenDriveLaneSection> newSections;
2933
#ifdef DEBUG_VARIABLE_WIDTHS
2934
if (DEBUG_COND(e)) {
2935
gDebugFlag1 = true;
2936
std::cout << "splitMinWidths e=" << e->id << " sections=" << e->laneSections.size() << "\n";
2937
}
2938
#endif
2939
for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
2940
OpenDriveLaneSection& sec = *j;
2941
std::vector<double> splitPositions;
2942
const double sectionEnd = (j + 1) == e->laneSections.end() ? e->length : (*(j + 1)).s;
2943
const int section = (int)(j - e->laneSections.begin());
2944
#ifdef DEBUG_VARIABLE_WIDTHS
2945
if (DEBUG_COND(e)) {
2946
std::cout << " findWidthSplit section=" << section << " sectionStart=" << sec.s << " sectionOrigStart=" << sec.sOrig << " sectionEnd=" << sectionEnd << "\n";
2947
}
2948
#endif
2949
if (sec.rightLaneNumber > 0) {
2950
findWidthSplit(tc, sec.lanesByDir[OPENDRIVE_TAG_RIGHT], section, sec.sOrig, sectionEnd, splitPositions);
2951
}
2952
if (sec.leftLaneNumber > 0) {
2953
findWidthSplit(tc, sec.lanesByDir[OPENDRIVE_TAG_LEFT], section, sec.sOrig, sectionEnd, splitPositions);
2954
}
2955
newSections.push_back(sec);
2956
std::sort(splitPositions.begin(), splitPositions.end());
2957
// filter out tiny splits
2958
double prevSplit = sec.s;
2959
for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end();) {
2960
if ((*it) - prevSplit < minDist || sectionEnd - (*it) < minDist) {
2961
// avoid tiny (or duplicate) splits
2962
#ifdef DEBUG_VARIABLE_WIDTHS
2963
if (DEBUG_COND(e)) {
2964
std::cout << " skip close split=" << (*it) << " prevSplit=" << prevSplit << "\n";
2965
}
2966
#endif
2967
it = splitPositions.erase(it);
2968
} else if ((*it) < sec.s) {
2969
// avoid splits for another section
2970
#ifdef DEBUG_VARIABLE_WIDTHS
2971
if (DEBUG_COND(e)) {
2972
std::cout << " skip early split=" << (*it) << " s=" << sec.s << "\n";
2973
}
2974
#endif
2975
it = splitPositions.erase(it);
2976
} else {
2977
prevSplit = *it;
2978
it++;
2979
}
2980
}
2981
2982
if (splitPositions.size() > 0) {
2983
#ifdef DEBUG_VARIABLE_WIDTHS
2984
if (DEBUG_COND(e)) {
2985
std::cout << " road=" << e->id << " splitMinWidths section=" << section
2986
<< " start=" << sec.s
2987
<< " origStart=" << sec.sOrig
2988
<< " end=" << sectionEnd << " minDist=" << minDist
2989
<< " splitPositions=" << toString(splitPositions) << "\n";
2990
}
2991
#endif
2992
#ifdef DEBUG_VARIABLE_WIDTHS
2993
if (DEBUG_COND(e)) {
2994
std::cout << "first section...\n";
2995
}
2996
#endif
2997
recomputeWidths(newSections.back(), sec.sOrig, splitPositions.front(), sec.sOrig, sectionEnd);
2998
for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end(); ++it) {
2999
OpenDriveLaneSection secNew = sec;
3000
secNew.s = *it;
3001
#ifdef DEBUG_VARIABLE_WIDTHS
3002
if (DEBUG_COND(e)) {
3003
std::cout << "splitAt " << secNew.s << "\n";
3004
}
3005
#endif
3006
newSections.push_back(secNew);
3007
if (secNew.rightLaneNumber > 0) {
3008
setStraightConnections(newSections.back().lanesByDir[OPENDRIVE_TAG_RIGHT]);
3009
}
3010
if (secNew.leftLaneNumber > 0) {
3011
setStraightConnections(newSections.back().lanesByDir[OPENDRIVE_TAG_LEFT]);
3012
}
3013
double end = (it + 1) == splitPositions.end() ? sectionEnd : *(it + 1);
3014
recomputeWidths(newSections.back(), secNew.s, end, sec.sOrig, sectionEnd);
3015
}
3016
}
3017
}
3018
gDebugFlag1 = false;
3019
e->laneSections = newSections;
3020
}
3021
3022
3023
void
3024
NIImporter_OpenDrive::findWidthSplit(const NBTypeCont& tc, std::vector<OpenDriveLane>& lanes,
3025
int section, double sectionStart, double sectionEnd,
3026
std::vector<double>& splitPositions) {
3027
UNUSED_PARAMETER(section);
3028
for (const OpenDriveLane& l : lanes) {
3029
const SVCPermissions permissions = tc.getEdgeTypePermissions(l.type) & ~SVC_VULNERABLE;
3030
if (l.widthData.size() > 0 && tc.knows(l.type) && !tc.getEdgeTypeShallBeDiscarded(l.type) && permissions != 0) {
3031
double sPrev = l.widthData.front().s;
3032
double wPrev = l.widthData.front().computeAt(sPrev);
3033
#ifdef DEBUG_VARIABLE_WIDTHS
3034
if (gDebugFlag1) std::cout
3035
<< "findWidthSplit section=" << section
3036
<< " sectionStart=" << sectionStart
3037
<< " sectionEnd=" << sectionEnd
3038
<< " lane=" << l.id
3039
<< " type=" << l.type
3040
<< " widthEntries=" << l.widthData.size() << "\n"
3041
<< " s=" << sPrev
3042
<< " w=" << wPrev
3043
<< "\n";
3044
#endif
3045
for (std::vector<OpenDriveWidth>::const_iterator it_w = l.widthData.begin(); it_w != l.widthData.end(); ++it_w) {
3046
double sEnd = (it_w + 1) != l.widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
3047
double w = (*it_w).computeAt(sEnd);
3048
#ifdef DEBUG_VARIABLE_WIDTHS
3049
if (gDebugFlag1) std::cout
3050
<< " sEnd=" << sEnd
3051
<< " s=" << (*it_w).s
3052
<< " a=" << (*it_w).a << " b=" << (*it_w).b << " c=" << (*it_w).c << " d=" << (*it_w).d
3053
<< " w=" << w
3054
<< "\n";
3055
#endif
3056
const double changeDist = fabs(myMinWidth - wPrev);
3057
if (((wPrev < myMinWidth) && (w > myMinWidth))
3058
|| ((wPrev > myMinWidth) && (w < myMinWidth))) {
3059
double splitPos = sPrev + (sEnd - sPrev) / fabs(w - wPrev) * changeDist;
3060
double wSplit = (*it_w).computeAt(splitPos);
3061
#ifdef DEBUG_VARIABLE_WIDTHS
3062
if (gDebugFlag1) {
3063
std::cout << " candidate splitPos=" << splitPos << " w=" << wSplit << "\n";
3064
}
3065
#endif
3066
// ensure that the thin part is actually thin enough
3067
while (wSplit > myMinWidth) {
3068
if (wPrev < myMinWidth) {
3069
// getting wider
3070
splitPos -= POSITION_EPS;
3071
if (splitPos < sPrev) {
3072
#ifdef DEBUG_VARIABLE_WIDTHS
3073
if (gDebugFlag1) {
3074
std::cout << " aborting search splitPos=" << splitPos << " wSplit=" << wSplit << " sPrev=" << sPrev << " wPrev=" << wPrev << "\n";
3075
}
3076
#endif
3077
splitPos = sPrev;
3078
break;
3079
}
3080
} else {
3081
// getting thinner
3082
splitPos += POSITION_EPS;
3083
if (splitPos > sEnd) {
3084
#ifdef DEBUG_VARIABLE_WIDTHS
3085
if (gDebugFlag1) {
3086
std::cout << " aborting search splitPos=" << splitPos << " wSplit=" << wSplit << " sEnd=" << sEnd << " w=" << w << "\n";
3087
}
3088
#endif
3089
splitPos = sEnd;
3090
break;
3091
}
3092
}
3093
wSplit = (*it_w).computeAt(splitPos);
3094
#ifdef DEBUG_VARIABLE_WIDTHS
3095
if (gDebugFlag1) {
3096
std::cout << " refined splitPos=" << splitPos << " w=" << wSplit << "\n";
3097
}
3098
#endif
3099
}
3100
splitPositions.push_back(sectionStart + splitPos);
3101
}
3102
// //wPrev = wSplit;
3103
//} else if ((fabs(wPrev) < NUMERICAL_EPS && w > POSITION_EPS)
3104
// || (wPrev > POSITION_EPS && fabs(w) < NUMERICAL_EPS)) {
3105
// splitPositions.push_back(sectionStart + sPrev);
3106
// if (gDebugFlag1) std::cout << " laneDisappears candidate splitPos=" << sPrev << " wPrev=" << wPrev << " w=" << w<< "\n";
3107
//}
3108
wPrev = w;
3109
sPrev = sEnd;
3110
}
3111
}
3112
}
3113
}
3114
3115
3116
void
3117
NIImporter_OpenDrive::setStraightConnections(std::vector<OpenDriveLane>& lanes) {
3118
for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
3119
(*k).predecessor = (*k).id;
3120
}
3121
}
3122
3123
3124
void
3125
NIImporter_OpenDrive::recomputeWidths(OpenDriveLaneSection& sec, double start, double end, double sectionStart, double sectionEnd) {
3126
if (sec.rightLaneNumber > 0) {
3127
recomputeWidths(sec.lanesByDir[OPENDRIVE_TAG_RIGHT], start, end, sectionStart, sectionEnd);
3128
}
3129
if (sec.leftLaneNumber > 0) {
3130
recomputeWidths(sec.lanesByDir[OPENDRIVE_TAG_LEFT], start, end, sectionStart, sectionEnd);
3131
}
3132
}
3133
3134
3135
void
3136
NIImporter_OpenDrive::recomputeWidths(std::vector<OpenDriveLane>& lanes, double start, double end, double sectionStart, double sectionEnd) {
3137
for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
3138
OpenDriveLane& l = *k;
3139
if (l.widthData.size() > 0) {
3140
#ifdef DEBUG_VARIABLE_WIDTHS
3141
if (gDebugFlag1) std::cout
3142
<< "recomputeWidths lane=" << l.id
3143
<< " type=" << l.type
3144
<< " start=" << start
3145
<< " end=" << end
3146
<< " sectionStart=" << sectionStart
3147
<< " sectionEnd=" << sectionEnd
3148
<< " widthEntries=" << l.widthData.size() << "\n"
3149
<< "\n";
3150
#endif
3151
l.width = 0;
3152
double sPrev = l.widthData.front().s;
3153
double sPrevAbs = sPrev + sectionStart;
3154
for (std::vector<OpenDriveWidth>::iterator it_w = l.widthData.begin(); it_w != l.widthData.end(); ++it_w) {
3155
double sEnd = (it_w + 1) != l.widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
3156
double sEndAbs = sEnd + sectionStart;
3157
#ifdef DEBUG_VARIABLE_WIDTHS
3158
if (gDebugFlag1) std::cout
3159
<< " sPrev=" << sPrev << " sPrevAbs=" << sPrevAbs
3160
<< " sEnd=" << sEnd << " sEndAbs=" << sEndAbs
3161
<< " widthData s=" << (*it_w).s
3162
<< " a=" << (*it_w).a
3163
<< " b=" << (*it_w).b
3164
<< " c=" << (*it_w).c
3165
<< " d=" << (*it_w).d
3166
<< "\n";
3167
#endif
3168
if (sPrevAbs <= start && sEndAbs >= start) {
3169
#ifdef DEBUG_VARIABLE_WIDTHS
3170
if (gDebugFlag1) {
3171
std::cout << " atStart=" << start << " pos=" << start - sectionStart << " w=" << (*it_w).computeAt(start - sectionStart) << "\n";
3172
}
3173
#endif
3174
l.width = MAX2(l.width, (*it_w).computeAt(start - sectionStart));
3175
}
3176
if (sPrevAbs <= end && sEndAbs >= end) {
3177
#ifdef DEBUG_VARIABLE_WIDTHS
3178
if (gDebugFlag1) {
3179
std::cout << " atEnd=" << end << " pos=" << end - sectionStart << " w=" << (*it_w).computeAt(end - sectionStart) << "\n";
3180
}
3181
#endif
3182
l.width = MAX2(l.width, (*it_w).computeAt(end - sectionStart));
3183
}
3184
if (start <= sPrevAbs && end >= sPrevAbs) {
3185
#ifdef DEBUG_VARIABLE_WIDTHS
3186
if (gDebugFlag1) {
3187
std::cout << " atSPrev=" << sPrev << " w=" << (*it_w).computeAt(sPrev) << "\n";
3188
}
3189
#endif
3190
l.width = MAX2(l.width, (*it_w).computeAt(sPrev));
3191
}
3192
if (start <= sEndAbs && end >= sEndAbs) {
3193
#ifdef DEBUG_VARIABLE_WIDTHS
3194
if (gDebugFlag1) {
3195
std::cout << " atSEnd=" << sEnd << " w=" << (*it_w).computeAt(sEnd) << "\n";
3196
}
3197
#endif
3198
l.width = MAX2(l.width, (*it_w).computeAt(sEnd));
3199
}
3200
#ifdef DEBUG_VARIABLE_WIDTHS
3201
if (gDebugFlag1) {
3202
std::cout << " sPrev=" << sPrev << " sEnd=" << sEnd << " l.width=" << l.width << "\n";
3203
}
3204
#endif
3205
sPrev = sEnd;
3206
sPrevAbs = sEndAbs;
3207
}
3208
}
3209
}
3210
}
3211
3212
/****************************************************************************/
3213
3214