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