SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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-sim.org/
13 // Copyright (C) 2001-2014 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 // ===========================================================================
72 // static variables
73 // ===========================================================================
95 
97 };
98 
99 
131 
133 };
134 
135 
138 
139 // ===========================================================================
140 // method definitions
141 // ===========================================================================
142 // ---------------------------------------------------------------------------
143 // static methods (interface in this case)
144 // ---------------------------------------------------------------------------
145 void
147  // check whether the option is set (properly)
148  if (!oc.isUsableFileList("opendrive-files")) {
149  return;
150  }
151  // prepare types
152  myImportAllTypes = oc.getBool("opendrive.import-all-lanes");
153  myImportWidths = !oc.getBool("opendrive.ignore-widths");
154  NBTypeCont& tc = nb.getTypeCont();
155  const SUMOReal WIDTH(3.65); // as wanted
156  tc.insert("driving", 1, (SUMOReal)(80. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
157  tc.insert("mwyEntry", 1, (SUMOReal)(80. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
158  tc.insert("mwyExit", 1, (SUMOReal)(80. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
159  tc.insert("stop", 1, (SUMOReal)(80. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
160  tc.insert("special1", 1, (SUMOReal)(80. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
161  tc.insert("parking", 1, (SUMOReal)(5. / 3.6), 1, ~SVC_PEDESTRIAN, WIDTH, true);
162  // build the handler
163  std::map<std::string, OpenDriveEdge*> edges;
164  NIImporter_OpenDrive handler(tc, edges);
165  // parse file(s)
166  std::vector<std::string> files = oc.getStringVector("opendrive-files");
167  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
168  if (!FileHelpers::exists(*file)) {
169  WRITE_ERROR("Could not open opendrive file '" + *file + "'.");
170  return;
171  }
172  handler.setFileName(*file);
173  PROGRESS_BEGIN_MESSAGE("Parsing opendrive from '" + *file + "'");
174  XMLSubSys::runParser(handler, *file);
176  }
177  // split inner/outer edges
178  std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
179  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
180  if ((*i).second->isInner) {
181  innerEdges[(*i).first] = (*i).second;
182  } else {
183  outerEdges[(*i).first] = (*i).second;
184  }
185  }
186 
187  // convert geometries into a discretised representation
188  computeShapes(edges);
189  // check whether lane sections are valid and whether further must be introduced
190  revisitLaneSections(tc, edges);
191 
192  // -------------------------
193  // node building
194  // -------------------------
195  // build nodes#1
196  // look at all links which belong to a node, collect their bounding boxes
197  // and place the node in the middle of this bounding box
198  std::map<std::string, Boundary> posMap;
199  std::map<std::string, std::string> edge2junction;
200  // compute node positions
201  for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
202  OpenDriveEdge* e = (*i).second;
203  assert(e->junction != "-1" && e->junction != "");
204  edge2junction[e->id] = e->junction;
205  if (posMap.find(e->junction) == posMap.end()) {
206  posMap[e->junction] = Boundary();
207  }
208  posMap[e->junction].add(e->geom.getBoxBoundary());
209  }
210  // build nodes
211  for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
212  if (!nb.getNodeCont().insert((*i).first, (*i).second.getCenter())) {
213  throw ProcessError("Could not add node '" + (*i).first + "'.");
214  }
215  }
216  // assign built nodes
217  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
218  OpenDriveEdge* e = (*i).second;
219  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
220  OpenDriveLink& l = *j;
221  if (l.elementType != OPENDRIVE_ET_ROAD) {
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 connectiosn 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  SUMOReal cF = e->length / e->geom.length2D();
335  NBEdge* prevRight = 0;
336  NBEdge* prevLeft = 0;
337 
338  // starting at the same node as ending, and no lane sections?
339  if (sFrom == sTo && e->laneSections.size() == 1) {
340  // --> loop, split!
342  ls.s = e->length / 2.;
343  e->laneSections.push_back(ls);
344  WRITE_WARNING("Edge '" + e->id + "' has to be split as it connects same junctions.")
345  }
346 
347  // build along lane sections
348  for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
349  // add internal node if needed
350  if (j == e->laneSections.end() - 1) {
351  sTo = e->to;
352  sE = e->length / cF;
353  } else {
354  SUMOReal nextS = (j + 1)->s;
355  sTo = new NBNode(e->id + "." + toString(nextS), e->geom.positionAtOffset(nextS));
356  if (!nb.getNodeCont().insert(sTo)) {
357  throw ProcessError("Could not add node '" + sTo->getID() + "'.");
358  }
359  sE = nextS / cF;
360  }
361  PositionVector geom = e->geom.getSubpart2D(sB, sE);
362  std::string id = e->id;
363  if (sFrom != e->from || sTo != e->to) {
364  id = id + "." + toString((*j).s);
365  } else if (e->laneSections.size() == 1) {
366  id = id + ".0.00";
367  }
368 
369  // build lanes to right
370  NBEdge* currRight = 0;
371  if ((*j).rightLaneNumber > 0) {
372  currRight = new NBEdge("-" + id, sFrom, sTo, "", defaultSpeed, (*j).rightLaneNumber, priorityR,
374  if (!nb.getEdgeCont().insert(currRight)) {
375  throw ProcessError("Could not add edge '" + currRight->getID() + "'.");
376  }
377  lanesBuilt = true;
378  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_RIGHT];
379  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
380  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
381  if (lp != (*j).laneMap.end()) {
382  int sumoLaneIndex = lp->second;
383  NBEdge::Lane& sumoLane = currRight->getLaneStruct(sumoLaneIndex);
384  const OpenDriveLane& odLane = *k;
385 
386  sumoLane.origID = e->id + " -" + toString((*k).id);
387  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
388  sumoLane.permissions = tc.getPermissions(odLane.type);
389  sumoLane.width = myImportWidths && odLane.width != 0 ? odLane.width : tc.getWidth(odLane.type);
390  }
391  }
392  // connect lane sections
393  if (prevRight != 0) {
394  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_RIGHT, *(j - 1));
395  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
396  prevRight->addLane2LaneConnection((*k).first, currRight, (*k).second, NBEdge::L2L_VALIDATED);
397  }
398  }
399  prevRight = currRight;
400  }
401 
402  // build lanes to left
403  NBEdge* currLeft = 0;
404  if ((*j).leftLaneNumber > 0) {
405  currLeft = new NBEdge(id, sTo, sFrom, "", defaultSpeed, (*j).leftLaneNumber, priorityL,
407  if (!nb.getEdgeCont().insert(currLeft)) {
408  throw ProcessError("Could not add edge '" + currLeft->getID() + "'.");
409  }
410  lanesBuilt = true;
411  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_LEFT];
412  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
413  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
414  if (lp != (*j).laneMap.end()) {
415  int sumoLaneIndex = lp->second;
416  NBEdge::Lane& sumoLane = currLeft->getLaneStruct(sumoLaneIndex);
417  const OpenDriveLane& odLane = *k;
418 
419  sumoLane.origID = e->id + " " + toString((*k).id);
420  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
421  sumoLane.permissions = tc.getPermissions(odLane.type);
422  sumoLane.width = myImportWidths && odLane.width != 0 ? odLane.width : tc.getWidth(odLane.type);
423  }
424  }
425  // connect lane sections
426  if (prevLeft != 0) {
427  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_LEFT, *(j - 1));
428  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
429  currLeft->addLane2LaneConnection((*k).first, prevLeft, (*k).second, NBEdge::L2L_VALIDATED);
430  }
431  }
432  prevLeft = currLeft;
433  }
434  (*j).sumoID = id;
435 
436 
437  sB = sE;
438  sFrom = sTo;
439  }
440  if (!lanesBuilt) {
441  WRITE_WARNING("Edge '" + e->id + "' has no lanes.");
442  }
443  }
444 
445  // -------------------------
446  // connections building
447  // -------------------------
448  // generate explicit lane-to-lane connections
449  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
450  setEdgeLinks2(*(*i).second, edges);
451  }
452  // compute connections across intersections, if any
453  std::vector<Connection> connections2;
454  for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
455  const std::set<Connection>& conns = (*j).second->connections;
456 
457  for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
458  if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
459  // connections starting at inner edges are processed by starting from outer edges
460  continue;
461  }
462  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
463  buildConnectionsToOuter(*i, innerEdges, connections2);
464  } else {
465  connections2.push_back(*i);
466  }
467  }
468  }
469  // set connections
470  for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
471  std::string fromEdge = (*i).fromEdge;
472  if (edges.find(fromEdge) == edges.end()) {
473  WRITE_WARNING("While setting connections: from-edge '" + fromEdge + "' is not known.");
474  continue;
475  }
476  OpenDriveEdge* odFrom = edges[fromEdge];
477  int fromLane = (*i).fromLane;
478  bool fromLast = ((*i).fromCP == OPENDRIVE_CP_END) ^ ((*i).fromLane > 0 && !(*i).all);
479  fromEdge = fromLast ? odFrom->laneSections.back().sumoID : odFrom->laneSections[0].sumoID;
480 
481  std::string toEdge = (*i).toEdge;
482  if (edges.find(toEdge) == edges.end()) {
483  WRITE_WARNING("While setting connections: to-edge '" + toEdge + "' is not known.");
484  continue;
485  }
486 
487  OpenDriveEdge* odTo = edges[toEdge];
488  int toLane = (*i).toLane;
489  bool toLast = ((*i).toCP == OPENDRIVE_CP_END) || ((*i).toLane > 0);
490  toEdge = toLast ? odTo->laneSections.back().sumoID : odTo->laneSections[0].sumoID;
491 
492  if (fromLane == UNSET_CONNECTION) {
493  fromLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
494  }
495  if (fromLane < 0) {
496  fromEdge = revertID(fromEdge);
497  }
498  if (toLane == UNSET_CONNECTION) {
499  toLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
500  }
501  if (toLane < 0) {
502  toEdge = revertID(toEdge);
503  }
504  fromLane = fromLast ? odFrom->laneSections.back().laneMap[fromLane] : odFrom->laneSections[0].laneMap[fromLane];
505  toLane = toLast ? odTo->laneSections.back().laneMap[toLane] : odTo->laneSections[0].laneMap[toLane];
506  NBEdge* from = nb.getEdgeCont().retrieve(fromEdge);
507  NBEdge* to = nb.getEdgeCont().retrieve(toEdge);
508  if (from == 0) {
509  WRITE_WARNING("Could not find fromEdge representation of '" + fromEdge + "' in connection '" + (*i).origID + "'.");
510  }
511  if (to == 0) {
512  WRITE_WARNING("Could not find fromEdge representation of '" + toEdge + "' in connection '" + (*i).origID + "'.");
513  }
514  if (from == 0 || to == 0) {
515  continue;
516  }
517 
518  from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER);
519 
520  if ((*i).origID != "") {
521  // @todo: this is the most silly way to determine the connection
522  std::vector<NBEdge::Connection>& cons = from->getConnections();
523  for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
524  if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
525  (*k).origID = (*i).origID + " " + toString((*i).origLane);
526  break;
527  }
528  }
529  }
530  }
531 
532 
533  // -------------------------
534  // traffic lights
535  // -------------------------
536  std::map<std::string, std::string> tlsControlled;
537  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
538  OpenDriveEdge* e = (*i).second;
539  for (std::vector<OpenDriveSignal>::const_iterator j = e->signals.begin(); j != e->signals.end(); ++j) {
540  if ((*j).type != "1000001") {
541  continue;
542  }
543  std::vector<OpenDriveLaneSection>::iterator k = e->laneSections.begin();
544  bool found = false;
545  for (; k != e->laneSections.end() - 1 && !found;) {
546  if ((*j).s > (*k).s && (*j).s <= (*(k + 1)).s) {
547  found = true;
548  } else {
549  ++k;
550  }
551  }
552 
553  // @todo: major problem, currently, still not completely solved:
554  // inner edges may have traffic lights, too. Nice on one hand, as directions can be recognized
555  // but hard to follow backwards
556  std::string id = (*k).sumoID;
557  if (id == "") {
558  if (e->junction != "") {
559  //WRITE_WARNING("Found a traffic light signal on an internal edge; will not build it (original edge id='" + e->id + "').");
560  std::string fromID, toID;
561  for (std::vector<OpenDriveLink>::const_iterator l = e->links.begin(); l != e->links.end(); ++l) {
562  if ((*l).linkType == OPENDRIVE_LT_PREDECESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
563  if (fromID != "") {
564  WRITE_WARNING("Ambigous start of connection.");
565  }
566  fromID = (*l).elementID;
567  OpenDriveEdge* e = edges[fromID];
568  fromID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
569  }
570  if ((*l).linkType == OPENDRIVE_LT_SUCCESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
571  if (toID != "") {
572  WRITE_WARNING("Ambigous end of connection.");
573  }
574  toID = (*l).elementID;
575  OpenDriveEdge* e = edges[toID];
576  toID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
577  }
578  }
579  id = fromID + "->" + toID;
580  } else {
581  WRITE_WARNING("Found a traffic light signal on an unknown edge (original edge id='" + e->id + "').");
582  continue;
583  }
584  }
585 
586  if ((*j).orientation > 0) {
587  id = "-" + id;
588  }
589  tlsControlled[id] = (*j).name;
590  }
591  }
592 
593  for (std::map<std::string, std::string>::iterator i = tlsControlled.begin(); i != tlsControlled.end(); ++i) {
594  std::string id = (*i).first;
595  if (id.find("->") != std::string::npos) {
596  id = id.substr(0, id.find("->"));
597  }
598  NBEdge* e = nb.getEdgeCont().retrieve(id);
599  if (e == 0) {
600  WRITE_WARNING("Could not find edge '" + id + "' while building its traffic light.");
601  continue;
602  }
603  NBNode* toNode = e->getToNode();
604  NBTrafficLightDefinition* tlDef = 0;
605  if (!toNode->isTLControlled()) {
607  tlDef = new NBOwnTLDef(toNode->getID(), toNode, 0, type);
608  if (!nb.getTLLogicCont().insert(tlDef)) {
609  // actually, nothing should fail here
610  delete tlDef;
611  throw ProcessError();
612  }
613  toNode->addTrafficLight(tlDef);
614  static_cast<NBOwnTLDef*>(tlDef)->setSinglePhase();
615  }
616  tlDef = *toNode->getControllingTLS().begin();
617  tlDef->addParameter("connection:" + id, (*i).second);
618  }
619 
620  // -------------------------
621  // clean up
622  // -------------------------
623  if (oc.exists("geometry.min-dist") && oc.isSet("geometry.min-dist")) {
624  oc.unSet("geometry.min-dist");
625  }
626  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
627  delete(*i).second;
628  }
629 }
630 
631 
632 
633 void
634 NIImporter_OpenDrive::buildConnectionsToOuter(const Connection& c, const std::map<std::string, OpenDriveEdge*>& innerEdges, std::vector<Connection>& into) {
635 
636  OpenDriveEdge* dest = innerEdges.find(c.toEdge)->second;
637  if (dest == 0) {
639  return;
640  }
641  const std::set<Connection>& conts = dest->connections;
642  for (std::set<Connection>::const_iterator i = conts.begin(); i != conts.end(); ++i) {
643  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
644  std::vector<Connection> t;
645  buildConnectionsToOuter(*i, innerEdges, t);
646  for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
647  // @todo this section is unverified
648  Connection cn = (*j);
649  cn.fromEdge = c.fromEdge;
650  cn.fromLane = c.fromLane;
651  cn.fromCP = c.fromCP;
652  cn.all = c.all; // @todo "all" is a hack trying to avoid the "from is zero" problem;
653  into.push_back(cn);
654  }
655  } else {
656  if ((*i).fromLane == c.toLane) {
657  Connection cn = (*i);
658  cn.fromEdge = c.fromEdge;
659  cn.fromLane = c.fromLane;
660  cn.fromCP = c.fromCP;
661  cn.all = c.all;
662  cn.origID = c.toEdge;
663  cn.origLane = c.toLane;
664  into.push_back(cn);
665  }
666  }
667  }
668 }
669 
670 
671 void
672 NIImporter_OpenDrive::setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges) {
673  for (std::vector<OpenDriveLink>::iterator i = e.links.begin(); i != e.links.end(); ++i) {
674  OpenDriveLink& l = *i;
675  if (l.elementType != OPENDRIVE_ET_ROAD) {
676  // we assume that links to nodes are later given as connections to edges
677  continue;
678  }
679  // get the right direction of the connected edge
680  std::string connectedEdge = l.elementID;
681  std::string edgeID = e.id;
682 
683  OpenDriveLaneSection& laneSection = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e.laneSections.back() : e.laneSections[0];
684  const std::map<int, int>& laneMap = laneSection.laneMap;
685  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
686  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
687  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
688  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
689  continue;
690  }
691  Connection c; // @todo: give Connection a new name and a constructor
692  c.fromEdge = e.id;
693  c.fromLane = (*j).id;
695  c.toLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
696  c.toEdge = connectedEdge;
697  c.toCP = l.contactPoint;
698  c.all = false;
699  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
700  std::swap(c.fromEdge, c.toEdge);
701  std::swap(c.fromLane, c.toLane);
702  std::swap(c.fromCP, c.toCP);
703  }
704  if (edges.find(c.fromEdge) == edges.end()) {
705  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
706  } else {
707  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
708  src->connections.insert(c);
709  }
710  }
711  }
712  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
713  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
714  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
715  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
716  continue;
717  }
718  Connection c;
719  c.toEdge = e.id;
720  c.toLane = (*j).id;
722  c.fromLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
723  c.fromEdge = connectedEdge;
724  c.fromCP = l.contactPoint;
725  c.all = false;
726  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
727  std::swap(c.fromEdge, c.toEdge);
728  std::swap(c.fromLane, c.toLane);
729  std::swap(c.fromCP, c.toCP);
730  }
731  if (edges.find(c.fromEdge) == edges.end()) {
732  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
733  } else {
734  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
735  src->connections.insert(c);
736  }
737  }
738  }
739  }
740 }
741 
742 
743 std::string NIImporter_OpenDrive::revertID(const std::string& id) {
744  if (id[0] == '-') {
745  return id.substr(1);
746  }
747  return "-" + id;
748 }
749 
750 NBNode*
751 NIImporter_OpenDrive::getOrBuildNode(const std::string& id, const Position& pos,
752  NBNodeCont& nc) {
753  if (nc.retrieve(id) == 0) {
754  // not yet built; build now
755  if (!nc.insert(id, pos)) {
756  // !!! clean up
757  throw ProcessError("Could not add node '" + id + "'.");
758  }
759  }
760  return nc.retrieve(id);
761 }
762 
763 
764 void
766  const std::string& nodeID, NIImporter_OpenDrive::LinkType lt) {
767  NBNode* n = nc.retrieve(nodeID);
768  if (n == 0) {
769  throw ProcessError("Could not find node '" + nodeID + "'.");
770  }
771  if (lt == OPENDRIVE_LT_SUCCESSOR) {
772  if (e.to != 0 && e.to != n) {
773  throw ProcessError("Edge '" + e.id + "' has two end nodes.");
774  }
775  e.to = n;
776  } else {
777  if (e.from != 0 && e.from != n) {
778  throw ProcessError("Edge '" + e.id + "' has two start nodes.");
779  }
780  e.from = n;
781  }
782 }
783 
784 
785 
786 
787 
788 
789 
790 void
791 NIImporter_OpenDrive::computeShapes(std::map<std::string, OpenDriveEdge*>& edges) {
793  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
794  OpenDriveEdge& e = *(*i).second;
795  for (std::vector<OpenDriveGeometry>::iterator j = e.geometries.begin(); j != e.geometries.end(); ++j) {
796  OpenDriveGeometry& g = *j;
797  std::vector<Position> geom;
798  switch (g.type) {
800  break;
801  case OPENDRIVE_GT_LINE:
802  geom = geomFromLine(e, g);
803  break;
804  case OPENDRIVE_GT_SPIRAL:
805  geom = geomFromSpiral(e, g);
806  break;
807  case OPENDRIVE_GT_ARC:
808  geom = geomFromArc(e, g);
809  break;
810  case OPENDRIVE_GT_POLY3:
811  geom = geomFromPoly(e, g);
812  break;
813  default:
814  break;
815  }
816  for (std::vector<Position>::iterator k = geom.begin(); k != geom.end(); ++k) {
818  }
819  }
820  if (oc.exists("geometry.min-dist") && oc.isSet("geometry.min-dist")) {
821  e.geom.removeDoublePoints(oc.getFloat("geometry.min-dist"), true);
822  }
823  for (unsigned int j = 0; j < e.geom.size(); ++j) {
825  WRITE_ERROR("Unable to project coordinates for.");
826  }
827  }
828  }
829 }
830 
831 
832 void
833 NIImporter_OpenDrive::revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges) {
834  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
835  OpenDriveEdge& e = *(*i).second;
836  std::vector<OpenDriveLaneSection>& laneSections = e.laneSections;
837  // split by speed limits
838  std::vector<OpenDriveLaneSection> newSections;
839  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end(); ++j) {
840  std::vector<OpenDriveLaneSection> splitSections;
841  bool splitBySpeed = (*j).buildSpeedChanges(tc, splitSections);
842  if (!splitBySpeed) {
843  newSections.push_back(*j);
844  } else {
845  std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
846  }
847  }
848 
849  e.laneSections = newSections;
850  laneSections = e.laneSections;
851  SUMOReal lastS = -1;
852  // check whether the lane sections are in the right order
853  bool sorted = true;
854  for (std::vector<OpenDriveLaneSection>::const_iterator j = laneSections.begin(); j != laneSections.end() && sorted; ++j) {
855  if ((*j).s <= lastS) {
856  sorted = false;
857  }
858  lastS = (*j).s;
859  }
860  if (!sorted) {
861  WRITE_WARNING("The sections of edge '" + e.id + "' are not sorted properly.");
862  sort(e.laneSections.begin(), e.laneSections.end(), sections_by_s_sorter());
863  }
864  // check whether no duplicates of s-value occure
865  lastS = -1;
866  laneSections = e.laneSections;
867  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end();) {
868  bool simlarToLast = fabs((*j).s - lastS) < POSITION_EPS;
869  lastS = (*j).s;
870  if (simlarToLast) {
871  WRITE_WARNING("Almost duplicate s-value '" + toString(lastS) + "' for lane sections occured at edge '" + e.id + "'; second entry was removed.");
872  j = laneSections.erase(j);
873  } else {
874  ++j;
875  }
876  }
877  }
878 }
879 
880 
881 std::vector<Position>
883  UNUSED_PARAMETER(e);
884  std::vector<Position> ret;
885  ret.push_back(Position(g.x, g.y));
886  ret.push_back(calculateStraightEndPoint(g.hdg, g.length, Position(g.x, g.y)));
887  return ret;
888 }
889 
890 
891 std::vector<Position>
893  UNUSED_PARAMETER(e);
894  std::vector<Position> ret;
895  SUMOReal curveStart = g.params[0];
896  SUMOReal curveEnd = g.params[1];
897  Point2D<double> end;
898  EulerSpiral s(Point2D<double>(g.x, g.y), g.hdg, curveStart, (curveEnd - curveStart) / g.length, g.length);
899  std::vector<Point2D<double> > into;
900  s.computeSpiral(into, 1.);
901  for (std::vector<Point2D<double> >::iterator i = into.begin(); i != into.end(); ++i) {
902  ret.push_back(Position((*i).getX(), (*i).getY()));
903  }
904  return ret;
905 }
906 
907 
908 std::vector<Position>
910  UNUSED_PARAMETER(e);
911  std::vector<Position> ret;
912  SUMOReal dist = 0.0;
913  SUMOReal centerX = g.x;
914  SUMOReal centerY = g.y;
915  // left: positive value
916  SUMOReal curvature = g.params[0];
917  SUMOReal radius = 1. / curvature;
918  // center point
919  calculateCurveCenter(&centerX, &centerY, radius, g.hdg);
920  SUMOReal endX = g.x;
921  SUMOReal endY = g.y;
922  SUMOReal startX = g.x;
923  SUMOReal startY = g.y;
924  SUMOReal geo_posS = g.s;
925  SUMOReal geo_posE = g.s;
926  bool end = false;
927  do {
928  geo_posE += C_LENGTH;
929  if (geo_posE - g.s > g.length) {
930  geo_posE = g.s + g.length;
931  }
932  if (geo_posE - g.s > g.length) {
933  geo_posE = g.s + g.length;
934  }
935  calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
936 
937  dist += (geo_posE - geo_posS);
938  //
939  ret.push_back(Position(startX, startY));
940  //
941  startX = endX;
942  startY = endY;
943  geo_posS = geo_posE;
944 
945  if (geo_posE - (g.s + g.length) < 0.001 && geo_posE - (g.s + g.length) > -0.001) {
946  end = true;
947  }
948  } while (!end);
949  return ret;
950 }
951 
952 
953 std::vector<Position>
955  UNUSED_PARAMETER(e);
956  std::vector<Position> ret;
957  for (SUMOReal off = 0; off < g.length + 2.; off += 2.) {
958  SUMOReal x = off;
959  SUMOReal y = g.params[0] + g.params[1] * off + g.params[2] * pow(off, 2.) + g.params[3] * pow(off, 3.);
960  SUMOReal s = sin(g.hdg);
961  SUMOReal c = cos(g.hdg);
962  SUMOReal xnew = x * c - y * s;
963  SUMOReal ynew = x * s + y * c;
964  ret.push_back(Position(g.x + xnew, g.y + ynew));
965  }
966  return ret;
967 }
968 
969 
970 Position
971 NIImporter_OpenDrive::calculateStraightEndPoint(double hdg, double length, const Position& start) {
972  double normx = 1.0f;
973  double normy = 0.0f;
974  double x2 = normx * cos(hdg) - normy * sin(hdg);
975  double y2 = normx * sin(hdg) + normy * cos(hdg);
976  normx = x2 * length;
977  normy = y2 * length;
978  return Position(start.x() + normx, start.y() + normy);
979 }
980 
981 
982 void
984  SUMOReal normX = 1.0;
985  SUMOReal normY = 0.0;
986  SUMOReal tmpX;
987  SUMOReal turn;
988  if (ad_radius > 0) {
989  turn = -1.0;
990  } else {
991  turn = 1.0;
992  }
993 
994  tmpX = normX;
995  normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
996  normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
997 
998  tmpX = normX;
999  normX = turn * normY;
1000  normY = -turn * tmpX;
1001 
1002  normX = fabs(ad_radius) * normX;
1003  normY = fabs(ad_radius) * normY;
1004 
1005  *ad_x += normX;
1006  *ad_y += normY;
1007 }
1008 
1009 
1010 void
1012  SUMOReal ad_r, SUMOReal ad_length) {
1013  double rotAngle = ad_length / fabs(ad_r);
1014  double vx = *ad_x - ad_centerX;
1015  double vy = *ad_y - ad_centerY;
1016  double tmpx;
1017 
1018  double turn;
1019  if (ad_r > 0) {
1020  turn = -1; //left
1021  } else {
1022  turn = 1; //right
1023  }
1024  tmpx = vx;
1025  vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
1026  vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
1027  *ad_x = vx + ad_centerX;
1028  *ad_y = vy + ad_centerY;
1029 }
1030 
1031 
1032 // ---------------------------------------------------------------------------
1033 // section
1034 // ---------------------------------------------------------------------------
1036  lanesByDir[OPENDRIVE_TAG_LEFT] = std::vector<OpenDriveLane>();
1037  lanesByDir[OPENDRIVE_TAG_RIGHT] = std::vector<OpenDriveLane>();
1038  lanesByDir[OPENDRIVE_TAG_CENTER] = std::vector<OpenDriveLane>();
1039 }
1040 
1041 
1042 void
1044  unsigned int sumoLane = 0;
1045  const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
1046  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
1047  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1048  laneMap[(*i).id] = sumoLane++;
1049  }
1050  }
1051  rightLaneNumber = sumoLane;
1052  sumoLane = 0;
1053  const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
1054  for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
1055  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1056  laneMap[(*i).id] = sumoLane++;
1057  }
1058  }
1059  leftLaneNumber = sumoLane;
1060 }
1061 
1062 
1063 std::map<int, int>
1065  std::map<int, int> ret;
1066  const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
1067  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
1068  std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
1069  if (toP == laneMap.end()) {
1070  // the current lane is not available in SUMO
1071  continue;
1072  }
1073  int to = (*toP).second;
1074  int from = UNSET_CONNECTION;
1075  if ((*i).predecessor != UNSET_CONNECTION) {
1076  from = (*i).predecessor;
1077  }
1078  if (from != UNSET_CONNECTION) {
1079  std::map<int, int>::const_iterator fromP = prev.laneMap.find(from);
1080  if (fromP != prev.laneMap.end()) {
1081  from = (*fromP).second;
1082  } else {
1083  from = UNSET_CONNECTION;
1084  }
1085  }
1086  if (from != UNSET_CONNECTION && to != UNSET_CONNECTION) {
1087  if (ret.find(from) != ret.end()) {
1088 // WRITE_WARNING("double connection");
1089  }
1090  if (dir == OPENDRIVE_TAG_LEFT) {
1091  std::swap(from, to);
1092  }
1093  ret[from] = to;
1094  } else {
1095 // WRITE_WARNING("missing connection");
1096  }
1097  }
1098  return ret;
1099 }
1100 
1101 
1104  OpenDriveLaneSection ret(*this);
1105  ret.s += startPos;
1106  for (unsigned int k = 0; k != ret.lanesByDir[OPENDRIVE_TAG_RIGHT].size(); ++k) {
1108  l.speed = 0;
1109  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1110  if (i != l.speeds.end()) {
1111  l.speed = (*i).second;
1112  }
1113  }
1114  for (unsigned int k = 0; k != ret.lanesByDir[OPENDRIVE_TAG_LEFT].size(); ++k) {
1116  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1117  l.speed = 0;
1118  if (i != l.speeds.end()) {
1119  l.speed = (*i).second;
1120  }
1121  }
1122  return ret;
1123 }
1124 
1125 
1126 bool
1127 NIImporter_OpenDrive::OpenDriveLaneSection::buildSpeedChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections) {
1128  std::set<SUMOReal> speedChangePositions;
1129  // collect speed change positions and apply initial speed to the begin
1130  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_RIGHT].begin(); k != lanesByDir[OPENDRIVE_TAG_RIGHT].end(); ++k) {
1131  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1132  speedChangePositions.insert((*l).first);
1133  if ((*l).first == 0) {
1134  (*k).speed = (*l).second;
1135  }
1136  }
1137  }
1138  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_LEFT].begin(); k != lanesByDir[OPENDRIVE_TAG_LEFT].end(); ++k) {
1139  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1140  speedChangePositions.insert((*l).first);
1141  if ((*l).first == 0) {
1142  (*k).speed = (*l).second;
1143  }
1144  }
1145  }
1146  // do nothing if there is none
1147  if (speedChangePositions.size() == 0) {
1148  return false;
1149  }
1150  if (*speedChangePositions.begin() > 0) {
1151  speedChangePositions.insert(0);
1152  }
1153  //
1154  for (std::set<SUMOReal>::iterator i = speedChangePositions.begin(); i != speedChangePositions.end(); ++i) {
1155  if (i == speedChangePositions.begin()) {
1156  newSections.push_back(*this);
1157  } else {
1158  newSections.push_back(buildLaneSection(*i));
1159  }
1160  }
1161  // propagate speeds
1162  for (int i = 0; i != (int)newSections.size(); ++i) {
1163  OpenDriveLaneSection& ls = newSections[i];
1164  std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >& lanesByDir = ls.lanesByDir;
1165  for (std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >::iterator k = lanesByDir.begin(); k != lanesByDir.end(); ++k) {
1166  std::vector<OpenDriveLane>& lanes = (*k).second;
1167  for (int j = 0; j != (int)lanes.size(); ++j) {
1168  OpenDriveLane& l = lanes[j];
1169  if (l.speed != 0) {
1170  continue;
1171  }
1172  if (i > 0) {
1173  l.speed = newSections[i - 1].lanesByDir[(*k).first][j].speed;
1174  } else {
1175  tc.getSpeed(l.type);
1176  }
1177  }
1178  }
1179  }
1180  return true;
1181 }
1182 
1183 
1184 
1185 // ---------------------------------------------------------------------------
1186 // edge
1187 // ---------------------------------------------------------------------------
1188 int
1190  int prio = 1;
1191  for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
1192  int tmp = 1;
1193  if ((*i).type == "301" || (*i).type == "306") {
1194  tmp = 2;
1195  }
1196  if ((*i).type == "205") {
1197  tmp = 0;
1198  }
1199  if (tmp != 1 && dir == OPENDRIVE_TAG_RIGHT && (*i).orientation > 0) {
1200  prio = tmp;
1201  }
1202  if (tmp != 1 && dir == OPENDRIVE_TAG_LEFT && (*i).orientation < 0) {
1203  prio = tmp;
1204  }
1205 
1206  }
1207  return prio;
1208 }
1209 
1210 
1211 
1212 // ---------------------------------------------------------------------------
1213 // loader methods
1214 // ---------------------------------------------------------------------------
1215 NIImporter_OpenDrive::NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges)
1217  myTypeContainer(tc), myCurrentEdge("", "", -1), myEdges(edges) {
1218 }
1219 
1220 
1222 }
1223 
1224 
1225 void
1227  const SUMOSAXAttributes& attrs) {
1228  bool ok = true;
1229  switch (element) {
1230  case OPENDRIVE_TAG_HEADER: {
1231  int majorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMAJOR, 0, ok);
1232  int minorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMINOR, 0, ok);
1233  if (majorVersion != 1 || minorVersion != 2) {
1234  WRITE_WARNING("Given openDrive file '" + getFileName() + "' uses version " + toString(majorVersion) + "." + toString(minorVersion) + ";\n Version 1.2 is supported.");
1235  }
1236  }
1237  break;
1238  case OPENDRIVE_TAG_ROAD: {
1239  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, 0, ok);
1240  std::string junction = attrs.get<std::string>(OPENDRIVE_ATTR_JUNCTION, id.c_str(), ok);
1241  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, id.c_str(), ok);
1242  myCurrentEdge = OpenDriveEdge(id, junction, length);
1243  }
1244  break;
1246  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1247  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1248  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1249  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1250  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1251  : "end";
1252  addLink(OPENDRIVE_LT_PREDECESSOR, elementType, elementID, contactPoint);
1253  }
1254  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1255  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1256  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1257  l.predecessor = no;
1258  }
1259  }
1260  break;
1261  case OPENDRIVE_TAG_SUCCESSOR: {
1262  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1263  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1264  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1265  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1266  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1267  : "start";
1268  addLink(OPENDRIVE_LT_SUCCESSOR, elementType, elementID, contactPoint);
1269  }
1270  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1271  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1272  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1273  l.successor = no;
1274  }
1275  }
1276  break;
1277  case OPENDRIVE_TAG_GEOMETRY: {
1278  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, myCurrentEdge.id.c_str(), ok);
1279  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1280  SUMOReal x = attrs.get<SUMOReal>(OPENDRIVE_ATTR_X, myCurrentEdge.id.c_str(), ok);
1281  SUMOReal y = attrs.get<SUMOReal>(OPENDRIVE_ATTR_Y, myCurrentEdge.id.c_str(), ok);
1282  SUMOReal hdg = attrs.get<SUMOReal>(OPENDRIVE_ATTR_HDG, myCurrentEdge.id.c_str(), ok);
1283  myCurrentEdge.geometries.push_back(OpenDriveGeometry(length, s, x, y, hdg));
1284  }
1285  break;
1286  case OPENDRIVE_TAG_LINE: {
1287  std::vector<SUMOReal> vals;
1289  }
1290  break;
1291  case OPENDRIVE_TAG_SPIRAL: {
1292  std::vector<SUMOReal> vals;
1293  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVSTART, myCurrentEdge.id.c_str(), ok));
1294  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVEND, myCurrentEdge.id.c_str(), ok));
1296  }
1297  break;
1298  case OPENDRIVE_TAG_ARC: {
1299  std::vector<SUMOReal> vals;
1300  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVATURE, myCurrentEdge.id.c_str(), ok));
1302  }
1303  break;
1304  case OPENDRIVE_TAG_POLY3: {
1305  std::vector<SUMOReal> vals;
1306  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok));
1307  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok));
1308  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok));
1309  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok));
1311  }
1312  break;
1314  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1316  }
1317  break;
1318  case OPENDRIVE_TAG_LEFT:
1320  break;
1321  case OPENDRIVE_TAG_CENTER:
1323  break;
1324  case OPENDRIVE_TAG_RIGHT:
1326  break;
1327  case OPENDRIVE_TAG_LANE: {
1328  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1329  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1330  std::string level = attrs.hasAttribute(OPENDRIVE_ATTR_LEVEL)
1331  ? attrs.get<std::string>(OPENDRIVE_ATTR_LEVEL, myCurrentEdge.id.c_str(), ok)
1332  : "";
1334  ls.lanesByDir[myCurrentLaneDirection].push_back(OpenDriveLane(id, level, type));
1335  }
1336  break;
1337  case OPENDRIVE_TAG_SIGNAL: {
1338  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1339  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1340  std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, myCurrentEdge.id.c_str(), ok, "", false);
1341  int orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, myCurrentEdge.id.c_str(), ok) == "-" ? -1 : 1;
1342  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1343  bool dynamic = attrs.get<std::string>(OPENDRIVE_ATTR_DYNAMIC, myCurrentEdge.id.c_str(), ok) == "no" ? false : true;
1344  myCurrentEdge.signals.push_back(OpenDriveSignal(id, type, name, orientation, dynamic, s));
1345  }
1346  break;
1348  myCurrentJunctionID = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1349  break;
1350  case OPENDRIVE_TAG_CONNECTION: {
1351  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1352  myCurrentIncomingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_INCOMINGROAD, myCurrentJunctionID.c_str(), ok);
1354  std::string cp = attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentJunctionID.c_str(), ok);
1356  myConnectionWasEmpty = true;
1357  }
1358  break;
1359  case OPENDRIVE_TAG_LANELINK: {
1360  int from = attrs.get<int>(OPENDRIVE_ATTR_FROM, myCurrentJunctionID.c_str(), ok);
1361  int to = attrs.get<int>(OPENDRIVE_ATTR_TO, myCurrentJunctionID.c_str(), ok);
1362  Connection c;
1364  c.toEdge = myCurrentConnectingRoad;
1365  c.fromLane = from;
1366  c.toLane = to;
1367  c.fromCP = OPENDRIVE_CP_END;
1368  c.toCP = myCurrentContactPoint;
1369  c.all = false;
1370  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1371  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1372  } else {
1373  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1374  e->connections.insert(c);
1375  myConnectionWasEmpty = false;
1376  }
1377  }
1378  break;
1379  case OPENDRIVE_TAG_WIDTH: {
1380  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1381  SUMOReal width = attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1382  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1383  l.width = MAX2(l.width, width);
1384  }
1385  }
1386  break;
1387  case OPENDRIVE_TAG_SPEED: {
1388  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1389  SUMOReal speed = attrs.get<SUMOReal>(OPENDRIVE_ATTR_MAX, myCurrentEdge.id.c_str(), ok);
1390  SUMOReal pos = attrs.get<SUMOReal>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
1391  myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().speeds.push_back(std::make_pair(pos, speed));
1392  }
1393  }
1394  break;
1395  default:
1396  break;
1397  }
1398  myElementStack.push_back(element);
1399 }
1400 
1401 
1402 void
1404  myElementStack.pop_back();
1405  switch (element) {
1406  case OPENDRIVE_TAG_ROAD:
1408  break;
1410  if (myConnectionWasEmpty) {
1411  Connection c;
1414  c.fromLane = 0;
1415  c.toLane = 0;
1418  c.all = true;
1419  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1420  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1421  } else {
1422  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1423  e->connections.insert(c);
1424  }
1425  }
1426  break;
1428  myCurrentEdge.laneSections.back().buildLaneMapping(myTypeContainer);
1429  }
1430  break;
1431  default:
1432  break;
1433  }
1434 }
1435 
1436 
1437 
1438 void
1439 NIImporter_OpenDrive::addLink(LinkType lt, const std::string& elementType,
1440  const std::string& elementID,
1441  const std::string& contactPoint) {
1442  OpenDriveLink l(lt, elementID);
1443  // elementType
1444  if (elementType == "road") {
1446  } else if (elementType == "junction") {
1448  }
1449  // contact point
1450  if (contactPoint == "start") {
1452  } else if (contactPoint == "end") {
1454  }
1455  // add
1456  myCurrentEdge.links.push_back(l);
1457 }
1458 
1459 
1460 void
1461 NIImporter_OpenDrive::addGeometryShape(GeometryType type, const std::vector<SUMOReal>& vals) {
1462  // checks
1463  if (myCurrentEdge.geometries.size() == 0) {
1464  throw ProcessError("Mismatching paranthesis in geometry definition for road '" + myCurrentEdge.id + "'");
1465  }
1467  if (last.type != OPENDRIVE_GT_UNKNOWN) {
1468  throw ProcessError("Double geometry information for road '" + myCurrentEdge.id + "'");
1469  }
1470  // set
1471  last.type = type;
1472  last.params = vals;
1473 }
1474 
1475 
1476 bool
1478  if (c1.fromEdge != c2.fromEdge) {
1479  return c1.fromEdge < c2.fromEdge;
1480  }
1481  if (c1.toEdge != c2.toEdge) {
1482  return c1.toEdge < c2.toEdge;
1483  }
1484  if (c1.fromLane != c2.fromLane) {
1485  return c1.fromLane < c2.fromLane;
1486  }
1487  return c1.toLane < c2.toLane;
1488 }
1489 
1490 
1491 
1492 /****************************************************************************/
1493 
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 StringBijection< int >::Entry openDriveAttrs[]
The names of openDrive-XML attributes (for passing to GenericSAXHandler)
NBTypeCont & getTypeCont()
Returns the type container.
Definition: NBNetBuilder.h:170
is a pedestrian
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
Position positionAtOffset(SUMOReal pos) const
Returns the position at the given length.
void addLink(LinkType lt, const std::string &elementType, const std::string &elementID, const std::string &contactPoint)
std::string junction
The id of the junction the edge belongs to.
GeometryType
OpenDrive geometry type enumeration.
static std::vector< Position > geomFromPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g)
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:221
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:71
Representation of an openDrive "link".
bool insert(const std::string &id, int noLanes, SUMOReal maxSpeed, int prio, SUMOReal width, SUMOVehicleClass vClasses=SVC_UNKNOWN, bool oneWayIsDefault=false)
Adds a type into the list. This is a simplified convenience form of insert, if only one allowed vehic...
Definition: NBTypeCont.cpp:60
The base class for traffic light logic definitions.
ContactPoint myCurrentContactPoint
bool addLane2LaneConnection(unsigned int fromLane, NBEdge *dest, unsigned int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition: NBEdge.cpp:617
SUMOReal s
The starting offset of this lane section.
T MAX2(T a, T b)
Definition: StdDefs.h:71
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
bool operator<(const NIImporter_OpenDrive::Connection &c1, const NIImporter_OpenDrive::Connection &c2)
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false)
Runs the given handler on the given file; returns if everything's ok.
Definition: XMLSubSys.cpp:114
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
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:38
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/s].
Definition: NBTypeCont.cpp:134
static NBNode * getOrBuildNode(const std::string &id, const Position &pos, NBNodeCont &nc)
Builds a node or returns the already built.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:196
The connection was computed and validated.
Definition: NBEdge.h:116
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:67
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:123
const std::string & getID() const
Returns the id.
Definition: Named.h:60
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:104
const std::string & getFileName() const
returns the current file name
void setFileName(const std::string &name)
Sets the current file name.
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node.
Definition: NBNode.h:235
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:164
std::string type
The lane's type.
int getPriority(OpenDriveXMLTag dir) const
Returns the edge'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
static bool exists(std::string path)
Checks whether the given file exists.
Definition: FileHelpers.cpp:57
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:198
#define POSITION_EPS
Definition: config.h:186
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:80
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:52
The connection was given by the user.
Definition: NBEdge.h:114
static StringBijection< int >::Entry openDriveTags[]
The names of openDrive-XML elements (for passing to GenericSAXHandler)
static std::vector< Position > geomFromLine(const OpenDriveEdge &e, const OpenDriveGeometry &g)
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:201
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's geometry.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:362
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:250
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:251
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'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:122
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:79
NBTrafficLightLogicCont & getTLLogicCont()
Returns the traffic light logics container.
Definition: NBNetBuilder.h:178
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:994
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:215
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:124
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:128
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:199
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:54
static std::vector< Position > geomFromArc(const OpenDriveEdge &e, const OpenDriveGeometry &g)
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:724
Importer for networks stored in openDrive format.
static std::vector< Position > geomFromSpiral(const OpenDriveEdge &e, const OpenDriveGeometry &g)
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's width.
Definition: NBEdge.h:138
#define UNSET_CONNECTION
TrafficLightType
A storage for available types of edges.
Definition: NBTypeCont.h:56
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.