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