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-2016 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>
42 #include <netbuild/NBEdge.h>
43 #include <netbuild/NBEdgeCont.h>
44 #include <netbuild/NBNode.h>
45 #include <netbuild/NBNodeCont.h>
46 #include <netbuild/NBNetBuilder.h>
47 #include <netbuild/NBOwnTLDef.h>
55 #include <utils/xml/XMLSubSys.h>
56 #include <utils/geom/Boundary.h>
57 #include "NILoader.h"
58 #include "NIImporter_OpenDrive.h"
59 
60 #ifdef CHECK_MEMORY_LEAKS
61 #include <foreign/nvwa/debug_new.h>
62 #endif // CHECK_MEMORY_LEAKS
63 
64 
65 // ===========================================================================
66 // definitions
67 // ===========================================================================
68 #define C_LENGTH 10.
69 
70 // ===========================================================================
71 // static variables
72 // ===========================================================================
94 
96 };
97 
98 
130 
132 };
133 
134 
137 
138 // ===========================================================================
139 // method definitions
140 // ===========================================================================
141 // ---------------------------------------------------------------------------
142 // static methods (interface in this case)
143 // ---------------------------------------------------------------------------
144 void
146  // check whether the option is set (properly)
147  if (!oc.isUsableFileList("opendrive-files")) {
148  return;
149  }
150  // prepare types
151  myImportAllTypes = oc.getBool("opendrive.import-all-lanes");
152  myImportWidths = !oc.getBool("opendrive.ignore-widths");
153  NBTypeCont& tc = nb.getTypeCont();
154  // build the handler
155  std::map<std::string, OpenDriveEdge*> edges;
156  NIImporter_OpenDrive handler(nb.getTypeCont(), edges);
157  // parse file(s)
158  std::vector<std::string> files = oc.getStringVector("opendrive-files");
159  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
160  if (!FileHelpers::isReadable(*file)) {
161  WRITE_ERROR("Could not open opendrive file '" + *file + "'.");
162  return;
163  }
164  handler.setFileName(*file);
165  PROGRESS_BEGIN_MESSAGE("Parsing opendrive from '" + *file + "'");
166  XMLSubSys::runParser(handler, *file);
168  }
169  // split inner/outer edges
170  std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
171  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
172  if ((*i).second->isInner) {
173  innerEdges[(*i).first] = (*i).second;
174  } else {
175  outerEdges[(*i).first] = (*i).second;
176  }
177  }
178 
179  // convert geometries into a discretised representation
180  computeShapes(edges);
181  // check whether lane sections are valid and whether further must be introduced
182  revisitLaneSections(tc, edges);
183 
184  // -------------------------
185  // node building
186  // -------------------------
187  // build nodes#1
188  // look at all links which belong to a node, collect their bounding boxes
189  // and place the node in the middle of this bounding box
190  std::map<std::string, Boundary> posMap;
191  std::map<std::string, std::string> edge2junction;
192  // compute node positions
193  for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
194  OpenDriveEdge* e = (*i).second;
195  assert(e->junction != "-1" && e->junction != "");
196  edge2junction[e->id] = e->junction;
197  if (posMap.find(e->junction) == posMap.end()) {
198  posMap[e->junction] = Boundary();
199  }
200  posMap[e->junction].add(e->geom.getBoxBoundary());
201  }
202  // build nodes
203  for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
204  if (!nb.getNodeCont().insert((*i).first, (*i).second.getCenter())) {
205  throw ProcessError("Could not add node '" + (*i).first + "'.");
206  }
207  }
208  // assign built nodes
209  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
210  OpenDriveEdge* e = (*i).second;
211  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
212  OpenDriveLink& l = *j;
213  const std::string& nid = l.elementID;
214  if (l.elementType != OPENDRIVE_ET_ROAD) {
215  if (nb.getNodeCont().retrieve(nid) == 0) {
216  // not yet seen, build (possibly a junction without connections)
217  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
218  if (!nb.getNodeCont().insert(nid, pos)) {
219  throw ProcessError("Could not build node '" + nid + "'.");
220  }
221  }
222  // set node information
224  continue;
225  }
226  if (edge2junction.find(l.elementID) != edge2junction.end()) {
227  // set node information of an internal road
228  setNodeSecure(nb.getNodeCont(), *e, edge2junction[l.elementID], l.linkType);
229  continue;
230  }
231  }
232  }
233  // we should now have all nodes set for links which are not outer edge-to-outer edge links
234 
235 
236  // build nodes#2
237  // build nodes for all outer edge-to-outer edge connections
238  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
239  OpenDriveEdge* e = (*i).second;
240  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
241  OpenDriveLink& l = *j;
242  if (l.elementType != OPENDRIVE_ET_ROAD || edge2junction.find(l.elementID) != edge2junction.end()) {
243  // is a connection to an internal edge, or a node, skip
244  continue;
245  }
246  // we have a direct connection between to external edges
247  std::string id1 = e->id;
248  std::string id2 = l.elementID;
249  if (id1 < id2) {
250  std::swap(id1, id2);
251  }
252  std::string nid = id1 + "." + id2;
253  if (nb.getNodeCont().retrieve(nid) == 0) {
254  // not yet seen, build
255  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
256  if (!nb.getNodeCont().insert(nid, pos)) {
257  throw ProcessError("Could not build node '" + nid + "'.");
258  }
259  }
260  /* debug-stuff
261  else {
262  Position pos = l.linkType==OPENDRIVE_LT_SUCCESSOR ? e.geom[e.geom.size()-1] : e.geom[0];
263  cout << nid << " " << pos << " " << nb.getNodeCont().retrieve(nid)->getPosition() << endl;
264  }
265  */
266  setNodeSecure(nb.getNodeCont(), *e, nid, l.linkType);
267  }
268  }
269  // we should now have start/end nodes for all outer edge-to-outer edge connections
270 
271 
272  // build nodes#3
273  // assign further nodes generated from inner-edges
274  // these nodes have not been assigned earlier, because the connections are referenced in inner-edges
275  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
276  OpenDriveEdge* e = (*i).second;
277  if (e->to != 0 && e->from != 0) {
278  continue;
279  }
280  for (std::map<std::string, OpenDriveEdge*>::iterator j = innerEdges.begin(); j != innerEdges.end(); ++j) {
281  OpenDriveEdge* ie = (*j).second;
282  for (std::vector<OpenDriveLink>::iterator k = ie->links.begin(); k != ie->links.end(); ++k) {
283  OpenDriveLink& il = *k;
284  if (il.elementType != OPENDRIVE_ET_ROAD || il.elementID != e->id) {
285  // not conneted to the currently investigated outer edge
286  continue;
287  }
288  std::string nid = edge2junction[ie->id];
289  if (il.contactPoint == OPENDRIVE_CP_START) {
291  } else {
293  }
294  }
295  }
296 
297  }
298 
299  // build start/end nodes which were not defined previously
300  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
301  OpenDriveEdge* e = (*i).second;
302  if (e->from == 0) {
303  const std::string nid = e->id + ".begin";
304  e->from = getOrBuildNode(nid, e->geom.front(), nb.getNodeCont());
305  }
306  if (e->to == 0) {
307  const std::string nid = e->id + ".end";
308  e->to = getOrBuildNode(nid, e->geom.back(), nb.getNodeCont());
309  }
310  }
311 
312 
313  // -------------------------
314  // edge building
315  // -------------------------
316  SUMOReal defaultSpeed = tc.getSpeed("");
317  // build edges
318  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
319  OpenDriveEdge* e = (*i).second;
320  bool lanesBuilt = false;
321 
322  // go along the lane sections, build a node in between of each pair
323 
326 
328  NBNode* sFrom = e->from;
329  NBNode* sTo = e->to;
330  int priorityR = e->getPriority(OPENDRIVE_TAG_RIGHT);
331  int priorityL = e->getPriority(OPENDRIVE_TAG_LEFT);
332  SUMOReal sB = 0;
333  SUMOReal sE = e->length;
334  // 0-length geometries are possible if only the inner points are represented
335  const SUMOReal length2D = e->geom.length2D();
336  SUMOReal cF = length2D == 0 ? 1 : e->length / length2D;
337  NBEdge* prevRight = 0;
338  NBEdge* prevLeft = 0;
339 
340  // starting at the same node as ending, and no lane sections?
341  if (sFrom == sTo && e->laneSections.size() == 1) {
342  // --> loop, split!
344  ls.s = e->length / 2.;
345  e->laneSections.push_back(ls);
346  WRITE_WARNING("Edge '" + e->id + "' has to be split as it connects same junctions.")
347  }
348 
349  // build along lane sections
350  for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
351  // add internal node if needed
352  if (j == e->laneSections.end() - 1) {
353  sTo = e->to;
354  sE = e->length / cF;
355  } else {
356  SUMOReal nextS = (j + 1)->s;
357  sTo = new NBNode(e->id + "." + toString(nextS), e->geom.positionAtOffset(nextS));
358  if (!nb.getNodeCont().insert(sTo)) {
359  throw ProcessError("Could not add node '" + sTo->getID() + "'.");
360  }
361  sE = nextS / cF;
362  }
363  PositionVector geom = e->geom.getSubpart2D(sB, sE);
364  std::string id = e->id;
365  if (sFrom != e->from || sTo != e->to) {
366  id = id + "." + toString((*j).s);
367  } else if (e->laneSections.size() == 1) {
368  id = id + ".0.00";
369  }
370 
371  // build lanes to right
372  NBEdge* currRight = 0;
373  if ((*j).rightLaneNumber > 0) {
374  currRight = new NBEdge("-" + id, sFrom, sTo, "", defaultSpeed, (*j).rightLaneNumber, priorityR,
376  if (!nb.getEdgeCont().insert(currRight)) {
377  throw ProcessError("Could not add edge '" + currRight->getID() + "'.");
378  }
379  lanesBuilt = true;
380  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_RIGHT];
381  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
382  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
383  if (lp != (*j).laneMap.end()) {
384  int sumoLaneIndex = lp->second;
385  NBEdge::Lane& sumoLane = currRight->getLaneStruct(sumoLaneIndex);
386  const OpenDriveLane& odLane = *k;
387 
388  sumoLane.origID = e->id + " -" + toString((*k).id);
389  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
390  sumoLane.permissions = tc.getPermissions(odLane.type);
391  sumoLane.width = myImportWidths && odLane.width != 0 ? odLane.width : tc.getWidth(odLane.type);
392  }
393  }
394  // connect lane sections
395  if (prevRight != 0) {
396  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_RIGHT, *(j - 1));
397  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
398  prevRight->addLane2LaneConnection((*k).first, currRight, (*k).second, NBEdge::L2L_VALIDATED);
399  }
400  }
401  prevRight = currRight;
402  }
403 
404  // build lanes to left
405  NBEdge* currLeft = 0;
406  if ((*j).leftLaneNumber > 0) {
407  currLeft = new NBEdge(id, sTo, sFrom, "", defaultSpeed, (*j).leftLaneNumber, priorityL,
409  if (!nb.getEdgeCont().insert(currLeft)) {
410  throw ProcessError("Could not add edge '" + currLeft->getID() + "'.");
411  }
412  lanesBuilt = true;
413  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_LEFT];
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 = currLeft->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 != 0 ? odLane.width : tc.getWidth(odLane.type);
425  }
426  }
427  // connect lane sections
428  if (prevLeft != 0) {
429  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_LEFT, *(j - 1));
430  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
431  currLeft->addLane2LaneConnection((*k).first, prevLeft, (*k).second, NBEdge::L2L_VALIDATED);
432  }
433  }
434  prevLeft = currLeft;
435  }
436  (*j).sumoID = id;
437 
438 
439  sB = sE;
440  sFrom = sTo;
441  }
442  if (!lanesBuilt) {
443  WRITE_WARNING("Edge '" + e->id + "' has no lanes.");
444  }
445  }
446 
447  // -------------------------
448  // connections building
449  // -------------------------
450  // generate explicit lane-to-lane connections
451  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
452  setEdgeLinks2(*(*i).second, edges);
453  }
454  // compute connections across intersections, if any
455  std::vector<Connection> connections2;
456  for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
457  const std::set<Connection>& conns = (*j).second->connections;
458 
459  for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
460  if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
461  // connections starting at inner edges are processed by starting from outer edges
462  continue;
463  }
464  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
465  buildConnectionsToOuter(*i, innerEdges, connections2);
466  } else {
467  connections2.push_back(*i);
468  }
469  }
470  }
471  // set connections
472  for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
473  std::string fromEdge = (*i).fromEdge;
474  if (edges.find(fromEdge) == edges.end()) {
475  WRITE_WARNING("While setting connections: from-edge '" + fromEdge + "' is not known.");
476  continue;
477  }
478  OpenDriveEdge* odFrom = edges[fromEdge];
479  int fromLane = (*i).fromLane;
480  bool fromLast = ((*i).fromCP == OPENDRIVE_CP_END) ^ ((*i).fromLane > 0 && !(*i).all);
481  fromEdge = fromLast ? odFrom->laneSections.back().sumoID : odFrom->laneSections[0].sumoID;
482 
483  std::string toEdge = (*i).toEdge;
484  if (edges.find(toEdge) == edges.end()) {
485  WRITE_WARNING("While setting connections: to-edge '" + toEdge + "' is not known.");
486  continue;
487  }
488 
489  OpenDriveEdge* odTo = edges[toEdge];
490  int toLane = (*i).toLane;
491  bool toLast = ((*i).toCP == OPENDRIVE_CP_END) || ((*i).toLane > 0);
492  toEdge = toLast ? odTo->laneSections.back().sumoID : odTo->laneSections[0].sumoID;
493 
494  if (fromLane == UNSET_CONNECTION) {
495  fromLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
496  }
497  if (fromLane < 0) {
498  fromEdge = revertID(fromEdge);
499  }
500  if (toLane == UNSET_CONNECTION) {
501  toLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
502  }
503  if (toLane < 0) {
504  toEdge = revertID(toEdge);
505  }
506  fromLane = fromLast ? odFrom->laneSections.back().laneMap[fromLane] : odFrom->laneSections[0].laneMap[fromLane];
507  toLane = toLast ? odTo->laneSections.back().laneMap[toLane] : odTo->laneSections[0].laneMap[toLane];
508  NBEdge* from = nb.getEdgeCont().retrieve(fromEdge);
509  NBEdge* to = nb.getEdgeCont().retrieve(toEdge);
510  if (from == 0) {
511  WRITE_WARNING("Could not find fromEdge representation of '" + fromEdge + "' in connection '" + (*i).origID + "'.");
512  }
513  if (to == 0) {
514  WRITE_WARNING("Could not find fromEdge representation of '" + toEdge + "' in connection '" + (*i).origID + "'.");
515  }
516  if (from == 0 || to == 0) {
517  continue;
518  }
519 
520  from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER);
521 
522  if ((*i).origID != "") {
523  // @todo: this is the most silly way to determine the connection
524  std::vector<NBEdge::Connection>& cons = from->getConnections();
525  for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
526  if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
527  (*k).origID = (*i).origID + " " + toString((*i).origLane);
528  break;
529  }
530  }
531  }
532  }
533 
534 
535  // -------------------------
536  // traffic lights
537  // -------------------------
538  std::map<std::string, std::string> tlsControlled;
539  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
540  OpenDriveEdge* e = (*i).second;
541  for (std::vector<OpenDriveSignal>::const_iterator j = e->signals.begin(); j != e->signals.end(); ++j) {
542  if ((*j).type != "1000001") {
543  continue;
544  }
545  std::vector<OpenDriveLaneSection>::iterator k = e->laneSections.begin();
546  bool found = false;
547  for (; k != e->laneSections.end() - 1 && !found;) {
548  if ((*j).s > (*k).s && (*j).s <= (*(k + 1)).s) {
549  found = true;
550  } else {
551  ++k;
552  }
553  }
554 
555  // @todo: major problem, currently, still not completely solved:
556  // inner edges may have traffic lights, too. Nice on one hand, as directions can be recognized
557  // but hard to follow backwards
558  std::string id = (*k).sumoID;
559  if (id == "") {
560  if (e->junction != "") {
561  //WRITE_WARNING("Found a traffic light signal on an internal edge; will not build it (original edge id='" + e->id + "').");
562  std::string fromID, toID;
563  for (std::vector<OpenDriveLink>::const_iterator l = e->links.begin(); l != e->links.end(); ++l) {
564  if ((*l).linkType == OPENDRIVE_LT_PREDECESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
565  if (fromID != "") {
566  WRITE_WARNING("Ambigous start of connection.");
567  }
568  fromID = (*l).elementID;
569  OpenDriveEdge* e = edges[fromID];
570  fromID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
571  }
572  if ((*l).linkType == OPENDRIVE_LT_SUCCESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
573  if (toID != "") {
574  WRITE_WARNING("Ambigous end of connection.");
575  }
576  toID = (*l).elementID;
577  OpenDriveEdge* e = edges[toID];
578  toID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
579  }
580  }
581  id = fromID + "->" + toID;
582  } else {
583  WRITE_WARNING("Found a traffic light signal on an unknown edge (original edge id='" + e->id + "').");
584  continue;
585  }
586  }
587 
588  if ((*j).orientation > 0) {
589  id = "-" + id;
590  }
591  tlsControlled[id] = (*j).name;
592  }
593  }
594 
595  for (std::map<std::string, std::string>::iterator i = tlsControlled.begin(); i != tlsControlled.end(); ++i) {
596  std::string id = (*i).first;
597  if (id.find("->") != std::string::npos) {
598  id = id.substr(0, id.find("->"));
599  }
600  NBEdge* e = nb.getEdgeCont().retrieve(id);
601  if (e == 0) {
602  WRITE_WARNING("Could not find edge '" + id + "' while building its traffic light.");
603  continue;
604  }
605  NBNode* toNode = e->getToNode();
606  NBTrafficLightDefinition* tlDef = 0;
607  if (!toNode->isTLControlled()) {
609  tlDef = new NBOwnTLDef(toNode->getID(), toNode, 0, type);
610  if (!nb.getTLLogicCont().insert(tlDef)) {
611  // actually, nothing should fail here
612  delete tlDef;
613  throw ProcessError();
614  }
615  toNode->addTrafficLight(tlDef);
616  static_cast<NBOwnTLDef*>(tlDef)->setSinglePhase();
617  }
618  tlDef = *toNode->getControllingTLS().begin();
619  tlDef->addParameter("connection:" + id, (*i).second);
620  }
621 
622  // -------------------------
623  // clean up
624  // -------------------------
625  if (oc.exists("geometry.min-dist") && oc.isSet("geometry.min-dist")) {
626  oc.unSet("geometry.min-dist");
627  }
628  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
629  delete(*i).second;
630  }
631 }
632 
633 
634 
635 void
636 NIImporter_OpenDrive::buildConnectionsToOuter(const Connection& c, const std::map<std::string, OpenDriveEdge*>& innerEdges, std::vector<Connection>& into) {
637 
638  OpenDriveEdge* dest = innerEdges.find(c.toEdge)->second;
639  if (dest == 0) {
641  return;
642  }
643  const std::set<Connection>& conts = dest->connections;
644  for (std::set<Connection>::const_iterator i = conts.begin(); i != conts.end(); ++i) {
645  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
646  std::vector<Connection> t;
647  buildConnectionsToOuter(*i, innerEdges, t);
648  for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
649  // @todo this section is unverified
650  Connection cn = (*j);
651  cn.fromEdge = c.fromEdge;
652  cn.fromLane = c.fromLane;
653  cn.fromCP = c.fromCP;
654  cn.all = c.all; // @todo "all" is a hack trying to avoid the "from is zero" problem;
655  into.push_back(cn);
656  }
657  } else {
658  if ((*i).fromLane == c.toLane) {
659  Connection cn = (*i);
660  cn.fromEdge = c.fromEdge;
661  cn.fromLane = c.fromLane;
662  cn.fromCP = c.fromCP;
663  cn.all = c.all;
664  cn.origID = c.toEdge;
665  cn.origLane = c.toLane;
666  into.push_back(cn);
667  }
668  }
669  }
670 }
671 
672 
673 void
674 NIImporter_OpenDrive::setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges) {
675  for (std::vector<OpenDriveLink>::iterator i = e.links.begin(); i != e.links.end(); ++i) {
676  OpenDriveLink& l = *i;
677  if (l.elementType != OPENDRIVE_ET_ROAD) {
678  // we assume that links to nodes are later given as connections to edges
679  continue;
680  }
681  // get the right direction of the connected edge
682  std::string connectedEdge = l.elementID;
683  std::string edgeID = e.id;
684 
685  OpenDriveLaneSection& laneSection = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e.laneSections.back() : e.laneSections[0];
686  const std::map<int, int>& laneMap = laneSection.laneMap;
687  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
688  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
689  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
690  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
691  continue;
692  }
693  Connection c; // @todo: give Connection a new name and a constructor
694  c.fromEdge = e.id;
695  c.fromLane = (*j).id;
697  c.toLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
698  c.toEdge = connectedEdge;
699  c.toCP = l.contactPoint;
700  c.all = false;
701  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
702  std::swap(c.fromEdge, c.toEdge);
703  std::swap(c.fromLane, c.toLane);
704  std::swap(c.fromCP, c.toCP);
705  }
706  if (edges.find(c.fromEdge) == edges.end()) {
707  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
708  } else {
709  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
710  src->connections.insert(c);
711  }
712  }
713  }
714  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
715  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
716  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
717  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
718  continue;
719  }
720  Connection c;
721  c.toEdge = e.id;
722  c.toLane = (*j).id;
724  c.fromLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
725  c.fromEdge = connectedEdge;
726  c.fromCP = l.contactPoint;
727  c.all = false;
728  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
729  std::swap(c.fromEdge, c.toEdge);
730  std::swap(c.fromLane, c.toLane);
731  std::swap(c.fromCP, c.toCP);
732  }
733  if (edges.find(c.fromEdge) == edges.end()) {
734  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
735  } else {
736  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
737  src->connections.insert(c);
738  }
739  }
740  }
741  }
742 }
743 
744 
745 std::string NIImporter_OpenDrive::revertID(const std::string& id) {
746  if (id[0] == '-') {
747  return id.substr(1);
748  }
749  return "-" + id;
750 }
751 
752 NBNode*
753 NIImporter_OpenDrive::getOrBuildNode(const std::string& id, const Position& pos,
754  NBNodeCont& nc) {
755  if (nc.retrieve(id) == 0) {
756  // not yet built; build now
757  if (!nc.insert(id, pos)) {
758  // !!! clean up
759  throw ProcessError("Could not add node '" + id + "'.");
760  }
761  }
762  return nc.retrieve(id);
763 }
764 
765 
766 void
768  const std::string& nodeID, NIImporter_OpenDrive::LinkType lt) {
769  NBNode* n = nc.retrieve(nodeID);
770  if (n == 0) {
771  throw ProcessError("Could not find node '" + nodeID + "'.");
772  }
773  if (lt == OPENDRIVE_LT_SUCCESSOR) {
774  if (e.to != 0 && e.to != n) {
775  throw ProcessError("Edge '" + e.id + "' has two end nodes.");
776  }
777  e.to = n;
778  } else {
779  if (e.from != 0 && e.from != n) {
780  throw ProcessError("Edge '" + e.id + "' has two start nodes.");
781  }
782  e.from = n;
783  }
784 }
785 
786 
787 
788 
789 
790 
791 
792 void
793 NIImporter_OpenDrive::computeShapes(std::map<std::string, OpenDriveEdge*>& edges) {
795  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
796  OpenDriveEdge& e = *(*i).second;
798  for (std::vector<OpenDriveGeometry>::iterator j = e.geometries.begin(); j != e.geometries.end(); ++j) {
799  OpenDriveGeometry& g = *j;
800  PositionVector geom;
801  switch (g.type) {
803  break;
804  case OPENDRIVE_GT_LINE:
805  geom = geomFromLine(e, g);
806  break;
807  case OPENDRIVE_GT_SPIRAL:
808  geom = geomFromSpiral(e, g);
809  break;
810  case OPENDRIVE_GT_ARC:
811  geom = geomFromArc(e, g);
812  break;
813  case OPENDRIVE_GT_POLY3:
814  geom = geomFromPoly(e, g);
815  break;
816  default:
817  break;
818  }
819  if (e.geom.size() > 0 && prevType == OPENDRIVE_GT_LINE) {
820  // remove redundant end point of the previous geometry segment
821  // (the start point of the current segment should have the same value)
822  // this avoids geometry errors due to imprecision
823  if (!e.geom.back().almostSame(geom.front())) {
824  const int index = (int)(j - e.geometries.begin());
825  WRITE_WARNING("Mismatched geometry for edge '" + e.id + "' between geometry segments " + toString(index - 1) + " and " + toString(index) + ".");
826  }
827  e.geom.pop_back();
828  }
829  for (PositionVector::iterator k = geom.begin(); k != geom.end(); ++k) {
831  }
832  prevType = g.type;
833  }
834  if (oc.exists("geometry.min-dist") && oc.isSet("geometry.min-dist")) {
835  e.geom.removeDoublePoints(oc.getFloat("geometry.min-dist"), true);
836  }
837  for (unsigned int j = 0; j < e.geom.size(); ++j) {
839  WRITE_ERROR("Unable to project coordinates for.");
840  }
841  }
842  }
843 }
844 
845 
846 void
847 NIImporter_OpenDrive::revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges) {
848  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
849  OpenDriveEdge& e = *(*i).second;
850  std::vector<OpenDriveLaneSection>& laneSections = e.laneSections;
851  // split by speed limits
852  std::vector<OpenDriveLaneSection> newSections;
853  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end(); ++j) {
854  std::vector<OpenDriveLaneSection> splitSections;
855  bool splitBySpeed = (*j).buildSpeedChanges(tc, splitSections);
856  if (!splitBySpeed) {
857  newSections.push_back(*j);
858  } else {
859  std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
860  }
861  }
862 
863  e.laneSections = newSections;
864  laneSections = e.laneSections;
865  SUMOReal lastS = -1;
866  // check whether the lane sections are in the right order
867  bool sorted = true;
868  for (std::vector<OpenDriveLaneSection>::const_iterator j = laneSections.begin(); j != laneSections.end() && sorted; ++j) {
869  if ((*j).s <= lastS) {
870  sorted = false;
871  }
872  lastS = (*j).s;
873  }
874  if (!sorted) {
875  WRITE_WARNING("The sections of edge '" + e.id + "' are not sorted properly.");
876  sort(e.laneSections.begin(), e.laneSections.end(), sections_by_s_sorter());
877  }
878  // check whether no duplicates of s-value occure
879  lastS = -1;
880  laneSections = e.laneSections;
881  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end();) {
882  bool simlarToLast = fabs((*j).s - lastS) < POSITION_EPS;
883  lastS = (*j).s;
884  if (simlarToLast) {
885  WRITE_WARNING("Almost duplicate s-value '" + toString(lastS) + "' for lane sections occured at edge '" + e.id + "'; second entry was removed.");
886  j = laneSections.erase(j);
887  } else {
888  ++j;
889  }
890  }
891  }
892 }
893 
894 
897  UNUSED_PARAMETER(e);
898  PositionVector ret;
899  ret.push_back(Position(g.x, g.y));
900  ret.push_back(calculateStraightEndPoint(g.hdg, g.length, Position(g.x, g.y)));
901  return ret;
902 }
903 
904 
907  UNUSED_PARAMETER(e);
908  PositionVector ret;
909  SUMOReal curveStart = g.params[0];
910  SUMOReal curveEnd = g.params[1];
911  Point2D<double> end;
912  try {
913  EulerSpiral s(Point2D<double>(g.x, g.y), g.hdg, curveStart, (curveEnd - curveStart) / g.length, g.length);
914  std::vector<Point2D<double> > into;
915  s.computeSpiral(into, 1.);
916  for (std::vector<Point2D<double> >::iterator i = into.begin(); i != into.end(); ++i) {
917  ret.push_back(Position((*i).getX(), (*i).getY()));
918  }
919  } catch (const std::runtime_error& error) {
920  WRITE_WARNING("Could not compute spiral geometry for edge '" + e.id + "' (" + error.what() + ").");
921  ret.push_back(Position(g.x, g.y));
922  }
923  return ret.getSubpart2D(0, g.length);
924 }
925 
926 
929  UNUSED_PARAMETER(e);
930  PositionVector ret;
931  SUMOReal dist = 0.0;
932  SUMOReal centerX = g.x;
933  SUMOReal centerY = g.y;
934  // left: positive value
935  SUMOReal curvature = g.params[0];
936  SUMOReal radius = 1. / curvature;
937  // center point
938  calculateCurveCenter(&centerX, &centerY, radius, g.hdg);
939  SUMOReal endX = g.x;
940  SUMOReal endY = g.y;
941  SUMOReal startX = g.x;
942  SUMOReal startY = g.y;
943  SUMOReal geo_posS = g.s;
944  SUMOReal geo_posE = g.s;
945  bool end = false;
946  do {
947  geo_posE += C_LENGTH;
948  if (geo_posE - g.s > g.length) {
949  geo_posE = g.s + g.length;
950  }
951  if (geo_posE - g.s > g.length) {
952  geo_posE = g.s + g.length;
953  }
954  calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
955 
956  dist += (geo_posE - geo_posS);
957  //
958  ret.push_back(Position(startX, startY));
959  //
960  startX = endX;
961  startY = endY;
962  geo_posS = geo_posE;
963 
964  if (geo_posE - (g.s + g.length) < 0.001 && geo_posE - (g.s + g.length) > -0.001) {
965  end = true;
966  }
967  } while (!end);
968  return ret.getSubpart2D(0, g.length);
969 }
970 
971 
974  UNUSED_PARAMETER(e);
975  PositionVector ret;
976  for (SUMOReal off = 0; off < g.length + 2.; off += 2.) {
977  SUMOReal x = off;
978  SUMOReal y = g.params[0] + g.params[1] * off + g.params[2] * pow(off, 2.) + g.params[3] * pow(off, 3.);
979  SUMOReal s = sin(g.hdg);
980  SUMOReal c = cos(g.hdg);
981  SUMOReal xnew = x * c - y * s;
982  SUMOReal ynew = x * s + y * c;
983  ret.push_back(Position(g.x + xnew, g.y + ynew));
984  }
985  return ret.getSubpart2D(0, g.length);
986 }
987 
988 
989 Position
990 NIImporter_OpenDrive::calculateStraightEndPoint(double hdg, double length, const Position& start) {
991  double normx = 1.0f;
992  double normy = 0.0f;
993  double x2 = normx * cos(hdg) - normy * sin(hdg);
994  double y2 = normx * sin(hdg) + normy * cos(hdg);
995  normx = x2 * length;
996  normy = y2 * length;
997  return Position(start.x() + normx, start.y() + normy);
998 }
999 
1000 
1001 void
1003  SUMOReal normX = 1.0;
1004  SUMOReal normY = 0.0;
1005  SUMOReal tmpX;
1006  SUMOReal turn;
1007  if (ad_radius > 0) {
1008  turn = -1.0;
1009  } else {
1010  turn = 1.0;
1011  }
1012 
1013  tmpX = normX;
1014  normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
1015  normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
1016 
1017  tmpX = normX;
1018  normX = turn * normY;
1019  normY = -turn * tmpX;
1020 
1021  normX = fabs(ad_radius) * normX;
1022  normY = fabs(ad_radius) * normY;
1023 
1024  *ad_x += normX;
1025  *ad_y += normY;
1026 }
1027 
1028 
1029 void
1031  SUMOReal ad_r, SUMOReal ad_length) {
1032  double rotAngle = ad_length / fabs(ad_r);
1033  double vx = *ad_x - ad_centerX;
1034  double vy = *ad_y - ad_centerY;
1035  double tmpx;
1036 
1037  double turn;
1038  if (ad_r > 0) {
1039  turn = -1; //left
1040  } else {
1041  turn = 1; //right
1042  }
1043  tmpx = vx;
1044  vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
1045  vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
1046  *ad_x = vx + ad_centerX;
1047  *ad_y = vy + ad_centerY;
1048 }
1049 
1050 
1051 // ---------------------------------------------------------------------------
1052 // section
1053 // ---------------------------------------------------------------------------
1055  lanesByDir[OPENDRIVE_TAG_LEFT] = std::vector<OpenDriveLane>();
1056  lanesByDir[OPENDRIVE_TAG_RIGHT] = std::vector<OpenDriveLane>();
1057  lanesByDir[OPENDRIVE_TAG_CENTER] = std::vector<OpenDriveLane>();
1058 }
1059 
1060 
1061 void
1063  unsigned int sumoLane = 0;
1064  const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
1065  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
1066  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1067  laneMap[(*i).id] = sumoLane++;
1068  }
1069  }
1070  rightLaneNumber = sumoLane;
1071  sumoLane = 0;
1072  const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
1073  for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
1074  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1075  laneMap[(*i).id] = sumoLane++;
1076  }
1077  }
1078  leftLaneNumber = sumoLane;
1079 }
1080 
1081 
1082 std::map<int, int>
1084  std::map<int, int> ret;
1085  const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
1086  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
1087  std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
1088  if (toP == laneMap.end()) {
1089  // the current lane is not available in SUMO
1090  continue;
1091  }
1092  int to = (*toP).second;
1093  int from = UNSET_CONNECTION;
1094  if ((*i).predecessor != UNSET_CONNECTION) {
1095  from = (*i).predecessor;
1096  }
1097  if (from != UNSET_CONNECTION) {
1098  std::map<int, int>::const_iterator fromP = prev.laneMap.find(from);
1099  if (fromP != prev.laneMap.end()) {
1100  from = (*fromP).second;
1101  } else {
1102  from = UNSET_CONNECTION;
1103  }
1104  }
1105  if (from != UNSET_CONNECTION && to != UNSET_CONNECTION) {
1106  if (ret.find(from) != ret.end()) {
1107 // WRITE_WARNING("double connection");
1108  }
1109  if (dir == OPENDRIVE_TAG_LEFT) {
1110  std::swap(from, to);
1111  }
1112  ret[from] = to;
1113  } else {
1114 // WRITE_WARNING("missing connection");
1115  }
1116  }
1117  return ret;
1118 }
1119 
1120 
1123  OpenDriveLaneSection ret(*this);
1124  ret.s += startPos;
1125  for (unsigned int k = 0; k != ret.lanesByDir[OPENDRIVE_TAG_RIGHT].size(); ++k) {
1127  l.speed = 0;
1128  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1129  if (i != l.speeds.end()) {
1130  l.speed = (*i).second;
1131  }
1132  }
1133  for (unsigned int k = 0; k != ret.lanesByDir[OPENDRIVE_TAG_LEFT].size(); ++k) {
1135  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1136  l.speed = 0;
1137  if (i != l.speeds.end()) {
1138  l.speed = (*i).second;
1139  }
1140  }
1141  return ret;
1142 }
1143 
1144 
1145 bool
1146 NIImporter_OpenDrive::OpenDriveLaneSection::buildSpeedChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections) {
1147  std::set<SUMOReal> speedChangePositions;
1148  // collect speed change positions and apply initial speed to the begin
1149  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_RIGHT].begin(); k != lanesByDir[OPENDRIVE_TAG_RIGHT].end(); ++k) {
1150  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1151  speedChangePositions.insert((*l).first);
1152  if ((*l).first == 0) {
1153  (*k).speed = (*l).second;
1154  }
1155  }
1156  }
1157  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_LEFT].begin(); k != lanesByDir[OPENDRIVE_TAG_LEFT].end(); ++k) {
1158  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1159  speedChangePositions.insert((*l).first);
1160  if ((*l).first == 0) {
1161  (*k).speed = (*l).second;
1162  }
1163  }
1164  }
1165  // do nothing if there is none
1166  if (speedChangePositions.size() == 0) {
1167  return false;
1168  }
1169  if (*speedChangePositions.begin() > 0) {
1170  speedChangePositions.insert(0);
1171  }
1172  //
1173  for (std::set<SUMOReal>::iterator i = speedChangePositions.begin(); i != speedChangePositions.end(); ++i) {
1174  if (i == speedChangePositions.begin()) {
1175  newSections.push_back(*this);
1176  } else {
1177  newSections.push_back(buildLaneSection(*i));
1178  }
1179  }
1180  // propagate speeds
1181  for (int i = 0; i != (int)newSections.size(); ++i) {
1182  OpenDriveLaneSection& ls = newSections[i];
1183  std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >& lanesByDir = ls.lanesByDir;
1184  for (std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >::iterator k = lanesByDir.begin(); k != lanesByDir.end(); ++k) {
1185  std::vector<OpenDriveLane>& lanes = (*k).second;
1186  for (int j = 0; j != (int)lanes.size(); ++j) {
1187  OpenDriveLane& l = lanes[j];
1188  if (l.speed != 0) {
1189  continue;
1190  }
1191  if (i > 0) {
1192  l.speed = newSections[i - 1].lanesByDir[(*k).first][j].speed;
1193  } else {
1194  tc.getSpeed(l.type);
1195  }
1196  }
1197  }
1198  }
1199  return true;
1200 }
1201 
1202 
1203 
1204 // ---------------------------------------------------------------------------
1205 // edge
1206 // ---------------------------------------------------------------------------
1207 int
1209  int prio = 1;
1210  for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
1211  int tmp = 1;
1212  if ((*i).type == "301" || (*i).type == "306") {
1213  tmp = 2;
1214  }
1215  if ((*i).type == "205") {
1216  tmp = 0;
1217  }
1218  if (tmp != 1 && dir == OPENDRIVE_TAG_RIGHT && (*i).orientation > 0) {
1219  prio = tmp;
1220  }
1221  if (tmp != 1 && dir == OPENDRIVE_TAG_LEFT && (*i).orientation < 0) {
1222  prio = tmp;
1223  }
1224 
1225  }
1226  return prio;
1227 }
1228 
1229 
1230 
1231 // ---------------------------------------------------------------------------
1232 // loader methods
1233 // ---------------------------------------------------------------------------
1234 NIImporter_OpenDrive::NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges)
1236  myTypeContainer(tc), myCurrentEdge("", "", "", -1), myEdges(edges) {
1237 }
1238 
1239 
1241 }
1242 
1243 
1244 void
1246  const SUMOSAXAttributes& attrs) {
1247  bool ok = true;
1248  switch (element) {
1249  case OPENDRIVE_TAG_HEADER: {
1250  int majorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMAJOR, 0, ok);
1251  int minorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMINOR, 0, ok);
1252  if (majorVersion != 1 || minorVersion != 2) {
1253  WRITE_WARNING("Given openDrive file '" + getFileName() + "' uses version " + toString(majorVersion) + "." + toString(minorVersion) + ";\n Version 1.2 is supported.");
1254  }
1255  }
1256  break;
1257  case OPENDRIVE_TAG_ROAD: {
1258  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, 0, ok);
1259  std::string streetName = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, 0, ok, "", false);
1260  std::string junction = attrs.get<std::string>(OPENDRIVE_ATTR_JUNCTION, id.c_str(), ok);
1261  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, id.c_str(), ok);
1262  myCurrentEdge = OpenDriveEdge(id, streetName, junction, length);
1263  }
1264  break;
1266  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1267  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1268  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1269  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1270  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1271  : "end";
1272  addLink(OPENDRIVE_LT_PREDECESSOR, elementType, elementID, contactPoint);
1273  }
1274  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1275  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1276  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1277  l.predecessor = no;
1278  }
1279  }
1280  break;
1281  case OPENDRIVE_TAG_SUCCESSOR: {
1282  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1283  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1284  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1285  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1286  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1287  : "start";
1288  addLink(OPENDRIVE_LT_SUCCESSOR, elementType, elementID, contactPoint);
1289  }
1290  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1291  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1292  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1293  l.successor = no;
1294  }
1295  }
1296  break;
1297  case OPENDRIVE_TAG_GEOMETRY: {
1298  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, myCurrentEdge.id.c_str(), ok);
1299  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1300  SUMOReal x = attrs.get<SUMOReal>(OPENDRIVE_ATTR_X, myCurrentEdge.id.c_str(), ok);
1301  SUMOReal y = attrs.get<SUMOReal>(OPENDRIVE_ATTR_Y, myCurrentEdge.id.c_str(), ok);
1302  SUMOReal hdg = attrs.get<SUMOReal>(OPENDRIVE_ATTR_HDG, myCurrentEdge.id.c_str(), ok);
1303  myCurrentEdge.geometries.push_back(OpenDriveGeometry(length, s, x, y, hdg));
1304  }
1305  break;
1306  case OPENDRIVE_TAG_LINE: {
1307  std::vector<SUMOReal> vals;
1309  }
1310  break;
1311  case OPENDRIVE_TAG_SPIRAL: {
1312  std::vector<SUMOReal> vals;
1313  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVSTART, myCurrentEdge.id.c_str(), ok));
1314  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVEND, myCurrentEdge.id.c_str(), ok));
1316  }
1317  break;
1318  case OPENDRIVE_TAG_ARC: {
1319  std::vector<SUMOReal> vals;
1320  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVATURE, myCurrentEdge.id.c_str(), ok));
1322  }
1323  break;
1324  case OPENDRIVE_TAG_POLY3: {
1325  std::vector<SUMOReal> vals;
1326  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok));
1327  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok));
1328  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok));
1329  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok));
1331  }
1332  break;
1334  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1336  }
1337  break;
1338  case OPENDRIVE_TAG_LEFT:
1340  break;
1341  case OPENDRIVE_TAG_CENTER:
1343  break;
1344  case OPENDRIVE_TAG_RIGHT:
1346  break;
1347  case OPENDRIVE_TAG_LANE: {
1348  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1349  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1350  std::string level = attrs.hasAttribute(OPENDRIVE_ATTR_LEVEL)
1351  ? attrs.get<std::string>(OPENDRIVE_ATTR_LEVEL, myCurrentEdge.id.c_str(), ok)
1352  : "";
1354  ls.lanesByDir[myCurrentLaneDirection].push_back(OpenDriveLane(id, level, type));
1355  }
1356  break;
1357  case OPENDRIVE_TAG_SIGNAL: {
1358  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1359  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1360  std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, myCurrentEdge.id.c_str(), ok, "", false);
1361  int orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, myCurrentEdge.id.c_str(), ok) == "-" ? -1 : 1;
1362  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1363  bool dynamic = attrs.get<std::string>(OPENDRIVE_ATTR_DYNAMIC, myCurrentEdge.id.c_str(), ok) == "no" ? false : true;
1364  myCurrentEdge.signals.push_back(OpenDriveSignal(id, type, name, orientation, dynamic, s));
1365  }
1366  break;
1368  myCurrentJunctionID = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1369  break;
1370  case OPENDRIVE_TAG_CONNECTION: {
1371  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1372  myCurrentIncomingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_INCOMINGROAD, myCurrentJunctionID.c_str(), ok);
1374  std::string cp = attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentJunctionID.c_str(), ok);
1376  myConnectionWasEmpty = true;
1377  }
1378  break;
1379  case OPENDRIVE_TAG_LANELINK: {
1380  int from = attrs.get<int>(OPENDRIVE_ATTR_FROM, myCurrentJunctionID.c_str(), ok);
1381  int to = attrs.get<int>(OPENDRIVE_ATTR_TO, myCurrentJunctionID.c_str(), ok);
1382  Connection c;
1384  c.toEdge = myCurrentConnectingRoad;
1385  c.fromLane = from;
1386  c.toLane = to;
1387  c.fromCP = OPENDRIVE_CP_END;
1388  c.toCP = myCurrentContactPoint;
1389  c.all = false;
1390  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1391  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1392  } else {
1393  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1394  e->connections.insert(c);
1395  myConnectionWasEmpty = false;
1396  }
1397  }
1398  break;
1399  case OPENDRIVE_TAG_WIDTH: {
1400  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1401  SUMOReal width = attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1402  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1403  l.width = MAX2(l.width, width);
1404  }
1405  }
1406  break;
1407  case OPENDRIVE_TAG_SPEED: {
1408  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1409  SUMOReal speed = attrs.get<SUMOReal>(OPENDRIVE_ATTR_MAX, myCurrentEdge.id.c_str(), ok);
1410  SUMOReal pos = attrs.get<SUMOReal>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
1411  myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().speeds.push_back(std::make_pair(pos, speed));
1412  }
1413  }
1414  break;
1415  default:
1416  break;
1417  }
1418  myElementStack.push_back(element);
1419 }
1420 
1421 
1422 void
1424  myElementStack.pop_back();
1425  switch (element) {
1426  case OPENDRIVE_TAG_ROAD:
1428  break;
1430  if (myConnectionWasEmpty) {
1431  Connection c;
1434  c.fromLane = 0;
1435  c.toLane = 0;
1438  c.all = true;
1439  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1440  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1441  } else {
1442  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1443  e->connections.insert(c);
1444  }
1445  }
1446  break;
1448  myCurrentEdge.laneSections.back().buildLaneMapping(myTypeContainer);
1449  }
1450  break;
1451  default:
1452  break;
1453  }
1454 }
1455 
1456 
1457 
1458 void
1459 NIImporter_OpenDrive::addLink(LinkType lt, const std::string& elementType,
1460  const std::string& elementID,
1461  const std::string& contactPoint) {
1462  OpenDriveLink l(lt, elementID);
1463  // elementType
1464  if (elementType == "road") {
1466  } else if (elementType == "junction") {
1468  }
1469  // contact point
1470  if (contactPoint == "start") {
1472  } else if (contactPoint == "end") {
1474  }
1475  // add
1476  myCurrentEdge.links.push_back(l);
1477 }
1478 
1479 
1480 void
1481 NIImporter_OpenDrive::addGeometryShape(GeometryType type, const std::vector<SUMOReal>& vals) {
1482  // checks
1483  if (myCurrentEdge.geometries.size() == 0) {
1484  throw ProcessError("Mismatching paranthesis in geometry definition for road '" + myCurrentEdge.id + "'");
1485  }
1487  if (last.type != OPENDRIVE_GT_UNKNOWN) {
1488  throw ProcessError("Double geometry information for road '" + myCurrentEdge.id + "'");
1489  }
1490  // set
1491  last.type = type;
1492  last.params = vals;
1493 }
1494 
1495 
1496 bool
1498  if (c1.fromEdge != c2.fromEdge) {
1499  return c1.fromEdge < c2.fromEdge;
1500  }
1501  if (c1.toEdge != c2.toEdge) {
1502  return c1.toEdge < c2.toEdge;
1503  }
1504  if (c1.fromLane != c2.fromLane) {
1505  return c1.fromLane < c2.fromLane;
1506  }
1507  return c1.toLane < c2.toLane;
1508 }
1509 
1510 
1511 
1512 /****************************************************************************/
1513 
std::map< std::string, OpenDriveEdge * > & myEdges
static void calculateCurveCenter(SUMOReal *ad_x, SUMOReal *ad_y, SUMOReal ad_radius, SUMOReal ad_hdg)
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) ...
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:201
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 the type container.
Definition: NBNetBuilder.h:170
static bool transformCoordinates(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
void addLink(LinkType lt, const std::string &elementType, const std::string &elementID, const std::string &contactPoint)
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:58
std::string junction
The id of the junction the edge belongs to.
GeometryType
OpenDrive geometry type enumeration.
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:304
static void buildConnectionsToOuter(const Connection &c, const std::map< std::string, OpenDriveEdge * > &innerEdges, std::vector< Connection > &into)
void unSet(const std::string &name, bool failOnNonExistant=true) const
Marks the option as unset.
Representation of a lane section.
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:70
Representation of an openDrive "link".
bool addLane2LaneConnection(unsigned int fromLane, NBEdge *dest, unsigned int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, SUMOReal contPos=UNSPECIFIED_CONTPOS)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:684
The base class for traffic light logic definitions.
ContactPoint myCurrentContactPoint
SUMOReal s
The starting offset of this lane section.
T MAX2(T a, T b)
Definition: StdDefs.h:75
static PositionVector geomFromArc(const OpenDriveEdge &e, const OpenDriveGeometry &g)
std::map< OpenDriveXMLTag, std::vector< OpenDriveLane > > lanesByDir
The lanes, sorted by their direction.
SUMOReal getFloat(const std::string &name) const
Returns the SUMOReal-value of the named option (only for Option_Float)
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:203
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:114
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
friend bool operator<(const Connection &c1, const Connection &c2)
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list...
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:39
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
SUMOReal getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:217
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:69
static std::string revertID(const std::string &id)
PositionVector reverse() const
#define C_LENGTH
SUMOReal speed
The speed allowed on this lane.
Definition: NBEdge.h:130
OpenDriveXMLTag myCurrentLaneDirection
static void calcPointOnCurve(SUMOReal *ad_x, SUMOReal *ad_y, SUMOReal ad_centerX, SUMOReal ad_centerY, SUMOReal ad_r, SUMOReal ad_length)
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:65
SUMOReal length2D() const
Returns the length.
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:132
std::vector< OpenDriveLink > links
A handler which converts occuring elements and attributes into enums.
OpenDriveLaneSection buildLaneSection(SUMOReal startPos)
SUMOReal getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:181
const std::string & getFileName() const
returns the current file name
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node.
Definition: NBNode.h:318
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:161
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
static Position calculateStraightEndPoint(double hdg, double length, const Position &start)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Returns the edge container.
Definition: NBNetBuilder.h:154
void computeSpiral(std::vector< Point2D< double > > &spiral, double ds=0, int NPts=0)
Definition: euler.cpp:262
std::string id
The id of the edge.
A list of positions.
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)
const NBTypeCont & myTypeContainer
SUMOReal width
The lane&#39;s width;.
Position positionAtOffset(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
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:187
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
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
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:54
The connection was given by the user.
Definition: NBEdge.h:113
static PositionVector geomFromSpiral(const OpenDriveEdge &e, const OpenDriveGeometry &g)
static PositionVector geomFromPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g)
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:140
void buildLaneMapping(const NBTypeCont &tc)
Build the mapping from OpenDrive to SUMO lanes.
std::vector< OpenDriveSignal > signals
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
LinkType
OpenDrive link type enumeration.
void addParameter(const std::string &key, const std::string &value)
Adds a parameter.
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:369
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:312
void removeDoublePoints(SUMOReal minDist=POSITION_EPS, bool assertLength=false)
Removes positions if too near.
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:246
std::map< int, int > getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection &prev)
Returns the links from the previous to this lane section.
NBNodeCont & getNodeCont()
Returns the node container.
Definition: NBNetBuilder.h:162
SUMOReal speed
The lane&#39;s speed (set in post-processing)
Instance responsible for building networks.
Definition: NBNetBuilder.h:113
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
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
A storage for options typed value containers)
Definition: OptionsCont.h:108
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:80
NBTrafficLightLogicCont & getTLLogicCont()
Returns the traffic light logics container.
Definition: NBNetBuilder.h:178
unsigned int rightLaneNumber
The number of lanes on the right and on the left side, respectively.
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:74
T get(const std::string &str) const
Lane & getLaneStruct(unsigned int lane)
Definition: NBEdge.h:1067
A class for sorting lane sections by their s-value.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
#define SUMOReal
Definition: config.h:213
static void setNodeSecure(NBNodeCont &nc, OpenDriveEdge &e, const std::string &nodeID, NIImporter_OpenDrive::LinkType lt)
void push_back_noDoublePos(const Position &p)
A connection between two roads.
void addGeometryShape(GeometryType type, const std::vector< SUMOReal > &vals)
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.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:109
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:64
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
SUMOReal length
The length of the edge.
#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
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:763
Importer for networks stored in openDrive format.
std::vector< std::pair< SUMOReal, SUMOReal > > speeds
List of positions/speeds of speed changes.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
SUMOReal width
This lane&#39;s width.
Definition: NBEdge.h:138
#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.
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
static void revisitLaneSections(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Rechecks lane sections of the given edges.