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