SUMO - Simulation of Urban MObility
NIImporter_OpenDrive.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Importer for networks stored in openDrive format
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
13 // Copyright (C) 2001-2017 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 #include <string>
34 #include <cmath>
35 #include <iterator>
39 #include <utils/common/ToString.h>
43 #include <netbuild/NBEdge.h>
44 #include <netbuild/NBEdgeCont.h>
45 #include <netbuild/NBNode.h>
46 #include <netbuild/NBNodeCont.h>
47 #include <netbuild/NBNetBuilder.h>
48 #include <netbuild/NBOwnTLDef.h>
56 #include <utils/xml/XMLSubSys.h>
57 #include <utils/geom/Boundary.h>
58 #include "NILoader.h"
59 #include "NIImporter_OpenDrive.h"
60 
61 //#define DEBUG_VARIABLE_WIDTHS
62 //#define DEBUG_VARIABLE_SPEED
63 //#define DEBUG_CONNECTIONS
64 //#define DEBUG_SPIRAL
65 
66 //#define DEBUG_COND(road) ((road)->id == "42")
67 //#define DEBUG_COND2(edgeID) (StringUtils::startsWith((edgeID), "12"))
68 
69 // ===========================================================================
70 // definitions
71 // ===========================================================================
72 
73 // ===========================================================================
74 // static variables
75 // ===========================================================================
100 
102 };
103 
104 
145  // towards xodr v1.4 speed:unit
147 
149 };
150 
151 
155 
156 // ===========================================================================
157 // method definitions
158 // ===========================================================================
159 // ---------------------------------------------------------------------------
160 // static methods (interface in this case)
161 // ---------------------------------------------------------------------------
162 void
164  // check whether the option is set (properly)
165  if (!oc.isUsableFileList("opendrive-files")) {
166  return;
167  }
168  // prepare types
169  myImportAllTypes = oc.getBool("opendrive.import-all-lanes");
170  myImportWidths = !oc.getBool("opendrive.ignore-widths");
171  myMinWidth = oc.getFloat("opendrive.min-width");
172  NBTypeCont& tc = nb.getTypeCont();
173  // build the handler
174  std::map<std::string, OpenDriveEdge*> edges;
175  NIImporter_OpenDrive handler(nb.getTypeCont(), edges);
176  // parse file(s)
177  std::vector<std::string> files = oc.getStringVector("opendrive-files");
178  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
179  if (!FileHelpers::isReadable(*file)) {
180  WRITE_ERROR("Could not open opendrive file '" + *file + "'.");
181  return;
182  }
183  handler.setFileName(*file);
184  PROGRESS_BEGIN_MESSAGE("Parsing opendrive from '" + *file + "'");
185  XMLSubSys::runParser(handler, *file);
187  }
188  // split inner/outer edges
189  std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
190  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
191  if ((*i).second->isInner) {
192  innerEdges[(*i).first] = (*i).second;
193  } else {
194  outerEdges[(*i).first] = (*i).second;
195  }
196  }
197 
198  // convert geometries into a discretised representation
199  computeShapes(edges);
200  // check whether lane sections are valid and whether further must be introduced
201  revisitLaneSections(tc, edges);
202 
203  // -------------------------
204  // node building
205  // -------------------------
206  // build nodes#1
207  // look at all links which belong to a node, collect their bounding boxes
208  // and place the node in the middle of this bounding box
209  std::map<std::string, Boundary> posMap;
210  std::map<std::string, std::string> edge2junction;
211  // compute node positions
212  for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
213  OpenDriveEdge* e = (*i).second;
214  assert(e->junction != "-1" && e->junction != "");
215  edge2junction[e->id] = e->junction;
216  if (posMap.find(e->junction) == posMap.end()) {
217  posMap[e->junction] = Boundary();
218  }
219  posMap[e->junction].add(e->geom.getBoxBoundary());
220  }
221  // build nodes
222  for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
223  //std::cout << " import node=" << (*i).first << " z=" << (*i).second.getCenter() << " boundary=" << (*i).second << "\n";
224  if (!nb.getNodeCont().insert((*i).first, (*i).second.getCenter())) {
225  throw ProcessError("Could not add node '" + (*i).first + "'.");
226  }
227  }
228  // assign built nodes
229  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
230  OpenDriveEdge* e = (*i).second;
231  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
232  OpenDriveLink& l = *j;
233  const std::string& nid = l.elementID;
234  if (l.elementType != OPENDRIVE_ET_ROAD) {
235  if (nb.getNodeCont().retrieve(nid) == 0) {
236  // not yet seen, build (possibly a junction without connections)
237  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
238  if (!nb.getNodeCont().insert(nid, pos)) {
239  throw ProcessError("Could not build node '" + nid + "'.");
240  }
241  }
242  // set node information
244  continue;
245  }
246  if (edge2junction.find(l.elementID) != edge2junction.end()) {
247  // set node information of an internal road
248  setNodeSecure(nb.getNodeCont(), *e, edge2junction[l.elementID], l.linkType);
249  continue;
250  }
251  }
252  }
253  // we should now have all nodes set for links which are not outer edge-to-outer edge links
254 
255 
256  // build nodes#2
257  // build nodes for all outer edge-to-outer edge connections
258  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
259  OpenDriveEdge* e = (*i).second;
260  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
261  OpenDriveLink& l = *j;
262  if (l.elementType != OPENDRIVE_ET_ROAD || edge2junction.find(l.elementID) != edge2junction.end()) {
263  // is a connection to an internal edge, or a node, skip
264  continue;
265  }
266  // we have a direct connection between to external edges
267  std::string id1 = e->id;
268  std::string id2 = l.elementID;
269  if (id1 < id2) {
270  std::swap(id1, id2);
271  }
272  std::string nid = id1 + "." + id2;
273  if (nb.getNodeCont().retrieve(nid) == 0) {
274  // not yet seen, build
275  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
276  if (!nb.getNodeCont().insert(nid, pos)) {
277  throw ProcessError("Could not build node '" + nid + "'.");
278  }
279  }
280  /* debug-stuff
281  else {
282  Position pos = l.linkType==OPENDRIVE_LT_SUCCESSOR ? e.geom[e.geom.size()-1] : e.geom[0];
283  cout << nid << " " << pos << " " << nb.getNodeCont().retrieve(nid)->getPosition() << endl;
284  }
285  */
286  setNodeSecure(nb.getNodeCont(), *e, nid, l.linkType);
287  }
288  }
289  // we should now have start/end nodes for all outer edge-to-outer edge connections
290 
291 
292  // build nodes#3
293  // assign further nodes generated from inner-edges
294  // these nodes have not been assigned earlier, because the connections are referenced in inner-edges
295  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
296  OpenDriveEdge* e = (*i).second;
297  if (e->to != 0 && e->from != 0) {
298  continue;
299  }
300  for (std::map<std::string, OpenDriveEdge*>::iterator j = innerEdges.begin(); j != innerEdges.end(); ++j) {
301  OpenDriveEdge* ie = (*j).second;
302  for (std::vector<OpenDriveLink>::iterator k = ie->links.begin(); k != ie->links.end(); ++k) {
303  OpenDriveLink& il = *k;
304  if (il.elementType != OPENDRIVE_ET_ROAD || il.elementID != e->id) {
305  // not conneted to the currently investigated outer edge
306  continue;
307  }
308  std::string nid = edge2junction[ie->id];
309  if (il.contactPoint == OPENDRIVE_CP_START) {
311  } else {
313  }
314  }
315  }
316 
317  }
318 
319  // build start/end nodes which were not defined previously
320  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
321  OpenDriveEdge* e = (*i).second;
322  if ((e->from == 0 || e->to == 0) && e->geom.size() == 0) {
323  continue;
324  }
325  if (e->from == 0) {
326  const std::string nid = e->id + ".begin";
327  e->from = getOrBuildNode(nid, e->geom.front(), nb.getNodeCont());
328  }
329  if (e->to == 0) {
330  const std::string nid = e->id + ".end";
331  e->to = getOrBuildNode(nid, e->geom.back(), nb.getNodeCont());
332  }
333  }
334 
335 
336  // -------------------------
337  // edge building
338  // -------------------------
339  double defaultSpeed = tc.getSpeed("");
340  // build edges
341  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
342  OpenDriveEdge* e = (*i).second;
343  if (e->geom.size() == 0) {
344  WRITE_WARNING("Ignoring road '" + e->id + "' without geometry.");
345  continue;
346  }
347  bool lanesBuilt = false;
348 
349  // go along the lane sections, build a node in between of each pair
350 
353 
355  NBNode* sFrom = e->from;
356  NBNode* sTo = e->to;
357  int priorityR = e->getPriority(OPENDRIVE_TAG_RIGHT);
358  int priorityL = e->getPriority(OPENDRIVE_TAG_LEFT);
359  double sB = 0;
360  double sE = e->length;
361  // 0-length geometries are possible if only the inner points are represented
362  const double length2D = e->geom.length2D();
363  double cF = length2D == 0 ? 1 : e->length / length2D;
364  NBEdge* prevRight = 0;
365  NBEdge* prevLeft = 0;
366 
367  // starting at the same node as ending, and no lane sections?
368  if (sFrom == sTo && e->laneSections.size() == 1) {
369  // --> loop, split!
371  ls.s = e->length / 2.;
372  e->laneSections.push_back(ls);
373  WRITE_WARNING("Edge '" + e->id + "' has to be split as it connects same junctions.")
374  }
375  if (myMinWidth > 0) {
376  const double minDist = oc.getFloat("opendrive.curve-resolution");
377  splitMinWidths(e, tc, minDist);
378  }
379 
380  // build along lane sections
381  for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
382  // add internal node if needed
383  if (j == e->laneSections.end() - 1) {
384  sTo = e->to;
385  sE = e->length / cF;
386  } else {
387  double nextS = (j + 1)->s;
388  sTo = new NBNode(e->id + "." + toString(nextS), e->geom.positionAtOffset(nextS));
389  if (!nb.getNodeCont().insert(sTo)) {
390  throw ProcessError("Could not add node '" + sTo->getID() + "'.");
391  }
392  sE = nextS / cF;
393  }
394  PositionVector geom = e->geom.getSubpart2D(sB, sE);
395  std::string id = e->id;
396  if (sFrom != e->from || sTo != e->to) {
397  id = id + "." + toString((*j).s);
398  } else if (e->laneSections.size() == 1) {
399  id = id + ".0.00";
400  }
401 #ifdef DEBUG_VARIABLE_WIDTHS
402  if (DEBUG_COND(e)) {
403  std::cout << " id=" << id << " sB=" << sB << " sE=" << sE << " geom=" << geom << "\n";
404  }
405 #endif
406 
407  // build lanes to right
408  NBEdge* currRight = 0;
409  if ((*j).rightLaneNumber > 0) {
410  currRight = new NBEdge("-" + id, sFrom, sTo, (*j).rightType, defaultSpeed, (*j).rightLaneNumber, priorityR,
412  lanesBuilt = true;
413  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_RIGHT];
414  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
415  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
416  if (lp != (*j).laneMap.end()) {
417  int sumoLaneIndex = lp->second;
418  NBEdge::Lane& sumoLane = currRight->getLaneStruct(sumoLaneIndex);
419  const OpenDriveLane& odLane = *k;
420 
421  sumoLane.origID = e->id + "_" + toString((*k).id);
422  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
423  sumoLane.permissions = tc.getPermissions(odLane.type);
424  sumoLane.width = myImportWidths && odLane.width != NBEdge::UNSPECIFIED_WIDTH ? odLane.width : tc.getWidth(odLane.type);
425  if (sumoLane.width < myMinWidth
426  && sumoLane.permissions != SVC_BICYCLE
427  && sumoLane.permissions != SVC_PEDESTRIAN
428  && sumoLane.width < tc.getWidth(odLane.type)) {
430  }
431  }
432  }
433  if (!nb.getEdgeCont().insert(currRight, myImportAllTypes)) {
434  throw ProcessError("Could not add edge '" + currRight->getID() + "'.");
435  }
436  if (nb.getEdgeCont().wasIgnored(id)) {
437  prevRight = 0;
438  } else {
439  // connect lane sections
440  if (prevRight != 0) {
441  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_RIGHT, *(j - 1));
442  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
443 #ifdef DEBUG_CONNECTIONS
444  if (DEBUG_COND(e)) {
445  std::cout << "addCon1 from=" << prevRight->getID() << "_" << (*k).first << " to=" << currRight->getID() << "_" << (*k).second << "\n";
446  }
447 #endif
448  prevRight->addLane2LaneConnection((*k).first, currRight, (*k).second, NBEdge::L2L_VALIDATED);
449  }
450  }
451  prevRight = currRight;
452  }
453  }
454 
455  // build lanes to left
456  NBEdge* currLeft = 0;
457  if ((*j).leftLaneNumber > 0) {
458  currLeft = new NBEdge(id, sTo, sFrom, (*j).leftType, defaultSpeed, (*j).leftLaneNumber, priorityL,
460  lanesBuilt = true;
461  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_LEFT];
462  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
463  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
464  if (lp != (*j).laneMap.end()) {
465  int sumoLaneIndex = lp->second;
466  NBEdge::Lane& sumoLane = currLeft->getLaneStruct(sumoLaneIndex);
467  const OpenDriveLane& odLane = *k;
468 
469  sumoLane.origID = e->id + "_" + toString((*k).id);
470  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
471  sumoLane.permissions = tc.getPermissions(odLane.type);
472  sumoLane.width = myImportWidths && odLane.width != NBEdge::UNSPECIFIED_WIDTH ? odLane.width : tc.getWidth(odLane.type);
473  if (sumoLane.width < myMinWidth
474  && sumoLane.permissions != SVC_BICYCLE
475  && sumoLane.permissions != SVC_PEDESTRIAN
476  && sumoLane.width < tc.getWidth(odLane.type)) {
478  }
479  }
480  }
481  if (!nb.getEdgeCont().insert(currLeft, myImportAllTypes)) {
482  throw ProcessError("Could not add edge '" + currLeft->getID() + "'.");
483  }
484  if (nb.getEdgeCont().wasIgnored(id)) {
485  prevLeft = 0;
486  } else {
487  // connect lane sections
488  if (prevLeft != 0) {
489  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_LEFT, *(j - 1));
490  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
491 #ifdef DEBUG_CONNECTIONS
492  if (DEBUG_COND(e)) {
493  std::cout << "addCon2 from=" << currLeft->getID() << "_" << (*k).first << " to=" << prevLeft->getID() << "_" << (*k).second << "\n";
494  }
495 #endif
496  currLeft->addLane2LaneConnection((*k).first, prevLeft, (*k).second, NBEdge::L2L_VALIDATED);
497  }
498  }
499  prevLeft = currLeft;
500  }
501  }
502  (*j).sumoID = id;
503 
504 
505  sB = sE;
506  sFrom = sTo;
507  }
508  if (!lanesBuilt) {
509  WRITE_WARNING("Edge '" + e->id + "' has no lanes.");
510  }
511  }
512 
513  // -------------------------
514  // connections building
515  // -------------------------
516  // generate explicit lane-to-lane connections
517  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
518  setEdgeLinks2(*(*i).second, edges);
519  }
520  // compute connections across intersections, if any
521  std::vector<Connection> connections2;
522  for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
523  const std::set<Connection>& conns = (*j).second->connections;
524 
525  for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
526  if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
527  // connections starting at inner edges are processed by starting from outer edges
528  continue;
529  }
530  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
531  std::set<Connection> seen;
532  buildConnectionsToOuter(*i, innerEdges, connections2, seen);
533  } else {
534  connections2.push_back(*i);
535  }
536  }
537  }
538  // set connections
539  for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
540  std::string fromEdge = (*i).fromEdge;
541  if (edges.find(fromEdge) == edges.end()) {
542  WRITE_WARNING("While setting connections: from-edge '" + fromEdge + "' is not known.");
543  continue;
544  }
545  OpenDriveEdge* odFrom = edges[fromEdge];
546  int fromLane = (*i).fromLane;
547  bool fromLast = ((*i).fromCP == OPENDRIVE_CP_END) ^ ((*i).fromLane > 0 && !(*i).all);
548  fromEdge = fromLast ? odFrom->laneSections.back().sumoID : odFrom->laneSections[0].sumoID;
549 
550  std::string toEdge = (*i).toEdge;
551  if (edges.find(toEdge) == edges.end()) {
552  WRITE_WARNING("While setting connections: to-edge '" + toEdge + "' is not known.");
553  continue;
554  }
555 
556  OpenDriveEdge* odTo = edges[toEdge];
557  int toLane = (*i).toLane;
558  bool toLast = ((*i).toCP == OPENDRIVE_CP_END) || ((*i).toLane > 0);
559  toEdge = toLast ? odTo->laneSections.back().sumoID : odTo->laneSections[0].sumoID;
560 
561  if (fromLane == UNSET_CONNECTION) {
562  continue;
563  }
564  if (fromLane < 0) {
565  fromEdge = revertID(fromEdge);
566  }
567  if (toLane == UNSET_CONNECTION) {
568  continue;
569  }
570  if (toLane < 0) {
571  toEdge = revertID(toEdge);
572  }
573  fromLane = fromLast ? odFrom->laneSections.back().laneMap[fromLane] : odFrom->laneSections[0].laneMap[fromLane];
574  toLane = toLast ? odTo->laneSections.back().laneMap[toLane] : odTo->laneSections[0].laneMap[toLane];
575  NBEdge* from = nb.getEdgeCont().retrieve(fromEdge);
576  NBEdge* to = nb.getEdgeCont().retrieve(toEdge);
577  if (from == 0) {
578  WRITE_WARNING("Could not find fromEdge representation of '" + fromEdge + "' in connection '" + (*i).origID + "'.");
579  }
580  if (to == 0) {
581  WRITE_WARNING("Could not find fromEdge representation of '" + toEdge + "' in connection '" + (*i).origID + "'.");
582  }
583  if (from == 0 || to == 0) {
584  continue;
585  }
586 
587 #ifdef DEBUG_CONNECTIONS
588  if (DEBUG_COND2(from->getID())) {
589  std::cout << "addCon3 from=" << from->getID() << "_" << fromLane << " to=" << to->getID() << "_" << toLane << "\n";
590  }
591 #endif
592  from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER);
593 
594  if ((*i).origID != "") {
595  // @todo: this is the most silly way to determine the connection
596  std::vector<NBEdge::Connection>& cons = from->getConnections();
597  for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
598  if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
599  (*k).origID = (*i).origID + "_" + toString((*i).origLane);
600  break;
601  }
602  }
603  }
604  }
605 
606 
607  // -------------------------
608  // traffic lights
609  // -------------------------
610  std::map<std::string, std::string> tlsControlled;
611  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
612  OpenDriveEdge* e = (*i).second;
613  for (std::vector<OpenDriveSignal>::const_iterator j = e->signals.begin(); j != e->signals.end(); ++j) {
614  if ((*j).type != "1000001") { // traffic_light (Section 6.11)
615  continue;
616  }
617  std::vector<OpenDriveLaneSection>::iterator k = e->laneSections.begin();
618  bool found = false;
619  for (; k != e->laneSections.end() - 1 && !found;) {
620  if ((*j).s > (*k).s && (*j).s <= (*(k + 1)).s) {
621  found = true;
622  } else {
623  ++k;
624  }
625  }
626 
627  // @todo: major problem, currently, still not completely solved:
628  // inner edges may have traffic lights, too. Nice on one hand, as directions can be recognized
629  // but hard to follow backwards
630  std::string id = (*k).sumoID;
631  if (id == "") {
632  if (e->junction != "") {
633  //WRITE_WARNING("Found a traffic light signal on an internal edge; will not build it (original edge id='" + e->id + "').");
634  std::string fromID, toID;
635  for (std::vector<OpenDriveLink>::const_iterator l = e->links.begin(); l != e->links.end(); ++l) {
636  if ((*l).linkType == OPENDRIVE_LT_PREDECESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
637  if (fromID != "") {
638  WRITE_WARNING("Ambigous start of connection.");
639  }
640  OpenDriveEdge* e = edges[(*l).elementID];
641  if ((*l).contactPoint == OPENDRIVE_CP_START) {
642  fromID = e->laneSections[0].sumoID;
643  if ((*j).orientation < 0) {
644  fromID = "-" + fromID;
645  }
646  } else {
647  fromID = e->laneSections.back().sumoID;
648  if ((*j).orientation > 0) {
649  fromID = "-" + fromID;
650  }
651  }
652  }
653  if ((*l).linkType == OPENDRIVE_LT_SUCCESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
654  if (toID != "") {
655  WRITE_WARNING("Ambigous end of connection.");
656  }
657  OpenDriveEdge* e = edges[(*l).elementID];
658  toID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
659  }
660  }
661  id = fromID + "->" + toID;
662  } else {
663  WRITE_WARNING("Found a traffic light signal on an unknown edge (original edge id='" + e->id + "').");
664  continue;
665  }
666  } else {
667  if ((*j).orientation > 0) {
668  id = "-" + id;
669  }
670  }
671  tlsControlled[id] = (*j).name;
672  }
673  }
674 
675  for (std::map<std::string, std::string>::iterator i = tlsControlled.begin(); i != tlsControlled.end(); ++i) {
676  std::string id = (*i).first;
677  if (id.find("->") != std::string::npos) {
678  id = id.substr(0, id.find("->"));
679  }
680  NBEdge* e = nb.getEdgeCont().retrieve(id);
681  if (e == 0) {
682  WRITE_WARNING("Could not find edge '" + id + "' while building its traffic light.");
683  continue;
684  }
685  NBNode* toNode = e->getToNode();
686  if (!toNode->isTLControlled()) {
688  NBOwnTLDef* tlDef = new NBOwnTLDef(toNode->getID(), toNode, 0, type);
689  if (!nb.getTLLogicCont().insert(tlDef)) {
690  // actually, nothing should fail here
691  delete tlDef;
692  throw ProcessError();
693  }
694  toNode->addTrafficLight(tlDef);
695  //tlDef->setSinglePhase();
696  }
697  NBTrafficLightDefinition* tlDef = *toNode->getControllingTLS().begin();
698  tlDef->addParameter("connection:" + id, (*i).second);
699  }
700 
701  // -------------------------
702  // clean up
703  // -------------------------
704  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
705  delete(*i).second;
706  }
707 }
708 
709 
710 void
711 NIImporter_OpenDrive::buildConnectionsToOuter(const Connection& c, const std::map<std::string, OpenDriveEdge*>& innerEdges, std::vector<Connection>& into, std::set<Connection>& seen) {
712  //std::cout << "buildConnectionsToOuter "
713  // << " seen=" << seen.size()
714  // << " from=" << c.fromEdge
715  // << " to=" << c.toEdge
716  // << " fromLane=" << c.fromLane
717  // << " toLane=" << c.toLane
718  // << " fromCP=" << c.fromCP
719  // << " toCP=" << c.toCP
720  // << " all=" << c.all
721  // << " origID=" << c.origID
722  // << " origLane=" << c.origLane
723  // << " seenlist=";
724  //for (std::set<Connection>::const_iterator i = seen.begin(); i != seen.end(); ++i) {
725  // std::cout << (*i).fromEdge << "," << (*i).toEdge << " ";
726  //}
727  //std::cout << "\n";
728 
729  OpenDriveEdge* dest = innerEdges.find(c.toEdge)->second;
730  if (dest == 0) {
732  return;
733  }
734  seen.insert(c);
735  const std::set<Connection>& conts = dest->connections;
736  for (std::set<Connection>::const_iterator i = conts.begin(); i != conts.end(); ++i) {
737  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
738  std::vector<Connection> t;
739  if (seen.count(*i) == 0) {
740  buildConnectionsToOuter(*i, innerEdges, t, seen);
741  for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
742  // @todo this section is unverified
743  Connection cn = (*j);
744  cn.fromEdge = c.fromEdge;
745  cn.fromLane = c.fromLane;
746  cn.fromCP = c.fromCP;
747  cn.all = c.all; // @todo "all" is a hack trying to avoid the "from is zero" problem;
748  into.push_back(cn);
749  }
750  } else {
751  WRITE_WARNING("Circular connections in junction including roads '" + c.fromEdge + "' and '" + c.toEdge + "', loop size " + toString(seen.size()));
752  }
753  } else {
754  if ((*i).fromLane == c.toLane) {
755  Connection cn = (*i);
756  cn.fromEdge = c.fromEdge;
757  cn.fromLane = c.fromLane;
758  cn.fromCP = c.fromCP;
759  cn.all = c.all;
760  cn.origID = c.toEdge;
761  cn.origLane = c.toLane;
762  into.push_back(cn);
763  }
764  }
765  }
766 }
767 
768 
769 void
770 NIImporter_OpenDrive::setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges) {
771  for (std::vector<OpenDriveLink>::iterator i = e.links.begin(); i != e.links.end(); ++i) {
772  OpenDriveLink& l = *i;
773  if (l.elementType != OPENDRIVE_ET_ROAD) {
774  // we assume that links to nodes are later given as connections to edges
775  continue;
776  }
777  // get the right direction of the connected edge
778  std::string connectedEdge = l.elementID;
779  std::string edgeID = e.id;
780 
781  OpenDriveLaneSection& laneSection = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e.laneSections.back() : e.laneSections[0];
782  const std::map<int, int>& laneMap = laneSection.laneMap;
783 #ifdef DEBUG_CONNECTIONS
784  if (DEBUG_COND(&e)) {
785  std::cout << "edge=" << e.id << " eType=" << l.elementType << " lType=" << l.linkType << " connectedEdge=" << connectedEdge << " laneSection=" << laneSection.s << " map:\n";
786  std::cout << joinToString(laneMap, "\n", ":") << "\n";
787  }
788 #endif
789  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
790  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
791  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
792  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
793  continue;
794  }
795  Connection c; // @todo: give Connection a new name and a constructor
796  c.fromEdge = e.id;
797  c.fromLane = (*j).id;
799  c.toLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
800  c.toEdge = connectedEdge;
801  c.toCP = l.contactPoint;
802  c.all = false;
803  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
804  std::swap(c.fromEdge, c.toEdge);
805  std::swap(c.fromLane, c.toLane);
806  std::swap(c.fromCP, c.toCP);
807  }
808  if (edges.find(c.fromEdge) == edges.end()) {
809  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
810  } else {
811  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
812  src->connections.insert(c);
813 #ifdef DEBUG_CONNECTIONS
814  if (DEBUG_COND(src) std::cout << "insertConRight from=" << src->id << "_" << c.fromLane << " to=" << c.toEdge << "_" << c.toLane << "\n";
815 #endif
816  }
817  }
818  }
819  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
820  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
821  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
822  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
823  continue;
824  }
825  Connection c;
826  c.toEdge = e.id;
827  c.toLane = (*j).id;
829  c.fromLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
830  c.fromEdge = connectedEdge;
831  c.fromCP = l.contactPoint;
832  c.all = false;
833  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
834  std::swap(c.fromEdge, c.toEdge);
835  std::swap(c.fromLane, c.toLane);
836  std::swap(c.fromCP, c.toCP);
837  }
838  if (edges.find(c.fromEdge) == edges.end()) {
839  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
840  } else {
841  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
842  src->connections.insert(c);
843 #ifdef DEBUG_CONNECTIONS
844  if (DEBUG_COND2(src)) {
845  std::cout << "insertConLeft from=" << src->id << "_" << c.fromLane << " to=" << c.toEdge << "_" << c.toLane << "\n";
846  }
847 #endif
848  }
849  }
850  }
851  }
852 }
853 
854 
855 std::string NIImporter_OpenDrive::revertID(const std::string& id) {
856  if (id[0] == '-') {
857  return id.substr(1);
858  }
859  return "-" + id;
860 }
861 
862 
863 NBNode*
864 NIImporter_OpenDrive::getOrBuildNode(const std::string& id, const Position& pos,
865  NBNodeCont& nc) {
866  if (nc.retrieve(id) == 0) {
867  // not yet built; build now
868  if (!nc.insert(id, pos)) {
869  // !!! clean up
870  throw ProcessError("Could not add node '" + id + "'.");
871  }
872  }
873  return nc.retrieve(id);
874 }
875 
876 
877 void
879  const std::string& nodeID, NIImporter_OpenDrive::LinkType lt) {
880  NBNode* n = nc.retrieve(nodeID);
881  if (n == 0) {
882  throw ProcessError("Could not find node '" + nodeID + "'.");
883  }
884  if (lt == OPENDRIVE_LT_SUCCESSOR) {
885  if (e.to != 0 && e.to != n) {
886  throw ProcessError("Edge '" + e.id + "' has two end nodes.");
887  }
888  e.to = n;
889  } else {
890  if (e.from != 0 && e.from != n) {
891  throw ProcessError("Edge '" + e.id + "' has two start nodes.");
892  }
893  e.from = n;
894  }
895 }
896 
897 
898 void
899 NIImporter_OpenDrive::computeShapes(std::map<std::string, OpenDriveEdge*>& edges) {
901  const double res = oc.getFloat("opendrive.curve-resolution");
902  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
903  OpenDriveEdge& e = *(*i).second;
905  for (std::vector<OpenDriveGeometry>::iterator j = e.geometries.begin(); j != e.geometries.end(); ++j) {
906  OpenDriveGeometry& g = *j;
907  PositionVector geom;
908  switch (g.type) {
910  break;
911  case OPENDRIVE_GT_LINE:
912  geom = geomFromLine(e, g);
913  break;
914  case OPENDRIVE_GT_SPIRAL:
915  geom = geomFromSpiral(e, g, res);
916  break;
917  case OPENDRIVE_GT_ARC:
918  geom = geomFromArc(e, g, res);
919  break;
920  case OPENDRIVE_GT_POLY3:
921  geom = geomFromPoly(e, g, res);
922  break;
924  geom = geomFromParamPoly(e, g, res);
925  break;
926  default:
927  break;
928  }
929  if (e.geom.size() > 0 && prevType == OPENDRIVE_GT_LINE) {
930  // remove redundant end point of the previous geometry segment
931  // (the start point of the current segment should have the same value)
932  // this avoids geometry errors due to imprecision
933  if (!e.geom.back().almostSame(geom.front())) {
934  const int index = (int)(j - e.geometries.begin());
935  WRITE_WARNING("Mismatched geometry for edge '" + e.id + "' between geometry segments " + toString(index - 1) + " and " + toString(index) + ".");
936  }
937  e.geom.pop_back();
938  }
939  //std::cout << " adding geometry to road=" << e.id << " old=" << e.geom << " new=" << geom << "\n";
940  for (PositionVector::iterator k = geom.begin(); k != geom.end(); ++k) {
942  }
943  prevType = g.type;
944  }
945  if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
946  e.geom.removeDoublePoints(oc.getFloat("geometry.min-dist"), true);
947  }
949  WRITE_ERROR("Unable to project coordinates for edge '" + e.id + "'.");
950  }
951  // add z-data
952  int k = 0;
953  double pos = 0;
954  for (std::vector<OpenDriveElevation>::iterator j = e.elevations.begin(); j != e.elevations.end(); ++j) {
955  const OpenDriveElevation& el = *j;
956  const double sNext = (j + 1) == e.elevations.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
957  while (k < (int)e.geom.size() && pos < sNext) {
958  const double z = el.computeAt(pos);
959  //std::cout << " edge=" << e.id << " k=" << k << " sNext=" << sNext << " pos=" << pos << " z=" << z << " ds=" << ds << " el.s=" << el.s << "el.a=" << el.a << " el.b=" << el.b << " el.c=" << el.c << " el.d=" << el.d << "\n";
960  e.geom[k].add(0, 0, z);
961  k++;
962  if (k < (int)e.geom.size()) {
963  // XXX pos understimates the actual position since the
964  // actual geometry between k-1 and k could be curved
965  pos += e.geom[k - 1].distanceTo2D(e.geom[k]);
966  }
967  }
968  }
969  // add laneoffset
970  if (e.offsets.size() > 0) {
971  // make sure there are intermediate points for each offset-section
972  for (std::vector<OpenDriveLaneOffset>::iterator j = e.offsets.begin(); j != e.offsets.end(); ++j) {
973  const OpenDriveLaneOffset& el = *j;
974  // check wether we need to insert a new point at dist
975  Position pS = e.geom.positionAtOffset2D(el.s);
976  int iS = e.geom.indexOfClosest(pS);
977  // prevent close spacing to reduce impact of rounding errors in z-axis
978  if (pS.distanceTo2D(e.geom[iS]) > POSITION_EPS) {
979  e.geom.insertAtClosest(pS);
980  //std::cout << " edge=" << e.id << " inserting pos=" << pS << " s=" << el.s << " iS=" << iS << " dist=" << pS.distanceTo2D(e.geom[iS]) << "\n";
981  }
982  }
983  // XXX add further points for sections with non-constant offset
984  // shift each point orthogonally by the specified offset
985  int k = 0;
986  double pos = 0;
987  PositionVector geom2;
988  for (std::vector<OpenDriveLaneOffset>::iterator j = e.offsets.begin(); j != e.offsets.end(); ++j) {
989  const OpenDriveLaneOffset& el = *j;
990  const double sNext = (j + 1) == e.offsets.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
991  while (k < (int)e.geom.size() && pos < sNext) {
992  const double offset = el.computeAt(pos);
993  //std::cout << " edge=" << e.id << " k=" << k << " sNext=" << sNext << " pos=" << pos << " offset=" << offset << " ds=" << ds << " el.s=" << el.s << "el.a=" << el.a << " el.b=" << el.b << " el.c=" << el.c << " el.d=" << el.d << "\n";
994  if (fabs(offset) > POSITION_EPS) {
995  try {
996  PositionVector tmp = e.geom;
997  // XXX shifting the whole geometry is inefficient. could also use positionAtOffset(lateralOffset=...)
998  tmp.move2side(-offset);
999  //std::cout << " edge=" << e.id << " k=" << k << " offset=" << offset << " geom[k]=" << e.geom[k] << " tmp[k]=" << tmp[k] << " gSize=" << e.geom.size() << " tSize=" << tmp.size() << " geom=" << e.geom << " tmp=" << tmp << "\n";
1000  geom2.push_back(tmp[k]);
1001  } catch (InvalidArgument&) {
1002  geom2.push_back(e.geom[k]);
1003  }
1004  } else {
1005  geom2.push_back(e.geom[k]);
1006  }
1007  k++;
1008  if (k < (int)e.geom.size()) {
1009  // XXX pos understimates the actual position since the
1010  // actual geometry between k-1 and k could be curved
1011  pos += e.geom[k - 1].distanceTo2D(e.geom[k]);
1012  }
1013  }
1014  }
1015  assert(e.geom.size() == geom2.size());
1016  e.geom = geom2;
1017  }
1018  //std::cout << " loaded geometry " << e.id << "=" << e.geom << "\n";
1019  }
1020 }
1021 
1022 
1023 void
1024 NIImporter_OpenDrive::revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges) {
1025  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
1026  OpenDriveEdge& e = *(*i).second;
1027 #ifdef DEBUG_VARIABLE_SPEED
1028  if (DEBUG_COND(&e)) {
1029  gDebugFlag1 = true;
1030  std::cout << "revisitLaneSections e=" << e.id << "\n";
1031  }
1032 #endif
1033  std::vector<OpenDriveLaneSection>& laneSections = e.laneSections;
1034  // split by speed limits
1035  std::vector<OpenDriveLaneSection> newSections;
1036  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end(); ++j) {
1037  std::vector<OpenDriveLaneSection> splitSections;
1038  bool splitBySpeed = (*j).buildSpeedChanges(tc, splitSections);
1039  if (!splitBySpeed) {
1040  newSections.push_back(*j);
1041  } else {
1042  std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
1043  }
1044  }
1045 
1046  e.laneSections = newSections;
1047  laneSections = e.laneSections;
1048  double lastS = -1;
1049  // check whether the lane sections are in the right order
1050  bool sorted = true;
1051  for (std::vector<OpenDriveLaneSection>::const_iterator j = laneSections.begin(); j != laneSections.end() && sorted; ++j) {
1052  if ((*j).s <= lastS) {
1053  sorted = false;
1054  }
1055  lastS = (*j).s;
1056  }
1057  if (!sorted) {
1058  WRITE_WARNING("The sections of edge '" + e.id + "' are not sorted properly.");
1059  sort(e.laneSections.begin(), e.laneSections.end(), sections_by_s_sorter());
1060  }
1061  // check whether no duplicates of s-value occure
1062  lastS = -1;
1063  laneSections = e.laneSections;
1064  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end();) {
1065  bool simlarToLast = fabs((*j).s - lastS) < POSITION_EPS;
1066  lastS = (*j).s;
1067  if (simlarToLast) {
1068  WRITE_WARNING("Almost duplicate s-value '" + toString(lastS) + "' for lane sections occured at edge '" + e.id + "'; second entry was removed.");
1069  j = laneSections.erase(j);
1070  } else {
1071  ++j;
1072  }
1073  }
1074 #ifdef DEBUG_VARIABLE_SPEED
1075  gDebugFlag1 = false;
1076 #endif
1077  }
1078 }
1079 
1080 
1083  UNUSED_PARAMETER(e);
1084  PositionVector ret;
1085  ret.push_back(Position(g.x, g.y));
1086  ret.push_back(calculateStraightEndPoint(g.hdg, g.length, Position(g.x, g.y)));
1087  return ret;
1088 }
1089 
1090 
1093  UNUSED_PARAMETER(e);
1094  PositionVector ret;
1095  double curveStart = g.params[0];
1096  double curveEnd = g.params[1];
1097  try {
1098  double cDot = (curveEnd - curveStart) / g.length;
1099  if (cDot == 0 || g.length == 0) {
1100  WRITE_WARNING("Could not compute spiral geometry for edge '" + e.id + "' (cDot=" + toString(cDot) + " length=" + toString(g.length) + ").");
1101  ret.push_back(Position(g.x, g.y));
1102  }
1103  double sStart = curveStart / cDot;
1104  double sEnd = curveEnd / cDot;
1105  double x = 0;
1106  double y = 0;
1107  double t = 0;
1108  double tStart = 0;
1109  double s;
1110  odrSpiral(sStart, cDot, &x, &y, &tStart);
1111  for (s = sStart; s <= sEnd; s += resolution) {
1112  odrSpiral(s, cDot, &x, &y, &t);
1113  ret.push_back(Position(x, y));
1114  }
1115  if (s != sEnd /*&& ret.size() == 1*/) {
1116  odrSpiral(sEnd, cDot, &x, &y, &t);
1117  ret.push_back(Position(x, y));
1118  }
1119  //if (s != sEnd && ret.size() > 2) {
1120  // ret.pop_back();
1121  //}
1122  assert(ret.size() >= 2);
1123  assert(ret[0] != ret[1]);
1124  // shift start to coordinate origin
1125  PositionVector ret1 = ret;
1126  ret.add(ret.front() * -1);
1127  // rotate
1128  PositionVector ret2 = ret;
1129  ret.rotate2D(g.hdg - tStart);
1130 #ifdef DEBUG_SPIRAL
1131  std::cout
1132  << std::setprecision(4)
1133  << "edge=" << e.id << " s=" << g.s
1134  << " cStart=" << curveStart
1135  << " cEnd=" << curveEnd
1136  << " cDot=" << cDot
1137  << " sStart=" << sStart
1138  << " sEnd=" << sEnd
1139  << " g.hdg=" << GeomHelper::naviDegree(g.hdg)
1140  << " tStart=" << GeomHelper::naviDegree(tStart)
1141  << "\n beforeShift=" << ret1
1142  << "\n beforeRot=" << ret2
1143  << "\n";
1144 #endif
1145  // shift to geometry start
1146  ret.add(g.x, g.y, 0);
1147  } catch (const std::runtime_error& error) {
1148  WRITE_WARNING("Could not compute spiral geometry for edge '" + e.id + "' (" + error.what() + ").");
1149  ret.push_back(Position(g.x, g.y));
1150  }
1151  return ret.getSubpart2D(0, g.length);
1152 }
1153 
1154 
1157  UNUSED_PARAMETER(e);
1158  PositionVector ret;
1159  double dist = 0.0;
1160  double centerX = g.x;
1161  double centerY = g.y;
1162  // left: positive value
1163  double curvature = g.params[0];
1164  double radius = 1. / curvature;
1165  // center point
1166  calculateCurveCenter(&centerX, &centerY, radius, g.hdg);
1167  double endX = g.x;
1168  double endY = g.y;
1169  double startX = g.x;
1170  double startY = g.y;
1171  double geo_posS = g.s;
1172  double geo_posE = g.s;
1173  bool end = false;
1174  do {
1175  geo_posE += resolution;
1176  if (geo_posE - g.s > g.length) {
1177  geo_posE = g.s + g.length;
1178  }
1179  if (geo_posE - g.s > g.length) {
1180  geo_posE = g.s + g.length;
1181  }
1182  calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
1183 
1184  dist += (geo_posE - geo_posS);
1185  //
1186  ret.push_back(Position(startX, startY));
1187  //
1188  startX = endX;
1189  startY = endY;
1190  geo_posS = geo_posE;
1191 
1192  if (geo_posE - (g.s + g.length) < 0.001 && geo_posE - (g.s + g.length) > -0.001) {
1193  end = true;
1194  }
1195  } while (!end);
1196  return ret.getSubpart2D(0, g.length);
1197 }
1198 
1199 
1202  UNUSED_PARAMETER(e);
1203  const double s = sin(g.hdg);
1204  const double c = cos(g.hdg);
1205  PositionVector ret;
1206  for (double off = 0; off < g.length + 2.; off += resolution) {
1207  double x = off;
1208  double y = g.params[0] + g.params[1] * off + g.params[2] * pow(off, 2.) + g.params[3] * pow(off, 3.);
1209  double xnew = x * c - y * s;
1210  double ynew = x * s + y * c;
1211  ret.push_back(Position(g.x + xnew, g.y + ynew));
1212  }
1213  return ret.getSubpart2D(0, g.length);
1214 }
1215 
1216 
1219  UNUSED_PARAMETER(e);
1220  const double s = sin(g.hdg);
1221  const double c = cos(g.hdg);
1222  const double pMax = g.params[8] <= 0 ? g.length : g.params[8];
1223  const double pStep = pMax / ceil(g.length / resolution);
1224  PositionVector ret;
1225  for (double p = 0; p <= pMax + pStep; p += pStep) {
1226  double x = g.params[0] + g.params[1] * p + g.params[2] * pow(p, 2.) + g.params[3] * pow(p, 3.);
1227  double y = g.params[4] + g.params[5] * p + g.params[6] * pow(p, 2.) + g.params[7] * pow(p, 3.);
1228  double xnew = x * c - y * s;
1229  double ynew = x * s + y * c;
1230  ret.push_back(Position(g.x + xnew, g.y + ynew));
1231  }
1232  return ret.getSubpart2D(0, g.length);
1233 }
1234 
1235 
1236 Position
1237 NIImporter_OpenDrive::calculateStraightEndPoint(double hdg, double length, const Position& start) {
1238  double normx = 1.0f;
1239  double normy = 0.0f;
1240  double x2 = normx * cos(hdg) - normy * sin(hdg);
1241  double y2 = normx * sin(hdg) + normy * cos(hdg);
1242  normx = x2 * length;
1243  normy = y2 * length;
1244  return Position(start.x() + normx, start.y() + normy);
1245 }
1246 
1247 
1248 void
1249 NIImporter_OpenDrive::calculateCurveCenter(double* ad_x, double* ad_y, double ad_radius, double ad_hdg) {
1250  double normX = 1.0;
1251  double normY = 0.0;
1252  double tmpX;
1253  double turn;
1254  if (ad_radius > 0) {
1255  turn = -1.0;
1256  } else {
1257  turn = 1.0;
1258  }
1259 
1260  tmpX = normX;
1261  normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
1262  normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
1263 
1264  tmpX = normX;
1265  normX = turn * normY;
1266  normY = -turn * tmpX;
1267 
1268  normX = fabs(ad_radius) * normX;
1269  normY = fabs(ad_radius) * normY;
1270 
1271  *ad_x += normX;
1272  *ad_y += normY;
1273 }
1274 
1275 
1276 void
1277 NIImporter_OpenDrive::calcPointOnCurve(double* ad_x, double* ad_y, double ad_centerX, double ad_centerY,
1278  double ad_r, double ad_length) {
1279  double rotAngle = ad_length / fabs(ad_r);
1280  double vx = *ad_x - ad_centerX;
1281  double vy = *ad_y - ad_centerY;
1282  double tmpx;
1283 
1284  double turn;
1285  if (ad_r > 0) {
1286  turn = -1; //left
1287  } else {
1288  turn = 1; //right
1289  }
1290  tmpx = vx;
1291  vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
1292  vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
1293  *ad_x = vx + ad_centerX;
1294  *ad_y = vy + ad_centerY;
1295 }
1296 
1297 
1298 // ---------------------------------------------------------------------------
1299 // section
1300 // ---------------------------------------------------------------------------
1302  lanesByDir[OPENDRIVE_TAG_LEFT] = std::vector<OpenDriveLane>();
1303  lanesByDir[OPENDRIVE_TAG_RIGHT] = std::vector<OpenDriveLane>();
1304  lanesByDir[OPENDRIVE_TAG_CENTER] = std::vector<OpenDriveLane>();
1305 }
1306 
1307 
1308 void
1310  int sumoLane = 0;
1311  bool singleType = true;
1312  std::vector<std::string> types;
1313  const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
1314  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
1315  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1316  laneMap[(*i).id] = sumoLane++;
1317  types.push_back((*i).type);
1318  if (types.front() != types.back()) {
1319  singleType = false;
1320  }
1321  }
1322  }
1323  rightLaneNumber = sumoLane;
1324  rightType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
1325  sumoLane = 0;
1326  singleType = true;
1327  types.clear();
1328  const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
1329  for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
1330  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1331  laneMap[(*i).id] = sumoLane++;
1332  types.push_back((*i).type);
1333  if (types.front() != types.back()) {
1334  singleType = false;
1335  }
1336  }
1337  }
1338  leftLaneNumber = sumoLane;
1339  leftType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
1340 }
1341 
1342 
1343 std::map<int, int>
1345  std::map<int, int> ret;
1346  const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
1347  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
1348  std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
1349  if (toP == laneMap.end()) {
1350  // the current lane is not available in SUMO
1351  continue;
1352  }
1353  int to = (*toP).second;
1354  int from = UNSET_CONNECTION;
1355  if ((*i).predecessor != UNSET_CONNECTION) {
1356  from = (*i).predecessor;
1357  }
1358  if (from != UNSET_CONNECTION) {
1359  std::map<int, int>::const_iterator fromP = prev.laneMap.find(from);
1360  if (fromP != prev.laneMap.end()) {
1361  from = (*fromP).second;
1362  } else {
1363  from = UNSET_CONNECTION;
1364  }
1365  }
1366  if (from != UNSET_CONNECTION && to != UNSET_CONNECTION) {
1367  if (ret.find(from) != ret.end()) {
1368 // WRITE_WARNING("double connection");
1369  }
1370  if (dir == OPENDRIVE_TAG_LEFT) {
1371  std::swap(from, to);
1372  }
1373  ret[from] = to;
1374  } else {
1375 // WRITE_WARNING("missing connection");
1376  }
1377  }
1378  return ret;
1379 }
1380 
1381 
1384  OpenDriveLaneSection ret(*this);
1385  ret.s += startPos;
1386  for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_RIGHT].size(); ++k) {
1388  l.speed = 0;
1389  std::vector<std::pair<double, double> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1390  if (i != l.speeds.end()) {
1391  l.speed = (*i).second;
1392  }
1393  }
1394  for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_LEFT].size(); ++k) {
1396  std::vector<std::pair<double, double> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1397  l.speed = 0;
1398  if (i != l.speeds.end()) {
1399  l.speed = (*i).second;
1400  }
1401  }
1402  return ret;
1403 }
1404 
1405 
1406 bool
1407 NIImporter_OpenDrive::OpenDriveLaneSection::buildSpeedChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections) {
1408  std::set<double> speedChangePositions;
1409  // collect speed change positions and apply initial speed to the begin
1410  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_RIGHT].begin(); k != lanesByDir[OPENDRIVE_TAG_RIGHT].end(); ++k) {
1411  for (std::vector<std::pair<double, double> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1412  speedChangePositions.insert((*l).first);
1413  if ((*l).first == 0) {
1414  (*k).speed = (*l).second;
1415  }
1416  }
1417  }
1418  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_LEFT].begin(); k != lanesByDir[OPENDRIVE_TAG_LEFT].end(); ++k) {
1419  for (std::vector<std::pair<double, double> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1420  speedChangePositions.insert((*l).first);
1421  if ((*l).first == 0) {
1422  (*k).speed = (*l).second;
1423  }
1424  }
1425  }
1426  // do nothing if there is none
1427  if (speedChangePositions.size() == 0) {
1428  return false;
1429  }
1430  if (*speedChangePositions.begin() > 0) {
1431  speedChangePositions.insert(0);
1432  }
1433 #ifdef DEBUG_VARIABLE_SPEED
1434  if (gDebugFlag1) std::cout
1435  << " buildSpeedChanges sectionStart=" << s
1436  << " speedChangePositions=" << joinToString(speedChangePositions, ", ")
1437  << "\n";
1438 #endif
1439  for (std::set<double>::iterator i = speedChangePositions.begin(); i != speedChangePositions.end(); ++i) {
1440  if (i == speedChangePositions.begin()) {
1441  newSections.push_back(*this);
1442  } else {
1443  newSections.push_back(buildLaneSection(*i));
1444  }
1445  }
1446  // propagate speeds
1447  for (int i = 0; i != (int)newSections.size(); ++i) {
1448  OpenDriveLaneSection& ls = newSections[i];
1449  std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >& lanesByDir = ls.lanesByDir;
1450  for (std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >::iterator k = lanesByDir.begin(); k != lanesByDir.end(); ++k) {
1451  std::vector<OpenDriveLane>& lanes = (*k).second;
1452  for (int j = 0; j != (int)lanes.size(); ++j) {
1453  OpenDriveLane& l = lanes[j];
1454  if (l.speed != 0) {
1455  continue;
1456  }
1457  if (i > 0) {
1458  l.speed = newSections[i - 1].lanesByDir[(*k).first][j].speed;
1459  } else {
1460  tc.getSpeed(l.type);
1461  }
1462  }
1463  }
1464  }
1465  return true;
1466 }
1467 
1468 
1469 
1470 // ---------------------------------------------------------------------------
1471 // edge
1472 // ---------------------------------------------------------------------------
1473 int
1475  // for signal interpretations see https://de.wikipedia.org/wiki/Bildtafel_der_Verkehrszeichen_in_der_Bundesrepublik_Deutschland_seit_2013
1476  int prio = 1;
1477  for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
1478  int tmp = 1;
1479  if ((*i).type == "301" || (*i).type == "306") { // priority road or local priority
1480  tmp = 2;
1481  }
1482  if ((*i).type == "205" /*|| (*i).type == "206"*/) { // yield or stop
1483  tmp = 0;
1484  }
1485  if (tmp != 1 && dir == OPENDRIVE_TAG_RIGHT && (*i).orientation > 0) {
1486  prio = tmp;
1487  }
1488  if (tmp != 1 && dir == OPENDRIVE_TAG_LEFT && (*i).orientation < 0) {
1489  prio = tmp;
1490  }
1491 
1492  }
1493  return prio;
1494 }
1495 
1496 
1497 
1498 // ---------------------------------------------------------------------------
1499 // loader methods
1500 // ---------------------------------------------------------------------------
1501 NIImporter_OpenDrive::NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges)
1503  myTypeContainer(tc), myCurrentEdge("", "", "", -1), myEdges(edges) {
1504 }
1505 
1506 
1508 }
1509 
1510 
1511 void
1513  const SUMOSAXAttributes& attrs) {
1514  bool ok = true;
1515  switch (element) {
1516  case OPENDRIVE_TAG_HEADER: {
1517  int majorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMAJOR, 0, ok);
1518  int minorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMINOR, 0, ok);
1519  if (majorVersion != 1 || minorVersion != 2) {
1520  // TODO: leave note of exceptions
1521  WRITE_WARNING("Given openDrive file '" + getFileName() + "' uses version " + toString(majorVersion) + "." + toString(minorVersion) + ";\n Version 1.2 is supported.");
1522  }
1523  }
1524  break;
1525  case OPENDRIVE_TAG_ROAD: {
1526  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, 0, ok);
1527  std::string streetName = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, 0, ok, "", false);
1528  std::string junction = attrs.get<std::string>(OPENDRIVE_ATTR_JUNCTION, id.c_str(), ok);
1529  double length = attrs.get<double>(OPENDRIVE_ATTR_LENGTH, id.c_str(), ok);
1530  myCurrentEdge = OpenDriveEdge(id, streetName, junction, length);
1531  }
1532  break;
1534  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1535  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1536  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1537  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1538  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1539  : "end";
1540  addLink(OPENDRIVE_LT_PREDECESSOR, elementType, elementID, contactPoint);
1541  }
1542  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1543  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1544  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1545  l.predecessor = no;
1546  }
1547  }
1548  break;
1549  case OPENDRIVE_TAG_SUCCESSOR: {
1550  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1551  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1552  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1553  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1554  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1555  : "start";
1556  addLink(OPENDRIVE_LT_SUCCESSOR, elementType, elementID, contactPoint);
1557  }
1558  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1559  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1560  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1561  l.successor = no;
1562  }
1563  }
1564  break;
1565  case OPENDRIVE_TAG_GEOMETRY: {
1566  double length = attrs.get<double>(OPENDRIVE_ATTR_LENGTH, myCurrentEdge.id.c_str(), ok);
1567  double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1568  double x = attrs.get<double>(OPENDRIVE_ATTR_X, myCurrentEdge.id.c_str(), ok);
1569  double y = attrs.get<double>(OPENDRIVE_ATTR_Y, myCurrentEdge.id.c_str(), ok);
1570  double hdg = attrs.get<double>(OPENDRIVE_ATTR_HDG, myCurrentEdge.id.c_str(), ok);
1571  myCurrentEdge.geometries.push_back(OpenDriveGeometry(length, s, x, y, hdg));
1572  }
1573  break;
1574  case OPENDRIVE_TAG_ELEVATION: {
1575  double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1576  double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1577  double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
1578  double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
1579  double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
1580  myCurrentEdge.elevations.push_back(OpenDriveElevation(s, a, b, c, d));
1581  }
1582  break;
1583  case OPENDRIVE_TAG_LINE: {
1584  if (myElementStack.size() > 0 && myElementStack.back() == OPENDRIVE_TAG_GEOMETRY) {
1585  std::vector<double> vals;
1587  }
1588  }
1589  break;
1590  case OPENDRIVE_TAG_SPIRAL: {
1591  std::vector<double> vals;
1592  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVSTART, myCurrentEdge.id.c_str(), ok));
1593  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVEND, myCurrentEdge.id.c_str(), ok));
1595  }
1596  break;
1597  case OPENDRIVE_TAG_ARC: {
1598  std::vector<double> vals;
1599  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CURVATURE, myCurrentEdge.id.c_str(), ok));
1601  }
1602  break;
1603  case OPENDRIVE_TAG_POLY3: {
1604  std::vector<double> vals;
1605  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok));
1606  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok));
1607  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok));
1608  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok));
1610  }
1611  break;
1612  case OPENDRIVE_TAG_PARAMPOLY3: {
1613  std::vector<double> vals;
1614  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_AU, myCurrentEdge.id.c_str(), ok));
1615  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_BU, myCurrentEdge.id.c_str(), ok));
1616  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CU, myCurrentEdge.id.c_str(), ok));
1617  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_DU, myCurrentEdge.id.c_str(), ok));
1618  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_AV, myCurrentEdge.id.c_str(), ok));
1619  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_BV, myCurrentEdge.id.c_str(), ok));
1620  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_CV, myCurrentEdge.id.c_str(), ok));
1621  vals.push_back(attrs.get<double>(OPENDRIVE_ATTR_DV, myCurrentEdge.id.c_str(), ok));
1622  const std::string pRange = attrs.getOpt<std::string>(OPENDRIVE_ATTR_PRANGE, myCurrentEdge.id.c_str(), ok, "normalized", false);
1623  if (pRange == "normalized") {
1624  vals.push_back(1.0);
1625  } else if (pRange == "arcLength") {
1626  vals.push_back(-1.0);
1627  } else {
1628  WRITE_WARNING("Ignoring invalid pRange value '" + pRange + "' for road '" + myCurrentEdge.id + "'.");
1629  vals.push_back(1.0);
1630  }
1632  }
1633  break;
1635  double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1637  }
1638  break;
1639  case OPENDRIVE_TAG_LANEOFFSET: {
1640  double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1641  double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1642  double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
1643  double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
1644  double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
1645  myCurrentEdge.offsets.push_back(OpenDriveLaneOffset(s, a, b, c, d));
1646  }
1647  break;
1648  case OPENDRIVE_TAG_LEFT:
1650  break;
1651  case OPENDRIVE_TAG_CENTER:
1653  break;
1654  case OPENDRIVE_TAG_RIGHT:
1656  break;
1657  case OPENDRIVE_TAG_LANE: {
1658  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1659  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1660  std::string level = attrs.hasAttribute(OPENDRIVE_ATTR_LEVEL)
1661  ? attrs.get<std::string>(OPENDRIVE_ATTR_LEVEL, myCurrentEdge.id.c_str(), ok)
1662  : "";
1664  ls.lanesByDir[myCurrentLaneDirection].push_back(OpenDriveLane(id, level, type));
1665  }
1666  break;
1667  case OPENDRIVE_TAG_SIGNAL: {
1668  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1669  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1670  std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, myCurrentEdge.id.c_str(), ok, "", false);
1671  int orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, myCurrentEdge.id.c_str(), ok) == "-" ? -1 : 1;
1672  double s = attrs.get<double>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1673  bool dynamic = attrs.get<std::string>(OPENDRIVE_ATTR_DYNAMIC, myCurrentEdge.id.c_str(), ok) == "no" ? false : true;
1674  myCurrentEdge.signals.push_back(OpenDriveSignal(id, type, name, orientation, dynamic, s));
1675  }
1676  break;
1678  myCurrentJunctionID = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1679  break;
1680  case OPENDRIVE_TAG_CONNECTION: {
1681  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1682  myCurrentIncomingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_INCOMINGROAD, myCurrentJunctionID.c_str(), ok);
1684  std::string cp = attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentJunctionID.c_str(), ok);
1686  myConnectionWasEmpty = true;
1687  }
1688  break;
1689  case OPENDRIVE_TAG_LANELINK: {
1690  int from = attrs.get<int>(OPENDRIVE_ATTR_FROM, myCurrentJunctionID.c_str(), ok);
1691  int to = attrs.get<int>(OPENDRIVE_ATTR_TO, myCurrentJunctionID.c_str(), ok);
1692  Connection c;
1694  c.toEdge = myCurrentConnectingRoad;
1695  c.fromLane = from;
1696  c.toLane = to;
1697  c.fromCP = OPENDRIVE_CP_END;
1698  c.toCP = myCurrentContactPoint;
1699  c.all = false;
1700  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1701  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1702  } else {
1703  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1704  e->connections.insert(c);
1705  myConnectionWasEmpty = false;
1706  }
1707  }
1708  break;
1709  case OPENDRIVE_TAG_WIDTH: {
1710  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1711  const double s = attrs.get<double>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
1712  const double a = attrs.get<double>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1713  const double b = attrs.get<double>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
1714  const double c = attrs.get<double>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
1715  const double d = attrs.get<double>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
1716  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1717  l.width = MAX2(l.width, a);
1718  l.widthData.push_back(OpenDriveWidth(s, a, b, c, d));
1719 #ifdef DEBUG_VARIABLE_WIDTHS
1720  if (DEBUG_COND(&myCurrentEdge)) {
1721  std::cout << " road=" << myCurrentEdge.id
1722  << std::setprecision(gPrecision)
1723  << " junction=" << myCurrentEdge.junction
1724  << " section=" << myCurrentEdge.laneSections.size() - 1
1725  << " dir=" << myCurrentLaneDirection << " lane=" << l.id
1726  << " type=" << l.type
1727  << " width=" << l.width
1728  << " a=" << a
1729  << " b=" << b
1730  << " c=" << c
1731  << " d=" << d
1732  << " s=" << s
1733  << " entries=" << l.widthData.size()
1734  << "\n";
1735  }
1736 #endif
1737  }
1738  }
1739  break;
1740  case OPENDRIVE_TAG_SPEED: {
1741  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1742  double speed = attrs.get<double>(OPENDRIVE_ATTR_MAX, myCurrentEdge.id.c_str(), ok);
1743  double pos = attrs.get<double>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
1744  // required for xodr v1.4
1745  const std::string unit = attrs.getOpt<std::string>(OPENDRIVE_ATTR_UNIT, myCurrentEdge.id.c_str(), ok, "", false);
1746  // now convert the speed to reasonable default SI [m/s]
1747  if (!unit.empty()) {
1748  // something to be done at all ?
1749  if (unit == "km/h") {
1750  speed /= 3.6;
1751  }
1752  if (unit == "mph") {
1753  speed *= 1.609344 / 3.6;
1754  }
1755  // IGNORING unknown units.
1756  }
1757  myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().speeds.push_back(std::make_pair(pos, speed));
1758  }
1759  }
1760  break;
1761  default:
1762  break;
1763  }
1764  myElementStack.push_back(element);
1765 }
1766 
1767 
1768 void
1770  myElementStack.pop_back();
1771  switch (element) {
1772  case OPENDRIVE_TAG_ROAD:
1774  break;
1776  if (myConnectionWasEmpty) {
1777  Connection c;
1780  c.fromLane = 0;
1781  c.toLane = 0;
1784  c.all = true;
1785  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1786  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1787  } else {
1788  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1789  e->connections.insert(c);
1790  }
1791  }
1792  break;
1794  myCurrentEdge.laneSections.back().buildLaneMapping(myTypeContainer);
1795  }
1796  break;
1797  default:
1798  break;
1799  }
1800 }
1801 
1802 
1803 
1804 void
1805 NIImporter_OpenDrive::addLink(LinkType lt, const std::string& elementType,
1806  const std::string& elementID,
1807  const std::string& contactPoint) {
1808  OpenDriveLink l(lt, elementID);
1809  // elementType
1810  if (elementType == "road") {
1812  } else if (elementType == "junction") {
1814  }
1815  // contact point
1816  if (contactPoint == "start") {
1818  } else if (contactPoint == "end") {
1820  }
1821  // add
1822  myCurrentEdge.links.push_back(l);
1823 }
1824 
1825 
1826 void
1827 NIImporter_OpenDrive::addGeometryShape(GeometryType type, const std::vector<double>& vals) {
1828  // checks
1829  if (myCurrentEdge.geometries.size() == 0) {
1830  throw ProcessError("Mismatching paranthesis in geometry definition for road '" + myCurrentEdge.id + "'");
1831  }
1833  if (last.type != OPENDRIVE_GT_UNKNOWN) {
1834  throw ProcessError("Double geometry information for road '" + myCurrentEdge.id + "'");
1835  }
1836  // set
1837  last.type = type;
1838  last.params = vals;
1839 }
1840 
1841 
1842 bool
1844  if (c1.fromEdge != c2.fromEdge) {
1845  return c1.fromEdge < c2.fromEdge;
1846  }
1847  if (c1.toEdge != c2.toEdge) {
1848  return c1.toEdge < c2.toEdge;
1849  }
1850  if (c1.fromLane != c2.fromLane) {
1851  return c1.fromLane < c2.fromLane;
1852  }
1853  return c1.toLane < c2.toLane;
1854 }
1855 
1856 
1857 void
1859  std::vector<OpenDriveLaneSection> newSections;
1860 #ifdef DEBUG_VARIABLE_WIDTHS
1861  if (DEBUG_COND(e)) {
1862  gDebugFlag1 = true;
1863  std::cout << "splitMinWidths e=" << e->id << " sections=" << e->laneSections.size() << "\n";
1864  }
1865 #endif
1866  for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
1867  OpenDriveLaneSection& sec = *j;
1868  std::vector<double> splitPositions;
1869  const double sectionEnd = (j + 1) == e->laneSections.end() ? e->length : (*(j + 1)).s;
1870  const int section = (int)(j - e->laneSections.begin());
1871 #ifdef DEBUG_VARIABLE_WIDTHS
1872  if (DEBUG_COND(e)) {
1873  std::cout << " findWidthSplit section=" << section << " sectionStart=" << sec.s << " sectionOrigStart=" << sec.sOrig << " sectionEnd=" << sectionEnd << "\n";
1874  }
1875 #endif
1876  if (sec.rightLaneNumber > 0) {
1877  findWidthSplit(tc, sec.lanesByDir[OPENDRIVE_TAG_RIGHT], section, sec.sOrig, sectionEnd, splitPositions);
1878  }
1879  if (sec.leftLaneNumber > 0) {
1880  findWidthSplit(tc, sec.lanesByDir[OPENDRIVE_TAG_LEFT], section, sec.sOrig, sectionEnd, splitPositions);
1881  }
1882  newSections.push_back(sec);
1883  std::sort(splitPositions.begin(), splitPositions.end());
1884  // filter out tiny splits
1885  double prevSplit = sec.s;
1886  for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end();) {
1887  if ((*it) - prevSplit < minDist || sectionEnd - (*it) < minDist) {
1888  // avoid tiny (or duplicate) splits
1889 #ifdef DEBUG_VARIABLE_WIDTHS
1890  if (DEBUG_COND(e)) {
1891  std::cout << " skip close split=" << (*it) << " prevSplit=" << prevSplit << "\n";
1892  }
1893 #endif
1894  it = splitPositions.erase(it);
1895  } else if ((*it) < sec.s) {
1896  // avoid splits for another section
1897 #ifdef DEBUG_VARIABLE_WIDTHS
1898  if (DEBUG_COND(e)) {
1899  std::cout << " skip early split=" << (*it) << " s=" << sec.s << "\n";
1900  }
1901 #endif
1902  it = splitPositions.erase(it);
1903  } else {
1904  prevSplit = *it;
1905  it++;
1906  }
1907  }
1908 
1909  if (splitPositions.size() > 0) {
1910 #ifdef DEBUG_VARIABLE_WIDTHS
1911  if (DEBUG_COND(e)) {
1912  std::cout << " road=" << e->id << " splitMinWidths section=" << section
1913  << " start=" << sec.s
1914  << " origStart=" << sec.sOrig
1915  << " end=" << sectionEnd << " minDist=" << minDist
1916  << " splitPositions=" << toString(splitPositions) << "\n";
1917  }
1918 #endif
1919 #ifdef DEBUG_VARIABLE_WIDTHS
1920  if (DEBUG_COND(e)) {
1921  std::cout << "first section...\n";
1922  }
1923 #endif
1924  recomputeWidths(newSections.back(), sec.sOrig, splitPositions.front(), sec.sOrig, sectionEnd);
1925  for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end(); ++it) {
1926  OpenDriveLaneSection secNew = sec;
1927  secNew.s = *it;
1928 #ifdef DEBUG_VARIABLE_WIDTHS
1929  if (DEBUG_COND(e)) {
1930  std::cout << "splitAt " << secNew.s << "\n";
1931  }
1932 #endif
1933  newSections.push_back(secNew);
1934  if (secNew.rightLaneNumber > 0) {
1935  setStraightConnections(newSections.back().lanesByDir[OPENDRIVE_TAG_RIGHT]);
1936  }
1937  if (secNew.leftLaneNumber > 0) {
1938  setStraightConnections(newSections.back().lanesByDir[OPENDRIVE_TAG_LEFT]);
1939  }
1940  double end = (it + 1) == splitPositions.end() ? sectionEnd : *(it + 1);
1941  recomputeWidths(newSections.back(), secNew.s, end, sec.sOrig, sectionEnd);
1942  }
1943  }
1944  }
1945  gDebugFlag1 = false;
1946  e->laneSections = newSections;
1947 }
1948 
1949 
1950 void
1951 NIImporter_OpenDrive::findWidthSplit(const NBTypeCont& tc, std::vector<OpenDriveLane>& lanes,
1952  int section, double sectionStart, double sectionEnd,
1953  std::vector<double>& splitPositions) {
1954  UNUSED_PARAMETER(section);
1955  for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
1956  OpenDriveLane& l = *k;
1957  SVCPermissions permissions = tc.getPermissions(l.type) & ~(SVC_PEDESTRIAN | SVC_BICYCLE);
1958  if (l.widthData.size() > 0 && tc.knows(l.type) && !tc.getShallBeDiscarded(l.type) && permissions != 0) {
1959  double sPrev = l.widthData.front().s;
1960  double wPrev = l.widthData.front().computeAt(sPrev);
1961  if (gDebugFlag1) std::cout
1962  << "findWidthSplit section=" << section
1963  << " sectionStart=" << sectionStart
1964  << " sectionEnd=" << sectionEnd
1965  << " lane=" << l.id
1966  << " type=" << l.type
1967  << " widthEntries=" << l.widthData.size() << "\n"
1968  << " s=" << sPrev
1969  << " w=" << wPrev
1970  << "\n";
1971  for (std::vector<OpenDriveWidth>::iterator it_w = l.widthData.begin(); it_w != l.widthData.end(); ++it_w) {
1972  double sEnd = (it_w + 1) != l.widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
1973  double w = (*it_w).computeAt(sEnd);
1974  if (gDebugFlag1) std::cout
1975  << " sEnd=" << sEnd
1976  << " s=" << (*it_w).s
1977  << " a=" << (*it_w).a << " b=" << (*it_w).b << " c=" << (*it_w).c << " d=" << (*it_w).d
1978  << " w=" << w
1979  << "\n";
1980  const double changeDist = fabs(myMinWidth - wPrev);
1981  if (((wPrev < myMinWidth) && (w > myMinWidth))
1982  || ((wPrev > myMinWidth) && (w < myMinWidth))) {
1983  double splitPos = sPrev + (sEnd - sPrev) / fabs(w - wPrev) * changeDist;
1984  double wSplit = (*it_w).computeAt(splitPos);
1985  if (gDebugFlag1) {
1986  std::cout << " candidate splitPos=" << splitPos << " w=" << wSplit << "\n";
1987  }
1988  // ensure that the thin part is actually thin enough
1989  while (wSplit > myMinWidth) {
1990  if (wPrev < myMinWidth) {
1991  // getting wider
1992  splitPos -= POSITION_EPS;
1993  if (splitPos < sPrev) {
1994  if (gDebugFlag1) {
1995  std::cout << " aborting search splitPos=" << splitPos << " wSplit=" << wSplit << " sPrev=" << sPrev << " wPrev=" << wPrev << "\n";
1996  }
1997  splitPos = sPrev;
1998  break;
1999  }
2000  } else {
2001  // getting thinner
2002  splitPos += POSITION_EPS;
2003  if (splitPos > sEnd) {
2004  if (gDebugFlag1) {
2005  std::cout << " aborting search splitPos=" << splitPos << " wSplit=" << wSplit << " sEnd=" << sEnd << " w=" << w << "\n";
2006  }
2007  splitPos = sEnd;
2008  break;
2009  }
2010  }
2011  wSplit = (*it_w).computeAt(splitPos);
2012  if (gDebugFlag1) {
2013  std::cout << " refined splitPos=" << splitPos << " w=" << wSplit << "\n";
2014  }
2015  }
2016  splitPositions.push_back(sectionStart + splitPos);
2017  }
2018  // //wPrev = wSplit;
2019  //} else if ((fabs(wPrev) < NUMERICAL_EPS && w > POSITION_EPS)
2020  // || (wPrev > POSITION_EPS && fabs(w) < NUMERICAL_EPS)) {
2021  // splitPositions.push_back(sectionStart + sPrev);
2022  // if (gDebugFlag1) std::cout << " laneDisappears candidate splitPos=" << sPrev << " wPrev=" << wPrev << " w=" << w<< "\n";
2023  //}
2024  wPrev = w;
2025  sPrev = sEnd;
2026  }
2027  }
2028  }
2029 }
2030 
2031 
2032 void
2033 NIImporter_OpenDrive::setStraightConnections(std::vector<OpenDriveLane>& lanes) {
2034  for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
2035  (*k).predecessor = (*k).id;
2036  }
2037 }
2038 
2039 
2040 void
2041 NIImporter_OpenDrive::recomputeWidths(OpenDriveLaneSection& sec, double start, double end, double sectionStart, double sectionEnd) {
2042  if (sec.rightLaneNumber > 0) {
2043  recomputeWidths(sec.lanesByDir[OPENDRIVE_TAG_RIGHT], start, end, sectionStart, sectionEnd);
2044  }
2045  if (sec.leftLaneNumber > 0) {
2046  recomputeWidths(sec.lanesByDir[OPENDRIVE_TAG_LEFT], start, end, sectionStart, sectionEnd);
2047  }
2048 }
2049 
2050 
2051 void
2052 NIImporter_OpenDrive::recomputeWidths(std::vector<OpenDriveLane>& lanes, double start, double end, double sectionStart, double sectionEnd) {
2053  for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
2054  OpenDriveLane& l = *k;
2055  if (l.widthData.size() > 0) {
2056 #ifdef DEBUG_VARIABLE_WIDTHS
2057  if (gDebugFlag1) std::cout
2058  << "recomputeWidths lane=" << l.id
2059  << " type=" << l.type
2060  << " start=" << start
2061  << " end=" << end
2062  << " sectionStart=" << sectionStart
2063  << " sectionEnd=" << sectionEnd
2064  << " widthEntries=" << l.widthData.size() << "\n"
2065  << "\n";
2066 #endif
2067  l.width = 0;
2068  double sPrev = l.widthData.front().s;
2069  double sPrevAbs = sPrev + sectionStart;
2070  for (std::vector<OpenDriveWidth>::iterator it_w = l.widthData.begin(); it_w != l.widthData.end(); ++it_w) {
2071  double sEnd = (it_w + 1) != l.widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
2072  double sEndAbs = sEnd + sectionStart;
2073 #ifdef DEBUG_VARIABLE_WIDTHS
2074  if (gDebugFlag1) std::cout
2075  << " sPrev=" << sPrev << " sPrevAbs=" << sPrevAbs
2076  << " sEnd=" << sEnd << " sEndAbs=" << sEndAbs
2077  << " widthData s=" << (*it_w).s
2078  << " a=" << (*it_w).a
2079  << " b=" << (*it_w).b
2080  << " c=" << (*it_w).c
2081  << " d=" << (*it_w).d
2082  << "\n";
2083 #endif
2084  if (sPrevAbs <= start && sEndAbs >= start) {
2085 #ifdef DEBUG_VARIABLE_WIDTHS
2086  if (gDebugFlag1) {
2087  std::cout << " atStart=" << start << " pos=" << start - sectionStart << " w=" << (*it_w).computeAt(start - sectionStart) << "\n";
2088  }
2089 #endif
2090  l.width = MAX2(l.width, (*it_w).computeAt(start - sectionStart));
2091  }
2092  if (sPrevAbs <= end && sEndAbs >= end) {
2093 #ifdef DEBUG_VARIABLE_WIDTHS
2094  if (gDebugFlag1) {
2095  std::cout << " atEnd=" << end << " pos=" << end - sectionStart << " w=" << (*it_w).computeAt(end - sectionStart) << "\n";
2096  }
2097 #endif
2098  l.width = MAX2(l.width, (*it_w).computeAt(end - sectionStart));
2099  }
2100  if (start <= sPrevAbs && end >= sPrevAbs) {
2101 #ifdef DEBUG_VARIABLE_WIDTHS
2102  if (gDebugFlag1) {
2103  std::cout << " atSPrev=" << sPrev << " w=" << (*it_w).computeAt(sPrev) << "\n";
2104  }
2105 #endif
2106  l.width = MAX2(l.width, (*it_w).computeAt(sPrev));
2107  }
2108  if (start <= sEndAbs && end >= sEndAbs) {
2109 #ifdef DEBUG_VARIABLE_WIDTHS
2110  if (gDebugFlag1) {
2111  std::cout << " atSEnd=" << sEnd << " w=" << (*it_w).computeAt(sEnd) << "\n";
2112  }
2113 #endif
2114  l.width = MAX2(l.width, (*it_w).computeAt(sEnd));
2115  }
2116 #ifdef DEBUG_VARIABLE_WIDTHS
2117  if (gDebugFlag1) {
2118  std::cout << " sPrev=" << sPrev << " sEnd=" << sEnd << " l.width=" << l.width << "\n";
2119  }
2120 #endif
2121  sPrev = sEnd;
2122  sPrevAbs = sEndAbs;
2123  }
2124  }
2125  }
2126 }
2127 
2128 /****************************************************************************/
2129 
std::map< std::string, OpenDriveEdge * > & myEdges
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:33
std::vector< int > myElementStack
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
std::string rightType
the composite type built from all used lane types
double sOrig
The original starting offset of this lane section (differs from s if the section had to be split) ...
static PositionVector geomFromLine(const OpenDriveEdge &e, const OpenDriveGeometry &g)
static StringBijection< int >::Entry openDriveAttrs[]
The names of openDrive-XML attributes (for passing to GenericSAXHandler)
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:166
OpenDriveLaneSection buildLaneSection(double startPos)
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:250
is a pedestrian
std::vector< OpenDriveWidth > widthData
double computeAt(double pos) const
void addLink(LinkType lt, const std::string &elementType, const std::string &elementID, const std::string &contactPoint)
static PositionVector geomFromArc(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:54
std::string junction
The id of the junction the edge belongs to.
std::vector< OpenDriveElevation > elevations
static void calculateCurveCenter(double *ad_x, double *ad_y, double ad_radius, double ad_hdg)
GeometryType
OpenDrive geometry type enumeration.
int rightLaneNumber
The number of lanes on the right and on the left side, respectively.
int gPrecision
the precision for floating point outputs
Definition: StdDefs.cpp:30
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:291
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
double getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:217
double x() const
Returns the x-position.
Definition: Position.h:63
Representation of a lane section.
vehicle is a bicycle
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
Representation of an openDrive "link".
The base class for traffic light logic definitions.
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:259
ContactPoint myCurrentContactPoint
void odrSpiral(double s, double cDot, double *x, double *y, double *t)
Definition: odrSpiral.cpp:231
T MAX2(T a, T b)
Definition: StdDefs.h:74
std::map< OpenDriveXMLTag, std::vector< OpenDriveLane > > lanesByDir
The lanes, sorted by their direction.
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
static PositionVector geomFromPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
static void calcPointOnCurve(double *ad_x, double *ad_y, double ad_centerX, double ad_centerY, double ad_r, double ad_length)
double length
The length of the edge.
Poly3 OpenDriveElevation
LaneOffset has the same fields as Elevation.
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1161
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false)
Runs the given handler on the given file; returns if everything&#39;s ok.
Definition: XMLSubSys.cpp:110
friend bool operator<(const Connection &c1, const Connection &c2)
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:40
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:256
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
static NBNode * getOrBuildNode(const std::string &id, const Position &pos, NBNodeCont &nc)
Builds a node or returns the already built.
void error(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Handler for XML-errors.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
The connection was computed and validated.
Definition: NBEdge.h:115
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:65
authorities vehicles
static std::string revertID(const std::string &id)
static void findWidthSplit(const NBTypeCont &tc, std::vector< OpenDriveLane > &lanes, int section, double sectionStart, double sectionEnd, std::vector< double > &splitPositions)
PositionVector reverse() const
reverse position vector
OpenDriveXMLTag myCurrentLaneDirection
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:122
const std::string & getID() const
Returns the id.
Definition: Named.h:66
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:133
std::vector< OpenDriveLink > links
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:187
A handler which converts occuring elements and attributes into enums.
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
static PositionVector geomFromSpiral(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
static void buildConnectionsToOuter(const Connection &c, const std::map< std::string, OpenDriveEdge * > &innerEdges, std::vector< Connection > &into, std::set< Connection > &seen)
#define max(a, b)
Definition: polyfonts.c:65
const std::string & getFileName() const
returns the current file name
static void setStraightConnections(std::vector< OpenDriveLane > &lanes)
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:296
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:158
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
std::string type
The lane&#39;s type.
int getPriority(OpenDriveXMLTag dir) const
Returns the edge&#39;s priority, regarding the direction.
Encapsulated SAX-Attributes.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
static Position calculateStraightEndPoint(double hdg, double length, const Position &start)
static void recomputeWidths(OpenDriveLaneSection &sec, double start, double end, double sectionStart, double sectionEnd)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:156
std::string id
The id of the edge.
A list of positions.
int indexOfClosest(const Position &p) const
index of the closest position to p
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given SUMO file.
NIImporter_OpenDrive(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Constructor.
bool isUsableFileList(const std::string &name) const
Checks whether the named option is usable as a file list (with at least a single file) ...
bool buildSpeedChanges(const NBTypeCont &tc, std::vector< OpenDriveLaneSection > &newSections)
static void splitMinWidths(OpenDriveEdge *e, const NBTypeCont &tc, double minDist)
const NBTypeCont & myTypeContainer
double y() const
Returns the y-position.
Definition: Position.h:68
std::vector< OpenDriveLaneOffset > offsets
double speed
The lane&#39;s speed (set in post-processing)
std::vector< OpenDriveLaneSection > laneSections
std::map< int, int > laneMap
A mapping from OpenDrive to SUMO-index (the first is signed, the second unsigned) ...
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:202
#define POSITION_EPS
Definition: config.h:176
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
int insertAtClosest(const Position &p)
inserts p between the two closest positions and returns the insertion index
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
OpenDriveXMLTag
Numbers representing openDrive-XML - element names.
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:75
The connection was given by the user.
Definition: NBEdge.h:113
double speed
The speed allowed on this lane.
Definition: NBEdge.h:130
double width
This lane&#39;s width.
Definition: NBEdge.h:142
void move2side(double amount)
move position vector to side using certain ammount
static PositionVector geomFromParamPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
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< int >::Entry openDriveTags[]
The names of openDrive-XML elements (for passing to GenericSAXHandler)
std::string origID
An original ID, if given.
Definition: NBEdge.h:145
void buildLaneMapping(const NBTypeCont &tc)
Build the mapping from OpenDrive to SUMO lanes.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
std::vector< OpenDriveSignal > signals
LinkType
OpenDrive link type enumeration.
void addParameter(const std::string &key, const std::string &value)
Adds a parameter.
void rotate2D(double angle)
static void computeShapes(std::map< std::string, OpenDriveEdge * > &edges)
Computes a polygon representation of each edge&#39;s geometry.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:435
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:312
double length2D() const
Returns the length.
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:251
std::map< int, int > getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection &prev)
Returns the links from the previous to this lane section.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:161
Instance responsible for building networks.
Definition: NBNetBuilder.h:115
Representation of an OpenDrive geometry part.
bool getShallBeDiscarded(const std::string &type) const
Returns the information whether edges of this type shall be discarded.
Definition: NBTypeCont.cpp:199
A storage for options typed value containers)
Definition: OptionsCont.h:99
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:77
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:171
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:913
static void setEdgeLinks2(OpenDriveEdge &e, const std::map< std::string, OpenDriveEdge * > &edges)
std::vector< OpenDriveGeometry > geometries
Represents a single node (junction) during network building.
Definition: NBNode.h:75
void addGeometryShape(GeometryType type, const std::vector< double > &vals)
T get(const std::string &str) const
A class for sorting lane sections by their s-value.
#define DEBUG_COND
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
double getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:181
static void setNodeSecure(NBNodeCont &nc, OpenDriveEdge &e, const std::string &nodeID, NIImporter_OpenDrive::LinkType lt)
#define DEBUG_COND2(obj)
Definition: MSLane.cpp:86
void push_back_noDoublePos(const Position &p)
insert in back a non double position
A connection between two roads.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue, bool report=true) const
Tries to read given attribute assuming it is an int.
bool wasIgnored(std::string id) const
Returns whether the edge with the id was ignored during parsing.
Definition: NBEdgeCont.h:474
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:106
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:211
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
std::vector< std::pair< double, double > > speeds
List of positions/speeds of speed changes.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:203
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
void add(double xoff, double yoff, double zoff)
public emergency vehicles
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:835
Importer for networks stored in openDrive format.
double s
The starting offset of this lane section.
static double cn[6]
Definition: odrSpiral.cpp:63
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:237
bool exists(const std::string &name) const
Returns the information whether the named option is known.
#define UNSET_CONNECTION
TrafficLightType
A storage for available types of edges.
Definition: NBTypeCont.h:62
std::string streetName
The road name of the edge.
void myEndElement(int element)
Called when a closing tag occurs.
static void revisitLaneSections(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Rechecks lane sections of the given edges.