SUMO - Simulation of Urban MObility
NIImporter_OpenDrive.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Importer for networks stored in openDrive format
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
13 // Copyright (C) 2001-2017 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 #include <string>
34 #include <cmath>
35 #include <iterator>
39 #include <utils/common/ToString.h>
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 #define POLY_RES 2.
70 #define PARAMPOLY3_RES 2.
71 #define SPIRAL_RES 1.
72 
73 // ===========================================================================
74 // static variables
75 // ===========================================================================
100 
102 };
103 
104 
145 
147 };
148 
149 
152 
153 // ===========================================================================
154 // method definitions
155 // ===========================================================================
156 // ---------------------------------------------------------------------------
157 // static methods (interface in this case)
158 // ---------------------------------------------------------------------------
159 void
161  // check whether the option is set (properly)
162  if (!oc.isUsableFileList("opendrive-files")) {
163  return;
164  }
165  // prepare types
166  myImportAllTypes = oc.getBool("opendrive.import-all-lanes");
167  myImportWidths = !oc.getBool("opendrive.ignore-widths");
168  NBTypeCont& tc = nb.getTypeCont();
169  // build the handler
170  std::map<std::string, OpenDriveEdge*> edges;
171  NIImporter_OpenDrive handler(nb.getTypeCont(), edges);
172  // parse file(s)
173  std::vector<std::string> files = oc.getStringVector("opendrive-files");
174  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
175  if (!FileHelpers::isReadable(*file)) {
176  WRITE_ERROR("Could not open opendrive file '" + *file + "'.");
177  return;
178  }
179  handler.setFileName(*file);
180  PROGRESS_BEGIN_MESSAGE("Parsing opendrive from '" + *file + "'");
181  XMLSubSys::runParser(handler, *file);
183  }
184  // split inner/outer edges
185  std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
186  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
187  if ((*i).second->isInner) {
188  innerEdges[(*i).first] = (*i).second;
189  } else {
190  outerEdges[(*i).first] = (*i).second;
191  }
192  }
193 
194  // convert geometries into a discretised representation
195  computeShapes(edges);
196  // check whether lane sections are valid and whether further must be introduced
197  revisitLaneSections(tc, edges);
198 
199  // -------------------------
200  // node building
201  // -------------------------
202  // build nodes#1
203  // look at all links which belong to a node, collect their bounding boxes
204  // and place the node in the middle of this bounding box
205  std::map<std::string, Boundary> posMap;
206  std::map<std::string, std::string> edge2junction;
207  // compute node positions
208  for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
209  OpenDriveEdge* e = (*i).second;
210  assert(e->junction != "-1" && e->junction != "");
211  edge2junction[e->id] = e->junction;
212  if (posMap.find(e->junction) == posMap.end()) {
213  posMap[e->junction] = Boundary();
214  }
215  posMap[e->junction].add(e->geom.getBoxBoundary());
216  }
217  // build nodes
218  for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
219  //std::cout << " import node=" << (*i).first << " z=" << (*i).second.getCenter() << " boundary=" << (*i).second << "\n";
220  if (!nb.getNodeCont().insert((*i).first, (*i).second.getCenter())) {
221  throw ProcessError("Could not add node '" + (*i).first + "'.");
222  }
223  }
224  // assign built nodes
225  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
226  OpenDriveEdge* e = (*i).second;
227  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
228  OpenDriveLink& l = *j;
229  const std::string& nid = l.elementID;
230  if (l.elementType != OPENDRIVE_ET_ROAD) {
231  if (nb.getNodeCont().retrieve(nid) == 0) {
232  // not yet seen, build (possibly a junction without connections)
233  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
234  if (!nb.getNodeCont().insert(nid, pos)) {
235  throw ProcessError("Could not build node '" + nid + "'.");
236  }
237  }
238  // set node information
240  continue;
241  }
242  if (edge2junction.find(l.elementID) != edge2junction.end()) {
243  // set node information of an internal road
244  setNodeSecure(nb.getNodeCont(), *e, edge2junction[l.elementID], l.linkType);
245  continue;
246  }
247  }
248  }
249  // we should now have all nodes set for links which are not outer edge-to-outer edge links
250 
251 
252  // build nodes#2
253  // build nodes for all outer edge-to-outer edge connections
254  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
255  OpenDriveEdge* e = (*i).second;
256  for (std::vector<OpenDriveLink>::iterator j = e->links.begin(); j != e->links.end(); ++j) {
257  OpenDriveLink& l = *j;
258  if (l.elementType != OPENDRIVE_ET_ROAD || edge2junction.find(l.elementID) != edge2junction.end()) {
259  // is a connection to an internal edge, or a node, skip
260  continue;
261  }
262  // we have a direct connection between to external edges
263  std::string id1 = e->id;
264  std::string id2 = l.elementID;
265  if (id1 < id2) {
266  std::swap(id1, id2);
267  }
268  std::string nid = id1 + "." + id2;
269  if (nb.getNodeCont().retrieve(nid) == 0) {
270  // not yet seen, build
271  Position pos = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e->geom[-1] : e->geom[0];
272  if (!nb.getNodeCont().insert(nid, pos)) {
273  throw ProcessError("Could not build node '" + nid + "'.");
274  }
275  }
276  /* debug-stuff
277  else {
278  Position pos = l.linkType==OPENDRIVE_LT_SUCCESSOR ? e.geom[e.geom.size()-1] : e.geom[0];
279  cout << nid << " " << pos << " " << nb.getNodeCont().retrieve(nid)->getPosition() << endl;
280  }
281  */
282  setNodeSecure(nb.getNodeCont(), *e, nid, l.linkType);
283  }
284  }
285  // we should now have start/end nodes for all outer edge-to-outer edge connections
286 
287 
288  // build nodes#3
289  // assign further nodes generated from inner-edges
290  // these nodes have not been assigned earlier, because the connections are referenced in inner-edges
291  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
292  OpenDriveEdge* e = (*i).second;
293  if (e->to != 0 && e->from != 0) {
294  continue;
295  }
296  for (std::map<std::string, OpenDriveEdge*>::iterator j = innerEdges.begin(); j != innerEdges.end(); ++j) {
297  OpenDriveEdge* ie = (*j).second;
298  for (std::vector<OpenDriveLink>::iterator k = ie->links.begin(); k != ie->links.end(); ++k) {
299  OpenDriveLink& il = *k;
300  if (il.elementType != OPENDRIVE_ET_ROAD || il.elementID != e->id) {
301  // not conneted to the currently investigated outer edge
302  continue;
303  }
304  std::string nid = edge2junction[ie->id];
305  if (il.contactPoint == OPENDRIVE_CP_START) {
307  } else {
309  }
310  }
311  }
312 
313  }
314 
315  // build start/end nodes which were not defined previously
316  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
317  OpenDriveEdge* e = (*i).second;
318  if (e->from == 0) {
319  const std::string nid = e->id + ".begin";
320  e->from = getOrBuildNode(nid, e->geom.front(), nb.getNodeCont());
321  }
322  if (e->to == 0) {
323  const std::string nid = e->id + ".end";
324  e->to = getOrBuildNode(nid, e->geom.back(), nb.getNodeCont());
325  }
326  }
327 
328 
329  // -------------------------
330  // edge building
331  // -------------------------
332  SUMOReal defaultSpeed = tc.getSpeed("");
333  // build edges
334  for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
335  OpenDriveEdge* e = (*i).second;
336  bool lanesBuilt = false;
337 
338  // go along the lane sections, build a node in between of each pair
339 
342 
344  NBNode* sFrom = e->from;
345  NBNode* sTo = e->to;
346  int priorityR = e->getPriority(OPENDRIVE_TAG_RIGHT);
347  int priorityL = e->getPriority(OPENDRIVE_TAG_LEFT);
348  SUMOReal sB = 0;
349  SUMOReal sE = e->length;
350  // 0-length geometries are possible if only the inner points are represented
351  const SUMOReal length2D = e->geom.length2D();
352  SUMOReal cF = length2D == 0 ? 1 : e->length / length2D;
353  NBEdge* prevRight = 0;
354  NBEdge* prevLeft = 0;
355 
356  // starting at the same node as ending, and no lane sections?
357  if (sFrom == sTo && e->laneSections.size() == 1) {
358  // --> loop, split!
360  ls.s = e->length / 2.;
361  e->laneSections.push_back(ls);
362  WRITE_WARNING("Edge '" + e->id + "' has to be split as it connects same junctions.")
363  }
364 
365  // build along lane sections
366  for (std::vector<OpenDriveLaneSection>::iterator j = e->laneSections.begin(); j != e->laneSections.end(); ++j) {
367  // add internal node if needed
368  if (j == e->laneSections.end() - 1) {
369  sTo = e->to;
370  sE = e->length / cF;
371  } else {
372  SUMOReal nextS = (j + 1)->s;
373  sTo = new NBNode(e->id + "." + toString(nextS), e->geom.positionAtOffset(nextS));
374  if (!nb.getNodeCont().insert(sTo)) {
375  throw ProcessError("Could not add node '" + sTo->getID() + "'.");
376  }
377  sE = nextS / cF;
378  }
379  PositionVector geom = e->geom.getSubpart2D(sB, sE);
380  std::string id = e->id;
381  if (sFrom != e->from || sTo != e->to) {
382  id = id + "." + toString((*j).s);
383  } else if (e->laneSections.size() == 1) {
384  id = id + ".0.00";
385  }
386 
387  // build lanes to right
388  NBEdge* currRight = 0;
389  if ((*j).rightLaneNumber > 0) {
390  currRight = new NBEdge("-" + id, sFrom, sTo, (*j).rightType, defaultSpeed, (*j).rightLaneNumber, priorityR,
392  lanesBuilt = true;
393  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_RIGHT];
394  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
395  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
396  if (lp != (*j).laneMap.end()) {
397  int sumoLaneIndex = lp->second;
398  NBEdge::Lane& sumoLane = currRight->getLaneStruct(sumoLaneIndex);
399  const OpenDriveLane& odLane = *k;
400 
401  sumoLane.origID = e->id + "_" + toString((*k).id);
402  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
403  sumoLane.permissions = tc.getPermissions(odLane.type);
404  sumoLane.width = myImportWidths && odLane.width != 0 ? odLane.width : tc.getWidth(odLane.type);
405  }
406  }
407  if (!nb.getEdgeCont().insert(currRight, myImportAllTypes)) {
408  throw ProcessError("Could not add edge '" + currRight->getID() + "'.");
409  }
410  if (nb.getEdgeCont().wasIgnored(id)) {
411  prevRight = 0;
412  } else {
413  // connect lane sections
414  if (prevRight != 0) {
415  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_RIGHT, *(j - 1));
416  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
417  prevRight->addLane2LaneConnection((*k).first, currRight, (*k).second, NBEdge::L2L_VALIDATED);
418  }
419  }
420  prevRight = currRight;
421  }
422  }
423 
424  // build lanes to left
425  NBEdge* currLeft = 0;
426  if ((*j).leftLaneNumber > 0) {
427  currLeft = new NBEdge(id, sTo, sFrom, (*j).leftType, defaultSpeed, (*j).leftLaneNumber, priorityL,
429  lanesBuilt = true;
430  const std::vector<OpenDriveLane>& lanes = (*j).lanesByDir[OPENDRIVE_TAG_LEFT];
431  for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
432  std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
433  if (lp != (*j).laneMap.end()) {
434  int sumoLaneIndex = lp->second;
435  NBEdge::Lane& sumoLane = currLeft->getLaneStruct(sumoLaneIndex);
436  const OpenDriveLane& odLane = *k;
437 
438  sumoLane.origID = e->id + "_" + toString((*k).id);
439  sumoLane.speed = odLane.speed != 0 ? odLane.speed : tc.getSpeed(odLane.type);
440  sumoLane.permissions = tc.getPermissions(odLane.type);
441  sumoLane.width = myImportWidths && odLane.width != 0 ? odLane.width : tc.getWidth(odLane.type);
442  }
443  }
444  if (!nb.getEdgeCont().insert(currLeft, myImportAllTypes)) {
445  throw ProcessError("Could not add edge '" + currLeft->getID() + "'.");
446  }
447  if (nb.getEdgeCont().wasIgnored(id)) {
448  prevLeft = 0;
449  } else {
450  // connect lane sections
451  if (prevLeft != 0) {
452  std::map<int, int> connections = (*j).getInnerConnections(OPENDRIVE_TAG_LEFT, *(j - 1));
453  for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
454  currLeft->addLane2LaneConnection((*k).first, prevLeft, (*k).second, NBEdge::L2L_VALIDATED);
455  }
456  }
457  prevLeft = currLeft;
458  }
459  }
460  (*j).sumoID = id;
461 
462 
463  sB = sE;
464  sFrom = sTo;
465  }
466  if (!lanesBuilt) {
467  WRITE_WARNING("Edge '" + e->id + "' has no lanes.");
468  }
469  }
470 
471  // -------------------------
472  // connections building
473  // -------------------------
474  // generate explicit lane-to-lane connections
475  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
476  setEdgeLinks2(*(*i).second, edges);
477  }
478  // compute connections across intersections, if any
479  std::vector<Connection> connections2;
480  for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
481  const std::set<Connection>& conns = (*j).second->connections;
482 
483  for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
484  if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
485  // connections starting at inner edges are processed by starting from outer edges
486  continue;
487  }
488  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
489  buildConnectionsToOuter(*i, innerEdges, connections2);
490  } else {
491  connections2.push_back(*i);
492  }
493  }
494  }
495  // set connections
496  for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
497  std::string fromEdge = (*i).fromEdge;
498  if (edges.find(fromEdge) == edges.end()) {
499  WRITE_WARNING("While setting connections: from-edge '" + fromEdge + "' is not known.");
500  continue;
501  }
502  OpenDriveEdge* odFrom = edges[fromEdge];
503  int fromLane = (*i).fromLane;
504  bool fromLast = ((*i).fromCP == OPENDRIVE_CP_END) ^ ((*i).fromLane > 0 && !(*i).all);
505  fromEdge = fromLast ? odFrom->laneSections.back().sumoID : odFrom->laneSections[0].sumoID;
506 
507  std::string toEdge = (*i).toEdge;
508  if (edges.find(toEdge) == edges.end()) {
509  WRITE_WARNING("While setting connections: to-edge '" + toEdge + "' is not known.");
510  continue;
511  }
512 
513  OpenDriveEdge* odTo = edges[toEdge];
514  int toLane = (*i).toLane;
515  bool toLast = ((*i).toCP == OPENDRIVE_CP_END) || ((*i).toLane > 0);
516  toEdge = toLast ? odTo->laneSections.back().sumoID : odTo->laneSections[0].sumoID;
517 
518  if (fromLane == UNSET_CONNECTION) {
519  fromLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
520  }
521  if (fromLane < 0) {
522  fromEdge = revertID(fromEdge);
523  }
524  if (toLane == UNSET_CONNECTION) {
525  toLane = toLast ? odTo->laneSections.back().laneMap.begin()->first : odTo->laneSections[0].laneMap.begin()->first;
526  }
527  if (toLane < 0) {
528  toEdge = revertID(toEdge);
529  }
530  fromLane = fromLast ? odFrom->laneSections.back().laneMap[fromLane] : odFrom->laneSections[0].laneMap[fromLane];
531  toLane = toLast ? odTo->laneSections.back().laneMap[toLane] : odTo->laneSections[0].laneMap[toLane];
532  NBEdge* from = nb.getEdgeCont().retrieve(fromEdge);
533  NBEdge* to = nb.getEdgeCont().retrieve(toEdge);
534  if (from == 0) {
535  WRITE_WARNING("Could not find fromEdge representation of '" + fromEdge + "' in connection '" + (*i).origID + "'.");
536  }
537  if (to == 0) {
538  WRITE_WARNING("Could not find fromEdge representation of '" + toEdge + "' in connection '" + (*i).origID + "'.");
539  }
540  if (from == 0 || to == 0) {
541  continue;
542  }
543 
544  from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER);
545 
546  if ((*i).origID != "") {
547  // @todo: this is the most silly way to determine the connection
548  std::vector<NBEdge::Connection>& cons = from->getConnections();
549  for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
550  if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
551  (*k).origID = (*i).origID + "_" + toString((*i).origLane);
552  break;
553  }
554  }
555  }
556  }
557 
558 
559  // -------------------------
560  // traffic lights
561  // -------------------------
562  std::map<std::string, std::string> tlsControlled;
563  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
564  OpenDriveEdge* e = (*i).second;
565  for (std::vector<OpenDriveSignal>::const_iterator j = e->signals.begin(); j != e->signals.end(); ++j) {
566  if ((*j).type != "1000001") { // traffic_light (Section 6.11)
567  continue;
568  }
569  std::vector<OpenDriveLaneSection>::iterator k = e->laneSections.begin();
570  bool found = false;
571  for (; k != e->laneSections.end() - 1 && !found;) {
572  if ((*j).s > (*k).s && (*j).s <= (*(k + 1)).s) {
573  found = true;
574  } else {
575  ++k;
576  }
577  }
578 
579  // @todo: major problem, currently, still not completely solved:
580  // inner edges may have traffic lights, too. Nice on one hand, as directions can be recognized
581  // but hard to follow backwards
582  std::string id = (*k).sumoID;
583  if (id == "") {
584  if (e->junction != "") {
585  //WRITE_WARNING("Found a traffic light signal on an internal edge; will not build it (original edge id='" + e->id + "').");
586  std::string fromID, toID;
587  for (std::vector<OpenDriveLink>::const_iterator l = e->links.begin(); l != e->links.end(); ++l) {
588  if ((*l).linkType == OPENDRIVE_LT_PREDECESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
589  if (fromID != "") {
590  WRITE_WARNING("Ambigous start of connection.");
591  }
592  fromID = (*l).elementID;
593  OpenDriveEdge* e = edges[fromID];
594  fromID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
595  }
596  if ((*l).linkType == OPENDRIVE_LT_SUCCESSOR && (*l).elementType == OPENDRIVE_ET_ROAD) {
597  if (toID != "") {
598  WRITE_WARNING("Ambigous end of connection.");
599  }
600  toID = (*l).elementID;
601  OpenDriveEdge* e = edges[toID];
602  toID = (*l).contactPoint == OPENDRIVE_CP_START ? e->laneSections[0].sumoID : e->laneSections.back().sumoID;
603  }
604  }
605  id = fromID + "->" + toID;
606  } else {
607  WRITE_WARNING("Found a traffic light signal on an unknown edge (original edge id='" + e->id + "').");
608  continue;
609  }
610  }
611 
612  if ((*j).orientation > 0) {
613  id = "-" + id;
614  }
615  tlsControlled[id] = (*j).name;
616  }
617  }
618 
619  for (std::map<std::string, std::string>::iterator i = tlsControlled.begin(); i != tlsControlled.end(); ++i) {
620  std::string id = (*i).first;
621  if (id.find("->") != std::string::npos) {
622  id = id.substr(0, id.find("->"));
623  }
624  NBEdge* e = nb.getEdgeCont().retrieve(id);
625  if (e == 0) {
626  WRITE_WARNING("Could not find edge '" + id + "' while building its traffic light.");
627  continue;
628  }
629  NBNode* toNode = e->getToNode();
630  if (!toNode->isTLControlled()) {
632  NBOwnTLDef* tlDef = new NBOwnTLDef(toNode->getID(), toNode, 0, type);
633  if (!nb.getTLLogicCont().insert(tlDef)) {
634  // actually, nothing should fail here
635  delete tlDef;
636  throw ProcessError();
637  }
638  toNode->addTrafficLight(tlDef);
639  //tlDef->setSinglePhase();
640  }
641  NBTrafficLightDefinition* tlDef = *toNode->getControllingTLS().begin();
642  tlDef->addParameter("connection:" + id, (*i).second);
643  }
644 
645  // -------------------------
646  // clean up
647  // -------------------------
648  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
649  delete(*i).second;
650  }
651 }
652 
653 
654 void
655 NIImporter_OpenDrive::buildConnectionsToOuter(const Connection& c, const std::map<std::string, OpenDriveEdge*>& innerEdges, std::vector<Connection>& into) {
656 
657  OpenDriveEdge* dest = innerEdges.find(c.toEdge)->second;
658  if (dest == 0) {
660  return;
661  }
662  const std::set<Connection>& conts = dest->connections;
663  for (std::set<Connection>::const_iterator i = conts.begin(); i != conts.end(); ++i) {
664  if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
665  std::vector<Connection> t;
666  buildConnectionsToOuter(*i, innerEdges, t);
667  for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
668  // @todo this section is unverified
669  Connection cn = (*j);
670  cn.fromEdge = c.fromEdge;
671  cn.fromLane = c.fromLane;
672  cn.fromCP = c.fromCP;
673  cn.all = c.all; // @todo "all" is a hack trying to avoid the "from is zero" problem;
674  into.push_back(cn);
675  }
676  } else {
677  if ((*i).fromLane == c.toLane) {
678  Connection cn = (*i);
679  cn.fromEdge = c.fromEdge;
680  cn.fromLane = c.fromLane;
681  cn.fromCP = c.fromCP;
682  cn.all = c.all;
683  cn.origID = c.toEdge;
684  cn.origLane = c.toLane;
685  into.push_back(cn);
686  }
687  }
688  }
689 }
690 
691 
692 void
693 NIImporter_OpenDrive::setEdgeLinks2(OpenDriveEdge& e, const std::map<std::string, OpenDriveEdge*>& edges) {
694  for (std::vector<OpenDriveLink>::iterator i = e.links.begin(); i != e.links.end(); ++i) {
695  OpenDriveLink& l = *i;
696  if (l.elementType != OPENDRIVE_ET_ROAD) {
697  // we assume that links to nodes are later given as connections to edges
698  continue;
699  }
700  // get the right direction of the connected edge
701  std::string connectedEdge = l.elementID;
702  std::string edgeID = e.id;
703 
704  OpenDriveLaneSection& laneSection = l.linkType == OPENDRIVE_LT_SUCCESSOR ? e.laneSections.back() : e.laneSections[0];
705  const std::map<int, int>& laneMap = laneSection.laneMap;
706  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT) != laneSection.lanesByDir.end()) {
707  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
708  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
709  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
710  continue;
711  }
712  Connection c; // @todo: give Connection a new name and a constructor
713  c.fromEdge = e.id;
714  c.fromLane = (*j).id;
716  c.toLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
717  c.toEdge = connectedEdge;
718  c.toCP = l.contactPoint;
719  c.all = false;
720  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
721  std::swap(c.fromEdge, c.toEdge);
722  std::swap(c.fromLane, c.toLane);
723  std::swap(c.fromCP, c.toCP);
724  }
725  if (edges.find(c.fromEdge) == edges.end()) {
726  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
727  } else {
728  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
729  src->connections.insert(c);
730  }
731  }
732  }
733  if (laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT) != laneSection.lanesByDir.end()) {
734  const std::vector<OpenDriveLane>& lanes = laneSection.lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
735  for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
736  if (!myImportAllTypes && laneMap.find((*j).id) == laneMap.end()) {
737  continue;
738  }
739  Connection c;
740  c.toEdge = e.id;
741  c.toLane = (*j).id;
743  c.fromLane = l.linkType == OPENDRIVE_LT_SUCCESSOR ? (*j).successor : (*j).predecessor;
744  c.fromEdge = connectedEdge;
745  c.fromCP = l.contactPoint;
746  c.all = false;
747  if (l.linkType != OPENDRIVE_LT_SUCCESSOR) {
748  std::swap(c.fromEdge, c.toEdge);
749  std::swap(c.fromLane, c.toLane);
750  std::swap(c.fromCP, c.toCP);
751  }
752  if (edges.find(c.fromEdge) == edges.end()) {
753  WRITE_ERROR("While setting connections: incoming road '" + c.fromEdge + "' is not known.");
754  } else {
755  OpenDriveEdge* src = edges.find(c.fromEdge)->second;
756  src->connections.insert(c);
757  }
758  }
759  }
760  }
761 }
762 
763 
764 std::string NIImporter_OpenDrive::revertID(const std::string& id) {
765  if (id[0] == '-') {
766  return id.substr(1);
767  }
768  return "-" + id;
769 }
770 
771 
772 NBNode*
773 NIImporter_OpenDrive::getOrBuildNode(const std::string& id, const Position& pos,
774  NBNodeCont& nc) {
775  if (nc.retrieve(id) == 0) {
776  // not yet built; build now
777  if (!nc.insert(id, pos)) {
778  // !!! clean up
779  throw ProcessError("Could not add node '" + id + "'.");
780  }
781  }
782  return nc.retrieve(id);
783 }
784 
785 
786 void
788  const std::string& nodeID, NIImporter_OpenDrive::LinkType lt) {
789  NBNode* n = nc.retrieve(nodeID);
790  if (n == 0) {
791  throw ProcessError("Could not find node '" + nodeID + "'.");
792  }
793  if (lt == OPENDRIVE_LT_SUCCESSOR) {
794  if (e.to != 0 && e.to != n) {
795  throw ProcessError("Edge '" + e.id + "' has two end nodes.");
796  }
797  e.to = n;
798  } else {
799  if (e.from != 0 && e.from != n) {
800  throw ProcessError("Edge '" + e.id + "' has two start nodes.");
801  }
802  e.from = n;
803  }
804 }
805 
806 
807 void
808 NIImporter_OpenDrive::computeShapes(std::map<std::string, OpenDriveEdge*>& edges) {
810  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
811  OpenDriveEdge& e = *(*i).second;
813  for (std::vector<OpenDriveGeometry>::iterator j = e.geometries.begin(); j != e.geometries.end(); ++j) {
814  OpenDriveGeometry& g = *j;
815  PositionVector geom;
816  switch (g.type) {
818  break;
819  case OPENDRIVE_GT_LINE:
820  geom = geomFromLine(e, g);
821  break;
822  case OPENDRIVE_GT_SPIRAL:
823  geom = geomFromSpiral(e, g);
824  break;
825  case OPENDRIVE_GT_ARC:
826  geom = geomFromArc(e, g);
827  break;
828  case OPENDRIVE_GT_POLY3:
829  geom = geomFromPoly(e, g);
830  break;
832  geom = geomFromParamPoly(e, g);
833  break;
834  default:
835  break;
836  }
837  if (e.geom.size() > 0 && prevType == OPENDRIVE_GT_LINE) {
838  // remove redundant end point of the previous geometry segment
839  // (the start point of the current segment should have the same value)
840  // this avoids geometry errors due to imprecision
841  if (!e.geom.back().almostSame(geom.front())) {
842  const int index = (int)(j - e.geometries.begin());
843  WRITE_WARNING("Mismatched geometry for edge '" + e.id + "' between geometry segments " + toString(index - 1) + " and " + toString(index) + ".");
844  }
845  e.geom.pop_back();
846  }
847  //std::cout << " adding geometry to road=" << e.id << " old=" << e.geom << " new=" << geom << "\n";
848  for (PositionVector::iterator k = geom.begin(); k != geom.end(); ++k) {
850  }
851  prevType = g.type;
852  }
853  if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
854  e.geom.removeDoublePoints(oc.getFloat("geometry.min-dist"), true);
855  }
857  WRITE_ERROR("Unable to project coordinates for edge '" + e.id + "'.");
858  }
859  // add z-data
860  int k = 0;
861  SUMOReal pos = 0;
862  for (std::vector<OpenDriveElevation>::iterator j = e.elevations.begin(); j != e.elevations.end(); ++j) {
863  const OpenDriveElevation& el = *j;
864  const SUMOReal sNext = (j + 1) == e.elevations.end() ? std::numeric_limits<SUMOReal>::max() : (*(j + 1)).s;
865  while (k < (int)e.geom.size() && pos < sNext) {
866  const SUMOReal ds = pos - el.s;
867  const SUMOReal z = el.a + el.b * ds + el.c * ds * ds + el.d * ds * ds * ds;
868  //std::cout << " edge=" << e.id << " k=" << k << " sNext=" << sNext << " pos=" << pos << " z=" << z << " ds=" << ds << " el.s=" << el.s << "el.a=" << el.a << " el.b=" << el.b << " el.c=" << el.c << " el.d=" << el.d << "\n";
869  e.geom[k].add(0, 0, z);
870  k++;
871  if (k < (int)e.geom.size()) {
872  // XXX pos understimates the actual position since the
873  // actual geometry between k-1 and k could be curved
874  pos += e.geom[k - 1].distanceTo2D(e.geom[k]);
875  }
876  }
877  }
878  // add laneoffset
879  if (e.offsets.size() > 0) {
880  // make sure there are intermediate points for each offset-section
881  for (std::vector<OpenDriveLaneOffset>::iterator j = e.offsets.begin(); j != e.offsets.end(); ++j) {
882  const OpenDriveLaneOffset& el = *j;
883  // check wether we need to insert a new point at dist
884  Position pS = e.geom.positionAtOffset2D(el.s);
885  int iS = e.geom.indexOfClosest(pS);
886  // prevent close spacing to reduce impact of rounding errors in z-axis
887  if (pS.distanceTo2D(e.geom[iS]) > POSITION_EPS) {
888  e.geom.insertAtClosest(pS);
889  //std::cout << " edge=" << e.id << " inserting pos=" << pS << " s=" << el.s << " iS=" << iS << " dist=" << pS.distanceTo2D(e.geom[iS]) << "\n";
890  }
891  }
892  // XXX add further points for sections with non-constant offset
893  // shift each point orthogonally by the specified offset
894  int k = 0;
895  SUMOReal pos = 0;
896  PositionVector geom2;
897  for (std::vector<OpenDriveLaneOffset>::iterator j = e.offsets.begin(); j != e.offsets.end(); ++j) {
898  const OpenDriveLaneOffset& el = *j;
899  const SUMOReal sNext = (j + 1) == e.offsets.end() ? std::numeric_limits<SUMOReal>::max() : (*(j + 1)).s;
900  while (k < (int)e.geom.size() && pos < sNext) {
901  const SUMOReal ds = pos - el.s;
902  const SUMOReal offset = el.a + el.b * ds + el.c * ds * ds + el.d * ds * ds * ds;
903  //std::cout << " edge=" << e.id << " k=" << k << " sNext=" << sNext << " pos=" << pos << " offset=" << offset << " ds=" << ds << " el.s=" << el.s << "el.a=" << el.a << " el.b=" << el.b << " el.c=" << el.c << " el.d=" << el.d << "\n";
904  if (fabs(offset) > POSITION_EPS) {
905  try {
906  PositionVector tmp = e.geom;
907  // XXX shifting the whole geometry is inefficient. could also use positionAtOffset(lateralOffset=...)
908  tmp.move2side(-offset);
909  //std::cout << " edge=" << e.id << " k=" << k << " offset=" << offset << " geom[k]=" << e.geom[k] << " tmp[k]=" << tmp[k] << " gSize=" << e.geom.size() << " tSize=" << tmp.size() << " geom=" << e.geom << " tmp=" << tmp << "\n";
910  geom2.push_back(tmp[k]);
911  } catch (InvalidArgument&) {
912  geom2.push_back(e.geom[k]);
913  }
914  } else {
915  geom2.push_back(e.geom[k]);
916  }
917  k++;
918  if (k < (int)e.geom.size()) {
919  // XXX pos understimates the actual position since the
920  // actual geometry between k-1 and k could be curved
921  pos += e.geom[k - 1].distanceTo2D(e.geom[k]);
922  }
923  }
924  }
925  assert(e.geom.size() == geom2.size());
926  e.geom = geom2;
927  }
928  //std::cout << " loaded geometry " << e.id << "=" << e.geom << "\n";
929  }
930 }
931 
932 
933 void
934 NIImporter_OpenDrive::revisitLaneSections(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges) {
935  for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
936  OpenDriveEdge& e = *(*i).second;
937  std::vector<OpenDriveLaneSection>& laneSections = e.laneSections;
938  // split by speed limits
939  std::vector<OpenDriveLaneSection> newSections;
940  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end(); ++j) {
941  std::vector<OpenDriveLaneSection> splitSections;
942  bool splitBySpeed = (*j).buildSpeedChanges(tc, splitSections);
943  if (!splitBySpeed) {
944  newSections.push_back(*j);
945  } else {
946  std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
947  }
948  }
949 
950  e.laneSections = newSections;
951  laneSections = e.laneSections;
952  SUMOReal lastS = -1;
953  // check whether the lane sections are in the right order
954  bool sorted = true;
955  for (std::vector<OpenDriveLaneSection>::const_iterator j = laneSections.begin(); j != laneSections.end() && sorted; ++j) {
956  if ((*j).s <= lastS) {
957  sorted = false;
958  }
959  lastS = (*j).s;
960  }
961  if (!sorted) {
962  WRITE_WARNING("The sections of edge '" + e.id + "' are not sorted properly.");
963  sort(e.laneSections.begin(), e.laneSections.end(), sections_by_s_sorter());
964  }
965  // check whether no duplicates of s-value occure
966  lastS = -1;
967  laneSections = e.laneSections;
968  for (std::vector<OpenDriveLaneSection>::iterator j = laneSections.begin(); j != laneSections.end();) {
969  bool simlarToLast = fabs((*j).s - lastS) < POSITION_EPS;
970  lastS = (*j).s;
971  if (simlarToLast) {
972  WRITE_WARNING("Almost duplicate s-value '" + toString(lastS) + "' for lane sections occured at edge '" + e.id + "'; second entry was removed.");
973  j = laneSections.erase(j);
974  } else {
975  ++j;
976  }
977  }
978  }
979 }
980 
981 
984  UNUSED_PARAMETER(e);
985  PositionVector ret;
986  ret.push_back(Position(g.x, g.y));
987  ret.push_back(calculateStraightEndPoint(g.hdg, g.length, Position(g.x, g.y)));
988  return ret;
989 }
990 
991 
994  UNUSED_PARAMETER(e);
995  PositionVector ret;
996  SUMOReal curveStart = g.params[0];
997  SUMOReal curveEnd = g.params[1];
998  Point2D<double> end;
999  try {
1000  EulerSpiral s(Point2D<double>(g.x, g.y), g.hdg, curveStart, (curveEnd - curveStart) / g.length, g.length);
1001  std::vector<Point2D<double> > into;
1002  s.computeSpiral(into, SPIRAL_RES);
1003  for (std::vector<Point2D<double> >::iterator i = into.begin(); i != into.end(); ++i) {
1004  ret.push_back(Position((*i).getX(), (*i).getY()));
1005  }
1006  } catch (const std::runtime_error& error) {
1007  WRITE_WARNING("Could not compute spiral geometry for edge '" + e.id + "' (" + error.what() + ").");
1008  ret.push_back(Position(g.x, g.y));
1009  }
1010  return ret.getSubpart2D(0, g.length);
1011 }
1012 
1013 
1016  UNUSED_PARAMETER(e);
1017  PositionVector ret;
1018  SUMOReal dist = 0.0;
1019  SUMOReal centerX = g.x;
1020  SUMOReal centerY = g.y;
1021  // left: positive value
1022  SUMOReal curvature = g.params[0];
1023  SUMOReal radius = 1. / curvature;
1024  // center point
1025  calculateCurveCenter(&centerX, &centerY, radius, g.hdg);
1026  SUMOReal endX = g.x;
1027  SUMOReal endY = g.y;
1028  SUMOReal startX = g.x;
1029  SUMOReal startY = g.y;
1030  SUMOReal geo_posS = g.s;
1031  SUMOReal geo_posE = g.s;
1032  bool end = false;
1033  do {
1034  geo_posE += C_LENGTH;
1035  if (geo_posE - g.s > g.length) {
1036  geo_posE = g.s + g.length;
1037  }
1038  if (geo_posE - g.s > g.length) {
1039  geo_posE = g.s + g.length;
1040  }
1041  calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
1042 
1043  dist += (geo_posE - geo_posS);
1044  //
1045  ret.push_back(Position(startX, startY));
1046  //
1047  startX = endX;
1048  startY = endY;
1049  geo_posS = geo_posE;
1050 
1051  if (geo_posE - (g.s + g.length) < 0.001 && geo_posE - (g.s + g.length) > -0.001) {
1052  end = true;
1053  }
1054  } while (!end);
1055  return ret.getSubpart2D(0, g.length);
1056 }
1057 
1058 
1061  UNUSED_PARAMETER(e);
1062  const SUMOReal s = sin(g.hdg);
1063  const SUMOReal c = cos(g.hdg);
1064  PositionVector ret;
1065  for (SUMOReal off = 0; off < g.length + 2.; off += POLY_RES) {
1066  SUMOReal x = off;
1067  SUMOReal y = g.params[0] + g.params[1] * off + g.params[2] * pow(off, 2.) + g.params[3] * pow(off, 3.);
1068  SUMOReal xnew = x * c - y * s;
1069  SUMOReal ynew = x * s + y * c;
1070  ret.push_back(Position(g.x + xnew, g.y + ynew));
1071  }
1072  return ret.getSubpart2D(0, g.length);
1073 }
1074 
1075 
1078  UNUSED_PARAMETER(e);
1079  const SUMOReal s = sin(g.hdg);
1080  const SUMOReal c = cos(g.hdg);
1081  const SUMOReal pMax = g.params[8];
1082  const SUMOReal pStep = pMax / ceil(g.length / PARAMPOLY3_RES);
1083  PositionVector ret;
1084  for (SUMOReal p = 0; p <= pMax + pStep; p += pStep) {
1085  SUMOReal x = g.params[0] + g.params[1] * p + g.params[2] * pow(p, 2.) + g.params[3] * pow(p, 3.);
1086  SUMOReal y = g.params[4] + g.params[5] * p + g.params[6] * pow(p, 2.) + g.params[7] * pow(p, 3.);
1087  SUMOReal xnew = x * c - y * s;
1088  SUMOReal ynew = x * s + y * c;
1089  ret.push_back(Position(g.x + xnew, g.y + ynew));
1090  }
1091  return ret.getSubpart2D(0, g.length);
1092 }
1093 
1094 
1095 Position
1096 NIImporter_OpenDrive::calculateStraightEndPoint(double hdg, double length, const Position& start) {
1097  double normx = 1.0f;
1098  double normy = 0.0f;
1099  double x2 = normx * cos(hdg) - normy * sin(hdg);
1100  double y2 = normx * sin(hdg) + normy * cos(hdg);
1101  normx = x2 * length;
1102  normy = y2 * length;
1103  return Position(start.x() + normx, start.y() + normy);
1104 }
1105 
1106 
1107 void
1109  SUMOReal normX = 1.0;
1110  SUMOReal normY = 0.0;
1111  SUMOReal tmpX;
1112  SUMOReal turn;
1113  if (ad_radius > 0) {
1114  turn = -1.0;
1115  } else {
1116  turn = 1.0;
1117  }
1118 
1119  tmpX = normX;
1120  normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
1121  normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
1122 
1123  tmpX = normX;
1124  normX = turn * normY;
1125  normY = -turn * tmpX;
1126 
1127  normX = fabs(ad_radius) * normX;
1128  normY = fabs(ad_radius) * normY;
1129 
1130  *ad_x += normX;
1131  *ad_y += normY;
1132 }
1133 
1134 
1135 void
1137  SUMOReal ad_r, SUMOReal ad_length) {
1138  double rotAngle = ad_length / fabs(ad_r);
1139  double vx = *ad_x - ad_centerX;
1140  double vy = *ad_y - ad_centerY;
1141  double tmpx;
1142 
1143  double turn;
1144  if (ad_r > 0) {
1145  turn = -1; //left
1146  } else {
1147  turn = 1; //right
1148  }
1149  tmpx = vx;
1150  vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
1151  vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
1152  *ad_x = vx + ad_centerX;
1153  *ad_y = vy + ad_centerY;
1154 }
1155 
1156 
1157 // ---------------------------------------------------------------------------
1158 // section
1159 // ---------------------------------------------------------------------------
1161  lanesByDir[OPENDRIVE_TAG_LEFT] = std::vector<OpenDriveLane>();
1162  lanesByDir[OPENDRIVE_TAG_RIGHT] = std::vector<OpenDriveLane>();
1163  lanesByDir[OPENDRIVE_TAG_CENTER] = std::vector<OpenDriveLane>();
1164 }
1165 
1166 
1167 void
1169  int sumoLane = 0;
1170  bool singleType = true;
1171  std::vector<std::string> types;
1172  const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(OPENDRIVE_TAG_RIGHT)->second;
1173  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
1174  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1175  laneMap[(*i).id] = sumoLane++;
1176  types.push_back((*i).type);
1177  if (types.front() != types.back()) {
1178  singleType = false;
1179  }
1180  }
1181  }
1182  rightLaneNumber = sumoLane;
1183  rightType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
1184  sumoLane = 0;
1185  singleType = true;
1186  types.clear();
1187  const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(OPENDRIVE_TAG_LEFT)->second;
1188  for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
1189  if (myImportAllTypes || (tc.knows((*i).type) && !tc.getShallBeDiscarded((*i).type))) {
1190  laneMap[(*i).id] = sumoLane++;
1191  types.push_back((*i).type);
1192  if (types.front() != types.back()) {
1193  singleType = false;
1194  }
1195  }
1196  }
1197  leftLaneNumber = sumoLane;
1198  leftType = sumoLane > 0 ? (singleType ? types.front() : joinToString(types, "|")) : "";
1199 }
1200 
1201 
1202 std::map<int, int>
1204  std::map<int, int> ret;
1205  const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
1206  for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
1207  std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
1208  if (toP == laneMap.end()) {
1209  // the current lane is not available in SUMO
1210  continue;
1211  }
1212  int to = (*toP).second;
1213  int from = UNSET_CONNECTION;
1214  if ((*i).predecessor != UNSET_CONNECTION) {
1215  from = (*i).predecessor;
1216  }
1217  if (from != UNSET_CONNECTION) {
1218  std::map<int, int>::const_iterator fromP = prev.laneMap.find(from);
1219  if (fromP != prev.laneMap.end()) {
1220  from = (*fromP).second;
1221  } else {
1222  from = UNSET_CONNECTION;
1223  }
1224  }
1225  if (from != UNSET_CONNECTION && to != UNSET_CONNECTION) {
1226  if (ret.find(from) != ret.end()) {
1227 // WRITE_WARNING("double connection");
1228  }
1229  if (dir == OPENDRIVE_TAG_LEFT) {
1230  std::swap(from, to);
1231  }
1232  ret[from] = to;
1233  } else {
1234 // WRITE_WARNING("missing connection");
1235  }
1236  }
1237  return ret;
1238 }
1239 
1240 
1243  OpenDriveLaneSection ret(*this);
1244  ret.s += startPos;
1245  for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_RIGHT].size(); ++k) {
1247  l.speed = 0;
1248  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1249  if (i != l.speeds.end()) {
1250  l.speed = (*i).second;
1251  }
1252  }
1253  for (int k = 0; k < (int)ret.lanesByDir[OPENDRIVE_TAG_LEFT].size(); ++k) {
1255  std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator i = std::find_if(l.speeds.begin(), l.speeds.end(), same_position_finder(startPos));
1256  l.speed = 0;
1257  if (i != l.speeds.end()) {
1258  l.speed = (*i).second;
1259  }
1260  }
1261  return ret;
1262 }
1263 
1264 
1265 bool
1266 NIImporter_OpenDrive::OpenDriveLaneSection::buildSpeedChanges(const NBTypeCont& tc, std::vector<OpenDriveLaneSection>& newSections) {
1267  std::set<SUMOReal> speedChangePositions;
1268  // collect speed change positions and apply initial speed to the begin
1269  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_RIGHT].begin(); k != lanesByDir[OPENDRIVE_TAG_RIGHT].end(); ++k) {
1270  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1271  speedChangePositions.insert((*l).first);
1272  if ((*l).first == 0) {
1273  (*k).speed = (*l).second;
1274  }
1275  }
1276  }
1277  for (std::vector<OpenDriveLane>::iterator k = lanesByDir[OPENDRIVE_TAG_LEFT].begin(); k != lanesByDir[OPENDRIVE_TAG_LEFT].end(); ++k) {
1278  for (std::vector<std::pair<SUMOReal, SUMOReal> >::const_iterator l = (*k).speeds.begin(); l != (*k).speeds.end(); ++l) {
1279  speedChangePositions.insert((*l).first);
1280  if ((*l).first == 0) {
1281  (*k).speed = (*l).second;
1282  }
1283  }
1284  }
1285  // do nothing if there is none
1286  if (speedChangePositions.size() == 0) {
1287  return false;
1288  }
1289  if (*speedChangePositions.begin() > 0) {
1290  speedChangePositions.insert(0);
1291  }
1292  //
1293  for (std::set<SUMOReal>::iterator i = speedChangePositions.begin(); i != speedChangePositions.end(); ++i) {
1294  if (i == speedChangePositions.begin()) {
1295  newSections.push_back(*this);
1296  } else {
1297  newSections.push_back(buildLaneSection(*i));
1298  }
1299  }
1300  // propagate speeds
1301  for (int i = 0; i != (int)newSections.size(); ++i) {
1302  OpenDriveLaneSection& ls = newSections[i];
1303  std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >& lanesByDir = ls.lanesByDir;
1304  for (std::map<OpenDriveXMLTag, std::vector<OpenDriveLane> >::iterator k = lanesByDir.begin(); k != lanesByDir.end(); ++k) {
1305  std::vector<OpenDriveLane>& lanes = (*k).second;
1306  for (int j = 0; j != (int)lanes.size(); ++j) {
1307  OpenDriveLane& l = lanes[j];
1308  if (l.speed != 0) {
1309  continue;
1310  }
1311  if (i > 0) {
1312  l.speed = newSections[i - 1].lanesByDir[(*k).first][j].speed;
1313  } else {
1314  tc.getSpeed(l.type);
1315  }
1316  }
1317  }
1318  }
1319  return true;
1320 }
1321 
1322 
1323 
1324 // ---------------------------------------------------------------------------
1325 // edge
1326 // ---------------------------------------------------------------------------
1327 int
1329  int prio = 1;
1330  for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
1331  int tmp = 1;
1332  if ((*i).type == "301" || (*i).type == "306") {
1333  tmp = 2;
1334  }
1335  if ((*i).type == "205") {
1336  tmp = 0;
1337  }
1338  if (tmp != 1 && dir == OPENDRIVE_TAG_RIGHT && (*i).orientation > 0) {
1339  prio = tmp;
1340  }
1341  if (tmp != 1 && dir == OPENDRIVE_TAG_LEFT && (*i).orientation < 0) {
1342  prio = tmp;
1343  }
1344 
1345  }
1346  return prio;
1347 }
1348 
1349 
1350 
1351 // ---------------------------------------------------------------------------
1352 // loader methods
1353 // ---------------------------------------------------------------------------
1354 NIImporter_OpenDrive::NIImporter_OpenDrive(const NBTypeCont& tc, std::map<std::string, OpenDriveEdge*>& edges)
1356  myTypeContainer(tc), myCurrentEdge("", "", "", -1), myEdges(edges) {
1357 }
1358 
1359 
1361 }
1362 
1363 
1364 void
1366  const SUMOSAXAttributes& attrs) {
1367  bool ok = true;
1368  switch (element) {
1369  case OPENDRIVE_TAG_HEADER: {
1370  int majorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMAJOR, 0, ok);
1371  int minorVersion = attrs.get<int>(OPENDRIVE_ATTR_REVMINOR, 0, ok);
1372  if (majorVersion != 1 || minorVersion != 2) {
1373  WRITE_WARNING("Given openDrive file '" + getFileName() + "' uses version " + toString(majorVersion) + "." + toString(minorVersion) + ";\n Version 1.2 is supported.");
1374  }
1375  }
1376  break;
1377  case OPENDRIVE_TAG_ROAD: {
1378  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, 0, ok);
1379  std::string streetName = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, 0, ok, "", false);
1380  std::string junction = attrs.get<std::string>(OPENDRIVE_ATTR_JUNCTION, id.c_str(), ok);
1381  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, id.c_str(), ok);
1382  myCurrentEdge = OpenDriveEdge(id, streetName, junction, length);
1383  }
1384  break;
1386  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1387  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1388  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1389  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1390  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1391  : "end";
1392  addLink(OPENDRIVE_LT_PREDECESSOR, elementType, elementID, contactPoint);
1393  }
1394  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1395  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1396  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1397  l.predecessor = no;
1398  }
1399  }
1400  break;
1401  case OPENDRIVE_TAG_SUCCESSOR: {
1402  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_ROAD) {
1403  std::string elementType = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTTYPE, myCurrentEdge.id.c_str(), ok);
1404  std::string elementID = attrs.get<std::string>(OPENDRIVE_ATTR_ELEMENTID, myCurrentEdge.id.c_str(), ok);
1405  std::string contactPoint = attrs.hasAttribute(OPENDRIVE_ATTR_CONTACTPOINT)
1406  ? attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentEdge.id.c_str(), ok)
1407  : "start";
1408  addLink(OPENDRIVE_LT_SUCCESSOR, elementType, elementID, contactPoint);
1409  }
1410  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 2] == OPENDRIVE_TAG_LANE) {
1411  int no = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1412  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1413  l.successor = no;
1414  }
1415  }
1416  break;
1417  case OPENDRIVE_TAG_GEOMETRY: {
1418  SUMOReal length = attrs.get<SUMOReal>(OPENDRIVE_ATTR_LENGTH, myCurrentEdge.id.c_str(), ok);
1419  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1420  SUMOReal x = attrs.get<SUMOReal>(OPENDRIVE_ATTR_X, myCurrentEdge.id.c_str(), ok);
1421  SUMOReal y = attrs.get<SUMOReal>(OPENDRIVE_ATTR_Y, myCurrentEdge.id.c_str(), ok);
1422  SUMOReal hdg = attrs.get<SUMOReal>(OPENDRIVE_ATTR_HDG, myCurrentEdge.id.c_str(), ok);
1423  myCurrentEdge.geometries.push_back(OpenDriveGeometry(length, s, x, y, hdg));
1424  }
1425  break;
1426  case OPENDRIVE_TAG_ELEVATION: {
1427  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1428  SUMOReal a = attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1429  SUMOReal b = attrs.get<SUMOReal>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
1430  SUMOReal c = attrs.get<SUMOReal>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
1431  SUMOReal d = attrs.get<SUMOReal>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
1432  myCurrentEdge.elevations.push_back(OpenDriveElevation(s, a, b, c, d));
1433  }
1434  break;
1435  case OPENDRIVE_TAG_LINE: {
1436  std::vector<SUMOReal> vals;
1438  }
1439  break;
1440  case OPENDRIVE_TAG_SPIRAL: {
1441  std::vector<SUMOReal> vals;
1442  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVSTART, myCurrentEdge.id.c_str(), ok));
1443  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVEND, myCurrentEdge.id.c_str(), ok));
1445  }
1446  break;
1447  case OPENDRIVE_TAG_ARC: {
1448  std::vector<SUMOReal> vals;
1449  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CURVATURE, myCurrentEdge.id.c_str(), ok));
1451  }
1452  break;
1453  case OPENDRIVE_TAG_POLY3: {
1454  std::vector<SUMOReal> vals;
1455  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok));
1456  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok));
1457  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok));
1458  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok));
1460  }
1461  break;
1462  case OPENDRIVE_TAG_PARAMPOLY3: {
1463  std::vector<SUMOReal> vals;
1464  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_AU, myCurrentEdge.id.c_str(), ok));
1465  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_BU, myCurrentEdge.id.c_str(), ok));
1466  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CU, myCurrentEdge.id.c_str(), ok));
1467  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_DU, myCurrentEdge.id.c_str(), ok));
1468  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_AV, myCurrentEdge.id.c_str(), ok));
1469  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_BV, myCurrentEdge.id.c_str(), ok));
1470  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_CV, myCurrentEdge.id.c_str(), ok));
1471  vals.push_back(attrs.get<SUMOReal>(OPENDRIVE_ATTR_DV, myCurrentEdge.id.c_str(), ok));
1472  vals.push_back(attrs.getOpt<SUMOReal>(OPENDRIVE_ATTR_PRANGE, myCurrentEdge.id.c_str(), ok, 1.0, false));
1474  }
1475  break;
1477  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1479  }
1480  break;
1481  case OPENDRIVE_TAG_LANEOFFSET: {
1482  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1483  SUMOReal a = attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1484  SUMOReal b = attrs.get<SUMOReal>(OPENDRIVE_ATTR_B, myCurrentEdge.id.c_str(), ok);
1485  SUMOReal c = attrs.get<SUMOReal>(OPENDRIVE_ATTR_C, myCurrentEdge.id.c_str(), ok);
1486  SUMOReal d = attrs.get<SUMOReal>(OPENDRIVE_ATTR_D, myCurrentEdge.id.c_str(), ok);
1487  myCurrentEdge.offsets.push_back(OpenDriveLaneOffset(s, a, b, c, d));
1488  }
1489  break;
1490  case OPENDRIVE_TAG_LEFT:
1492  break;
1493  case OPENDRIVE_TAG_CENTER:
1495  break;
1496  case OPENDRIVE_TAG_RIGHT:
1498  break;
1499  case OPENDRIVE_TAG_LANE: {
1500  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1501  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1502  std::string level = attrs.hasAttribute(OPENDRIVE_ATTR_LEVEL)
1503  ? attrs.get<std::string>(OPENDRIVE_ATTR_LEVEL, myCurrentEdge.id.c_str(), ok)
1504  : "";
1506  ls.lanesByDir[myCurrentLaneDirection].push_back(OpenDriveLane(id, level, type));
1507  }
1508  break;
1509  case OPENDRIVE_TAG_SIGNAL: {
1510  int id = attrs.get<int>(OPENDRIVE_ATTR_ID, myCurrentEdge.id.c_str(), ok);
1511  std::string type = attrs.get<std::string>(OPENDRIVE_ATTR_TYPE, myCurrentEdge.id.c_str(), ok);
1512  std::string name = attrs.getOpt<std::string>(OPENDRIVE_ATTR_NAME, myCurrentEdge.id.c_str(), ok, "", false);
1513  int orientation = attrs.get<std::string>(OPENDRIVE_ATTR_ORIENTATION, myCurrentEdge.id.c_str(), ok) == "-" ? -1 : 1;
1514  SUMOReal s = attrs.get<SUMOReal>(OPENDRIVE_ATTR_S, myCurrentEdge.id.c_str(), ok);
1515  bool dynamic = attrs.get<std::string>(OPENDRIVE_ATTR_DYNAMIC, myCurrentEdge.id.c_str(), ok) == "no" ? false : true;
1516  myCurrentEdge.signals.push_back(OpenDriveSignal(id, type, name, orientation, dynamic, s));
1517  }
1518  break;
1520  myCurrentJunctionID = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1521  break;
1522  case OPENDRIVE_TAG_CONNECTION: {
1523  std::string id = attrs.get<std::string>(OPENDRIVE_ATTR_ID, myCurrentJunctionID.c_str(), ok);
1524  myCurrentIncomingRoad = attrs.get<std::string>(OPENDRIVE_ATTR_INCOMINGROAD, myCurrentJunctionID.c_str(), ok);
1526  std::string cp = attrs.get<std::string>(OPENDRIVE_ATTR_CONTACTPOINT, myCurrentJunctionID.c_str(), ok);
1528  myConnectionWasEmpty = true;
1529  }
1530  break;
1531  case OPENDRIVE_TAG_LANELINK: {
1532  int from = attrs.get<int>(OPENDRIVE_ATTR_FROM, myCurrentJunctionID.c_str(), ok);
1533  int to = attrs.get<int>(OPENDRIVE_ATTR_TO, myCurrentJunctionID.c_str(), ok);
1534  Connection c;
1536  c.toEdge = myCurrentConnectingRoad;
1537  c.fromLane = from;
1538  c.toLane = to;
1539  c.fromCP = OPENDRIVE_CP_END;
1540  c.toCP = myCurrentContactPoint;
1541  c.all = false;
1542  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1543  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1544  } else {
1545  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1546  e->connections.insert(c);
1547  myConnectionWasEmpty = false;
1548  }
1549  }
1550  break;
1551  case OPENDRIVE_TAG_WIDTH: {
1552  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1553  SUMOReal width = attrs.get<SUMOReal>(OPENDRIVE_ATTR_A, myCurrentEdge.id.c_str(), ok);
1554  OpenDriveLane& l = myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back();
1555  l.width = MAX2(l.width, width);
1556  }
1557  }
1558  break;
1559  case OPENDRIVE_TAG_SPEED: {
1560  if (myElementStack.size() >= 2 && myElementStack[myElementStack.size() - 1] == OPENDRIVE_TAG_LANE) {
1561  SUMOReal speed = attrs.get<SUMOReal>(OPENDRIVE_ATTR_MAX, myCurrentEdge.id.c_str(), ok);
1562  SUMOReal pos = attrs.get<SUMOReal>(OPENDRIVE_ATTR_SOFFSET, myCurrentEdge.id.c_str(), ok);
1563  myCurrentEdge.laneSections.back().lanesByDir[myCurrentLaneDirection].back().speeds.push_back(std::make_pair(pos, speed));
1564  }
1565  }
1566  break;
1567  default:
1568  break;
1569  }
1570  myElementStack.push_back(element);
1571 }
1572 
1573 
1574 void
1576  myElementStack.pop_back();
1577  switch (element) {
1578  case OPENDRIVE_TAG_ROAD:
1580  break;
1582  if (myConnectionWasEmpty) {
1583  Connection c;
1586  c.fromLane = 0;
1587  c.toLane = 0;
1590  c.all = true;
1591  if (myEdges.find(c.fromEdge) == myEdges.end()) {
1592  WRITE_ERROR("In laneLink-element: incoming road '" + c.fromEdge + "' is not known.");
1593  } else {
1594  OpenDriveEdge* e = myEdges.find(c.fromEdge)->second;
1595  e->connections.insert(c);
1596  }
1597  }
1598  break;
1600  myCurrentEdge.laneSections.back().buildLaneMapping(myTypeContainer);
1601  }
1602  break;
1603  default:
1604  break;
1605  }
1606 }
1607 
1608 
1609 
1610 void
1611 NIImporter_OpenDrive::addLink(LinkType lt, const std::string& elementType,
1612  const std::string& elementID,
1613  const std::string& contactPoint) {
1614  OpenDriveLink l(lt, elementID);
1615  // elementType
1616  if (elementType == "road") {
1618  } else if (elementType == "junction") {
1620  }
1621  // contact point
1622  if (contactPoint == "start") {
1624  } else if (contactPoint == "end") {
1626  }
1627  // add
1628  myCurrentEdge.links.push_back(l);
1629 }
1630 
1631 
1632 void
1633 NIImporter_OpenDrive::addGeometryShape(GeometryType type, const std::vector<SUMOReal>& vals) {
1634  // checks
1635  if (myCurrentEdge.geometries.size() == 0) {
1636  throw ProcessError("Mismatching paranthesis in geometry definition for road '" + myCurrentEdge.id + "'");
1637  }
1639  if (last.type != OPENDRIVE_GT_UNKNOWN) {
1640  throw ProcessError("Double geometry information for road '" + myCurrentEdge.id + "'");
1641  }
1642  // set
1643  last.type = type;
1644  last.params = vals;
1645 }
1646 
1647 
1648 bool
1650  if (c1.fromEdge != c2.fromEdge) {
1651  return c1.fromEdge < c2.fromEdge;
1652  }
1653  if (c1.toEdge != c2.toEdge) {
1654  return c1.toEdge < c2.toEdge;
1655  }
1656  if (c1.fromLane != c2.fromLane) {
1657  return c1.fromLane < c2.fromLane;
1658  }
1659  return c1.toLane < c2.toLane;
1660 }
1661 
1662 
1663 
1664 /****************************************************************************/
1665 
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
#define POLY_RES
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
std::string rightType
the composite type built from all used lane types
static const SUMOReal UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:244
static PositionVector geomFromLine(const OpenDriveEdge &e, const OpenDriveGeometry &g)
static StringBijection< int >::Entry openDriveAttrs[]
The names of openDrive-XML attributes (for passing to GenericSAXHandler)
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:154
#define SPIRAL_RES
PositionVector getSubpart2D(SUMOReal beginOffset, SUMOReal endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
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.
std::vector< OpenDriveElevation > elevations
GeometryType
OpenDrive geometry type enumeration.
int rightLaneNumber
The number of lanes on the right and on the left side, respectively.
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:288
static void buildConnectionsToOuter(const Connection &c, const std::map< std::string, OpenDriveEdge * > &innerEdges, std::vector< Connection > &into)
Representation of a lane section.
#define PARAMPOLY3_RES
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:71
Representation of an openDrive "link".
The base class for traffic light logic definitions.
ContactPoint myCurrentContactPoint
SUMOReal s
The starting offset of this lane section.
T MAX2(T a, T b)
Definition: StdDefs.h:70
static PositionVector geomFromArc(const OpenDriveEdge &e, const OpenDriveGeometry &g)
std::map< OpenDriveXMLTag, std::vector< OpenDriveLane > > lanesByDir
The lanes, sorted by their direction.
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
SUMOReal getFloat(const std::string &name) const
Returns the SUMOReal-value of the named option (only for Option_Float)
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1123
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:247
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)
Position positionAtOffset2D(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
#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].
Definition: NBTypeCont.cpp:221
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:117
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:69
static std::string revertID(const std::string &id)
PositionVector reverse() const
reverse position vector
#define C_LENGTH
SUMOReal speed
The speed allowed on this lane.
Definition: NBEdge.h:132
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:124
const std::string & getID() const
Returns the id.
Definition: Named.h:66
SUMOReal length2D() const
Returns the length.
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
Definition: NBEdge.h:135
std::vector< OpenDriveLink > links
A handler which converts occuring elements and attributes into enums.
OpenDriveLaneSection buildLaneSection(SUMOReal startPos)
OpenDriveElevation OpenDriveLaneOffset
LaneOffset has the same fields as Elevation.
#define max(a, b)
Definition: polyfonts.c:65
SUMOReal getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:185
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 (The set of tls that control this node) ...
Definition: NBNode.h:298
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:162
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
std::string type
The lane&#39;s type.
int getPriority(OpenDriveXMLTag dir) const
Returns the edge&#39;s priority, regarding the direction.
Encapsulated SAX-Attributes.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
static Position calculateStraightEndPoint(double hdg, double length, const Position &start)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:144
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.
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
int indexOfClosest(const Position &p) const
index of the closest position to p
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given SUMO file.
NIImporter_OpenDrive(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Constructor.
bool isUsableFileList(const std::string &name) const
Checks whether the named option is usable as a file list (with at least a single file) ...
bool buildSpeedChanges(const NBTypeCont &tc, std::vector< OpenDriveLaneSection > &newSections)
const NBTypeCont & myTypeContainer
std::vector< OpenDriveLaneOffset > offsets
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, bool keepClear=true, SUMOReal contPos=UNSPECIFIED_CONTPOS, SUMOReal visibility=UNSPECIFIED_VISIBILITY_DISTANCE)
Adds a connection between the specified this edge&#39;s lane and an approached one.
Definition: NBEdge.cpp:826
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:182
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
int insertAtClosest(const Position &p)
inserts p between the two closest positions and returns the insertion index
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
OpenDriveXMLTag
Numbers representing openDrive-XML - element names.
bool knows(const std::string &type) const
Returns whether the named type is in the container.
Definition: NBTypeCont.cpp:79
The connection was given by the user.
Definition: NBEdge.h:115
static PositionVector geomFromSpiral(const OpenDriveEdge &e, const OpenDriveGeometry &g)
static PositionVector geomFromPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g)
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list...
static StringBijection< int >::Entry openDriveTags[]
The names of openDrive-XML elements (for passing to GenericSAXHandler)
std::string origID
An original ID, if given.
Definition: NBEdge.h:147
void buildLaneMapping(const NBTypeCont &tc)
Build the mapping from OpenDrive to SUMO lanes.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:206
std::vector< OpenDriveSignal > signals
LinkType
OpenDrive link type enumeration.
void addParameter(const std::string &key, const std::string &value)
Adds a parameter.
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:423
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
Definition: NBNode.cpp:314
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:255
std::map< int, int > getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection &prev)
Returns the links from the previous to this lane section.
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:149
SUMOReal speed
The lane&#39;s speed (set in post-processing)
Instance responsible for building networks.
Definition: NBNetBuilder.h:112
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:203
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
A storage for options typed value containers)
Definition: OptionsCont.h:99
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:81
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:159
static void setEdgeLinks2(OpenDriveEdge &e, const std::map< std::string, OpenDriveEdge * > &edges)
std::vector< OpenDriveGeometry > geometries
Represents a single node (junction) during network building.
Definition: NBNode.h:75
T get(const std::string &str) const
A class for sorting lane sections by their s-value.
SUMOReal distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:250
void move2side(SUMOReal amount)
move position vector to side using certain ammount
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
static PositionVector geomFromParamPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g)
#define SUMOReal
Definition: config.h:208
static void setNodeSecure(NBNodeCont &nc, OpenDriveEdge &e, const std::string &nodeID, NIImporter_OpenDrive::LinkType lt)
void push_back_noDoublePos(const Position &p)
insert in back a non double position
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.
bool wasIgnored(std::string id) const
Returns whether the edge with the id was ignored during parsing.
Definition: NBEdgeCont.h:472
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:110
SVCPermissions getPermissions(const std::string &type) const
Returns allowed vehicle classes for the given type.
Definition: NBTypeCont.cpp:215
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
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:810
Importer for networks stored in openDrive format.
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:188
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:144
#define UNSET_CONNECTION
TrafficLightType
A storage for available types of edges.
Definition: NBTypeCont.h:62
std::string streetName
The road name of the edge.
void myEndElement(int element)
Called when a closing tag occurs.
static void revisitLaneSections(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Rechecks lane sections of the given edges.
Coefficients of an elevation profile (3rd degree polynomial)