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