Eclipse SUMO - Simulation of Urban MObility
NWWriter_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) 2011-2019 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 /****************************************************************************/
15 // Exporter writing networks using the openDRIVE format
16 /****************************************************************************/
17 
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
24 #include <ctime>
25 #include "NWWriter_OpenDrive.h"
28 #include <netbuild/NBEdgeCont.h>
29 #include <netbuild/NBNode.h>
30 #include <netbuild/NBNodeCont.h>
31 #include <netbuild/NBNetBuilder.h>
35 #include <utils/common/StdDefs.h>
39 
40 #define INVALID_ID -1
41 
42 //#define DEBUG_SMOOTH_GEOM
43 #define DEBUGCOND true
44 
45 #define MIN_TURN_DIAMETER 2.0
46 
47 
48 // ===========================================================================
49 // method definitions
50 // ===========================================================================
51 // ---------------------------------------------------------------------------
52 // static methods
53 // ---------------------------------------------------------------------------
54 void
56  // check whether an opendrive-file shall be generated
57  if (!oc.isSet("opendrive-output")) {
58  return;
59  }
60  const NBNodeCont& nc = nb.getNodeCont();
61  const NBEdgeCont& ec = nb.getEdgeCont();
62  const bool origNames = oc.getBool("output.original-names");
63  const bool lefthand = oc.getBool("lefthand");
64  const double straightThresh = DEG2RAD(oc.getFloat("opendrive-output.straight-threshold"));
65  // some internal mapping containers
66  int nodeID = 1;
67  int edgeID = nc.size() * 10; // distinct from node ids
68  StringBijection<int> edgeMap;
69  StringBijection<int> nodeMap;
70  //
71  OutputDevice& device = OutputDevice::getDevice(oc.getString("opendrive-output"));
72  device << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
73  device.openTag("OpenDRIVE");
74  time_t now = time(nullptr);
75  std::string dstr(ctime(&now));
77  // write header
78  device.openTag("header");
79  device.writeAttr("revMajor", "1");
80  device.writeAttr("revMinor", "4");
81  device.writeAttr("name", "");
82  device.writeAttr("version", "1.00");
83  device.writeAttr("date", dstr.substr(0, dstr.length() - 1));
84  device.writeAttr("north", b.ymax());
85  device.writeAttr("south", b.ymin());
86  device.writeAttr("east", b.xmax());
87  device.writeAttr("west", b.xmin());
88  /* @note obsolete in 1.4
89  device.writeAttr("maxRoad", ec.size());
90  device.writeAttr("maxJunc", nc.size());
91  device.writeAttr("maxPrg", 0);
92  */
93  device.closeTag();
94  // write optional geo reference
96  if (gch.usingGeoProjection()) {
97  if (gch.getOffsetBase() == Position(0, 0)) {
98  device.openTag("geoReference");
99  device.writePreformattedTag(" <![CDATA[\n "
100  + gch.getProjString()
101  + "\n]]>\n");
102  device.closeTag();
103  } else {
104  WRITE_WARNING("Could not write OpenDRIVE geoReference. Only unshifted Coordinate systems are supported (offset=" + toString(gch.getOffsetBase()) + ")");
105  }
106  }
107 
108  // write normal edges (road)
109  for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
110  const NBEdge* e = (*i).second;
111  const int fromNodeID = e->getIncomingEdges().size() > 0 ? getID(e->getFromNode()->getID(), nodeMap, nodeID) : INVALID_ID;
112  const int toNodeID = e->getConnections().size() > 0 ? getID(e->getToNode()->getID(), nodeMap, nodeID) : INVALID_ID;
113  writeNormalEdge(device, e,
114  getID(e->getID(), edgeMap, edgeID),
115  fromNodeID, toNodeID,
116  origNames, straightThresh,
117  nb.getShapeCont());
118  }
119  device.lf();
120 
121  // write junction-internal edges (road). In OpenDRIVE these are called 'paths' or 'connecting roads'
122  OutputDevice_String junctionOSS(false, 3);
123  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
124  NBNode* n = (*i).second;
125  int connectionID = 0; // unique within a junction
126  const int nID = getID(n->getID(), nodeMap, nodeID);
127  if (n->numNormalConnections() > 0) {
128  junctionOSS << " <junction name=\"" << n->getID() << "\" id=\"" << nID << "\">\n";
129  }
130  std::vector<NBEdge*> incoming = (*i).second->getIncomingEdges();
131  if (lefthand) {
132  std::reverse(incoming.begin(), incoming.end());
133  }
134  for (NBEdge* inEdge : incoming) {
135  std::string centerMark = "none";
136  const int inEdgeID = getID(inEdge->getID(), edgeMap, edgeID);
137  // group parallel edges
138  const NBEdge* outEdge = nullptr;
139  bool isOuterEdge = true; // determine where a solid outer border should be drawn
140  int lastFromLane = -1;
141  std::vector<NBEdge::Connection> parallel;
142  std::vector<NBEdge::Connection> connections = inEdge->getConnections();
143  if (lefthand) {
144  std::reverse(connections.begin(), connections.end());
145  }
146  for (const NBEdge::Connection& c : connections) {
147  assert(c.toEdge != 0);
148  if (outEdge != c.toEdge || c.fromLane == lastFromLane) {
149  if (outEdge != nullptr) {
150  if (isOuterEdge) {
151  addPedestrianConnection(inEdge, outEdge, parallel);
152  }
153  connectionID = writeInternalEdge(device, junctionOSS, inEdge, nID,
154  getID(parallel.back().getInternalLaneID(), edgeMap, edgeID),
155  inEdgeID,
156  getID(outEdge->getID(), edgeMap, edgeID),
157  connectionID,
158  parallel, isOuterEdge, straightThresh, centerMark);
159  parallel.clear();
160  isOuterEdge = false;
161  }
162  outEdge = c.toEdge;
163  }
164  lastFromLane = c.fromLane;
165  parallel.push_back(c);
166  }
167  if (isOuterEdge) {
168  addPedestrianConnection(inEdge, outEdge, parallel);
169  }
170  if (!parallel.empty()) {
171  if (!lefthand && (n->geometryLike() || inEdge->isTurningDirectionAt(outEdge))) {
172  centerMark = "solid";
173  }
174  connectionID = writeInternalEdge(device, junctionOSS, inEdge, nID,
175  getID(parallel.back().getInternalLaneID(), edgeMap, edgeID),
176  inEdgeID,
177  getID(outEdge->getID(), edgeMap, edgeID),
178  connectionID,
179  parallel, isOuterEdge, straightThresh, centerMark);
180  parallel.clear();
181  }
182  }
183  if (n->numNormalConnections() > 0) {
184  junctionOSS << " </junction>\n";
185  }
186  }
187  device.lf();
188  // write junctions (junction)
189  device << junctionOSS.getString();
190 
191  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
192  NBNode* n = (*i).second;
193  const std::vector<NBEdge*>& incoming = n->getIncomingEdges();
194  // check if any connections must be written
195  int numConnections = 0;
196  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
197  numConnections += (int)((*j)->getConnections().size());
198  }
199  if (numConnections == 0) {
200  continue;
201  }
202  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
203  const NBEdge* inEdge = *j;
204  const std::vector<NBEdge::Connection>& elv = inEdge->getConnections();
205  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
206  const NBEdge::Connection& c = *k;
207  const NBEdge* outEdge = c.toEdge;
208  if (outEdge == nullptr) {
209  continue;
210  }
211  }
212  }
213  }
214 
215  device.closeTag();
216  device.close();
217 }
218 
219 
220 void
222  int edgeID, int fromNodeID, int toNodeID,
223  const bool origNames,
224  const double straightThresh,
225  const ShapeContainer& shc) {
226  // buffer output because some fields are computed out of order
227  OutputDevice_String elevationOSS(false, 3);
228  elevationOSS.setPrecision(8);
229  OutputDevice_String planViewOSS(false, 2);
230  planViewOSS.setPrecision(8);
231  double length = 0;
232 
233  planViewOSS.openTag("planView");
234  // for the shape we need to use the leftmost border of the leftmost lane
235  const std::vector<NBEdge::Lane>& lanes = e->getLanes();
237 #ifdef DEBUG_SMOOTH_GEOM
238  if (DEBUGCOND) {
239  std::cout << "write planview for edge " << e->getID() << "\n";
240  }
241 #endif
242 
243  if (ls.size() == 2 || e->getPermissions() == SVC_PEDESTRIAN) {
244  // foot paths may contain sharp angles
245  length = writeGeomLines(ls, planViewOSS, elevationOSS);
246  } else {
247  bool ok = writeGeomSmooth(ls, e->getSpeed(), planViewOSS, elevationOSS, straightThresh, length);
248  if (!ok) {
249  WRITE_WARNING("Could not compute smooth shape for edge '" + e->getID() + "'.");
250  }
251  }
252  planViewOSS.closeTag();
253 
254  device.openTag("road");
255  device.writeAttr("name", StringUtils::escapeXML(e->getStreetName()));
256  device.setPrecision(8); // length requires higher precision
257  device.writeAttr("length", MAX2(POSITION_EPS, length));
258  device.setPrecision(gPrecision);
259  device.writeAttr("id", edgeID);
260  device.writeAttr("junction", -1);
261  if (fromNodeID != INVALID_ID || toNodeID != INVALID_ID) {
262  device.openTag("link");
263  if (fromNodeID != INVALID_ID) {
264  device.openTag("predecessor");
265  device.writeAttr("elementType", "junction");
266  device.writeAttr("elementId", fromNodeID);
267  device.closeTag();
268  }
269  if (toNodeID != INVALID_ID) {
270  device.openTag("successor");
271  device.writeAttr("elementType", "junction");
272  device.writeAttr("elementId", toNodeID);
273  device.closeTag();
274  }
275  device.closeTag();
276  }
277  device.openTag("type").writeAttr("s", 0).writeAttr("type", "town").closeTag();
278  device << planViewOSS.getString();
279  writeElevationProfile(ls, device, elevationOSS);
280  device << " <lateralProfile/>\n";
281  device << " <lanes>\n";
282  device << " <laneSection s=\"0\">\n";
283  const std::string centerMark = e->getPermissions(e->getNumLanes() - 1) == 0 ? "none" : "solid";
284  writeEmptyCenterLane(device, centerMark, 0.13);
285  device << " <right>\n";
286  for (int j = e->getNumLanes(); --j >= 0;) {
287  device << " <lane id=\"-" << e->getNumLanes() - j << "\" type=\"" << getLaneType(e->getPermissions(j)) << "\" level=\"true\">\n";
288  device << " <link/>\n";
289  // this could be used for geometry-link junctions without u-turn,
290  // predecessor and sucessors would be lane indices,
291  // road predecessor / succesfors would be of type 'road' rather than
292  // 'junction'
293  //device << " <predecessor id=\"-1\"/>\n";
294  //device << " <successor id=\"-1\"/>\n";
295  //device << " </link>\n";
296  device << " <width sOffset=\"0\" a=\"" << e->getLaneWidth(j) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
297  std::string markType = "broken";
298  if (j == 0) {
299  markType = "solid";
300  } else if (j > 0
301  && (e->getPermissions(j - 1) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
302  // solid road mark to the left of sidewalk or bicycle lane
303  markType = "solid";
304  } else if (e->getPermissions(j) == 0) {
305  // solid road mark to the right of a forbidden lane
306  markType = "solid";
307  }
308  device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
309  device << " <speed sOffset=\"0\" max=\"" << lanes[j].speed << "\"/>\n";
310  device << " </lane>\n";
311  }
312  device << " </right>\n";
313  device << " </laneSection>\n";
314  device << " </lanes>\n";
315  writeRoadObjects(device, e, shc);
316  device << " <signals/>\n";
317  if (origNames) {
318  device << " <userData code=\"sumoId\" value=\"" << e->getID() << "\"/>\n";
319  }
320  device.closeTag();
322 }
323 
324 void
325 NWWriter_OpenDrive::addPedestrianConnection(const NBEdge* inEdge, const NBEdge* outEdge, std::vector<NBEdge::Connection>& parallel) {
326  // by default there are no internal lanes for pedestrians. Determine if
327  // one is feasible and does not exist yet.
328  if (outEdge != nullptr
329  && inEdge->getPermissions(0) == SVC_PEDESTRIAN
330  && outEdge->getPermissions(0) == SVC_PEDESTRIAN
331  && (parallel.empty()
332  || parallel.front().fromLane != 0
333  || parallel.front().toLane != 0)) {
334  parallel.insert(parallel.begin(), NBEdge::Connection(0, const_cast<NBEdge*>(outEdge), 0, false));
335  parallel.front().vmax = (inEdge->getLanes()[0].speed + outEdge->getLanes()[0].speed) / (double) 2.0;
336  }
337 }
338 
339 
340 int
341 NWWriter_OpenDrive::writeInternalEdge(OutputDevice& device, OutputDevice& junctionDevice, const NBEdge* inEdge, int nodeID,
342  int edgeID, int inEdgeID, int outEdgeID,
343  int connectionID,
344  const std::vector<NBEdge::Connection>& parallel,
345  const bool isOuterEdge,
346  const double straightThresh,
347  const std::string& centerMark) {
348  assert(parallel.size() != 0);
349  const NBEdge::Connection& cLeft = parallel.back();
350  const NBEdge* outEdge = cLeft.toEdge;
351  PositionVector begShape = getLeftLaneBorder(inEdge, cLeft.fromLane);
352  PositionVector endShape = getLeftLaneBorder(outEdge, cLeft.toLane);
353  //std::cout << "computing reference line for internal lane " << cLeft.getInternalLaneID() << " begLane=" << inEdge->getLaneShape(cLeft.fromLane) << " endLane=" << outEdge->getLaneShape(cLeft.toLane) << "\n";
354 
355  double length;
356  double laneOffset = 0;
357  PositionVector fallBackShape;
358  fallBackShape.push_back(begShape.back());
359  fallBackShape.push_back(endShape.front());
360  const bool turnaround = inEdge->isTurningDirectionAt(outEdge);
361  bool ok = true;
362  PositionVector init = NBNode::bezierControlPoints(begShape, endShape, turnaround, 25, 25, ok, nullptr, straightThresh);
363  if (init.size() == 0) {
364  length = fallBackShape.length2D();
365  // problem with turnarounds is known, method currently returns 'ok' (#2539)
366  if (!ok) {
367  WRITE_WARNING("Could not compute smooth shape from lane '" + inEdge->getLaneID(cLeft.fromLane) + "' to lane '" + outEdge->getLaneID(cLeft.toLane) + "'. Use option 'junctions.scurve-stretch' or increase radius of junction '" + inEdge->getToNode()->getID() + "' to fix this.");
368  } else if (length <= NUMERICAL_EPS) {
369  // left-curving geometry-like edges must use the right
370  // side as reference line and shift
371  begShape = getRightLaneBorder(inEdge, cLeft.fromLane);
372  endShape = getRightLaneBorder(outEdge, cLeft.toLane);
373  init = NBNode::bezierControlPoints(begShape, endShape, turnaround, 25, 25, ok, nullptr, straightThresh);
374  if (init.size() != 0) {
375  length = init.bezier(12).length2D();
376  laneOffset = outEdge->getLaneWidth(cLeft.toLane);
377  //std::cout << " internalLane=" << cLeft.getInternalLaneID() << " length=" << length << "\n";
378  }
379  }
380  } else {
381  length = init.bezier(12).length2D();
382  }
383 
384  junctionDevice << " <connection id=\"" << connectionID << "\" incomingRoad=\"" << inEdgeID << "\" connectingRoad=\"" << edgeID << "\" contactPoint=\"start\">\n";
385  device.openTag("road");
386  device.writeAttr("name", cLeft.id);
387  device.setPrecision(8); // length requires higher precision
388  device.writeAttr("length", MAX2(POSITION_EPS, length));
389  device.setPrecision(gPrecision);
390  device.writeAttr("id", edgeID);
391  device.writeAttr("junction", nodeID);
392  device.openTag("link");
393  device.openTag("predecessor");
394  device.writeAttr("elementType", "road");
395  device.writeAttr("elementId", inEdgeID);
396  device.writeAttr("contactPoint", "end");
397  device.closeTag();
398  device.openTag("successor");
399  device.writeAttr("elementType", "road");
400  device.writeAttr("elementId", outEdgeID);
401  device.writeAttr("contactPoint", "start");
402  device.closeTag();
403  device.closeTag();
404  device.openTag("type").writeAttr("s", 0).writeAttr("type", "town").closeTag();
405  device.openTag("planView");
406  device.setPrecision(8); // geometry hdg requires higher precision
407  OutputDevice_String elevationOSS(false, 3);
408  elevationOSS.setPrecision(8);
409 #ifdef DEBUG_SMOOTH_GEOM
410  if (DEBUGCOND) {
411  std::cout << "write planview for internal edge " << cLeft.id << " init=" << init << " fallback=" << fallBackShape
412  << " begShape=" << begShape << " endShape=" << endShape
413  << "\n";
414  }
415 #endif
416  if (init.size() == 0) {
417  writeGeomLines(fallBackShape, device, elevationOSS);
418  } else {
419  writeGeomPP3(device, elevationOSS, init, length);
420  }
421  device.setPrecision(gPrecision);
422  device.closeTag();
423  writeElevationProfile(fallBackShape, device, elevationOSS);
424  device << " <lateralProfile/>\n";
425  device << " <lanes>\n";
426  if (laneOffset != 0) {
427  device << " <laneOffset s=\"0\" a=\"" << laneOffset << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
428  }
429  device << " <laneSection s=\"0\">\n";
430  writeEmptyCenterLane(device, centerMark, 0);
431  device << " <right>\n";
432  for (int j = (int)parallel.size(); --j >= 0;) {
433  const NBEdge::Connection& c = parallel[j];
434  const int fromIndex = c.fromLane - inEdge->getNumLanes();
435  const int toIndex = c.toLane - outEdge->getNumLanes();
436  device << " <lane id=\"-" << parallel.size() - j << "\" type=\"" << getLaneType(outEdge->getPermissions(c.toLane)) << "\" level=\"true\">\n";
437  device << " <link>\n";
438  device << " <predecessor id=\"" << fromIndex << "\"/>\n";
439  device << " <successor id=\"" << toIndex << "\"/>\n";
440  device << " </link>\n";
441  device << " <width sOffset=\"0\" a=\"" << outEdge->getLaneWidth(c.toLane) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
442  std::string markType = "broken";
443  if (inEdge->isTurningDirectionAt(outEdge)) {
444  markType = "none";
445  } else if (c.fromLane == 0 && c.toLane == 0 && isOuterEdge) {
446  // solid road mark at the outer border
447  markType = "solid";
448  } else if (isOuterEdge && j > 0
449  && (outEdge->getPermissions(parallel[j - 1].toLane) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
450  // solid road mark to the left of sidewalk or bicycle lane
451  markType = "solid";
452  } else if (!inEdge->getToNode()->geometryLike()) {
453  // draw shorter road marks to indicate turning paths
454  LinkDirection dir = inEdge->getToNode()->getDirection(inEdge, outEdge, OptionsCont::getOptions().getBool("lefthand"));
455  if (dir == LINKDIR_LEFT || dir == LINKDIR_RIGHT || dir == LINKDIR_PARTLEFT || dir == LINKDIR_PARTRIGHT) {
456  // XXX <type><line/><type> is not rendered by odrViewer so cannot be validated
457  // device << " <type name=\"broken\" width=\"0.13\">\n";
458  // device << " <line length=\"0.5\" space=\"0.5\" tOffset=\"0\" sOffset=\"0\" rule=\"none\"/>\n";
459  // device << " </type>\n";
460  markType = "none";
461  }
462  }
463  device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
464  device << " <speed sOffset=\"0\" max=\"" << c.vmax << "\"/>\n";
465  device << " </lane>\n";
466 
467  junctionDevice << " <laneLink from=\"" << fromIndex << "\" to=\"" << toIndex << "\"/>\n";
468  connectionID++;
469  }
470  device << " </right>\n";
471  device << " </laneSection>\n";
472  device << " </lanes>\n";
473  device << " <objects/>\n";
474  device << " <signals/>\n";
475  device.closeTag();
476  junctionDevice << " </connection>\n";
477 
478  return connectionID;
479 }
480 
481 
482 double
483 NWWriter_OpenDrive::writeGeomLines(const PositionVector& shape, OutputDevice& device, OutputDevice& elevationDevice, double offset) {
484  for (int j = 0; j < (int)shape.size() - 1; ++j) {
485  const Position& p = shape[j];
486  const Position& p2 = shape[j + 1];
487  const double hdg = shape.angleAt2D(j);
488  const double length = p.distanceTo2D(p2);
489  device.openTag("geometry");
490  device.writeAttr("s", offset);
491  device.writeAttr("x", p.x());
492  device.writeAttr("y", p.y());
493  device.writeAttr("hdg", hdg);
494  device.writeAttr("length", length);
495  device.openTag("line").closeTag();
496  device.closeTag();
497  elevationDevice << " <elevation s=\"" << offset << "\" a=\"" << p.z() << "\" b=\"" << (p2.z() - p.z()) / MAX2(POSITION_EPS, length) << "\" c=\"0\" d=\"0\"/>\n";
498  offset += length;
499  }
500  return offset;
501 }
502 
503 
504 void
505 NWWriter_OpenDrive::writeEmptyCenterLane(OutputDevice& device, const std::string& mark, double markWidth) {
506  device << " <center>\n";
507  device << " <lane id=\"0\" type=\"none\" level=\"true\">\n";
508  device << " <link/>\n";
509  device << " <roadMark sOffset=\"0\" type=\"" << mark << "\" weight=\"standard\" color=\"standard\" width=\"" << markWidth << "\"/>\n";
510  device << " </lane>\n";
511  device << " </center>\n";
512 }
513 
514 
515 int
516 NWWriter_OpenDrive::getID(const std::string& origID, StringBijection<int>& map, int& lastID) {
517  if (map.hasString(origID)) {
518  return map.get(origID);
519  }
520  map.insert(origID, lastID++);
521  return lastID - 1;
522 }
523 
524 
525 std::string
527  switch (permissions) {
528  case SVC_PEDESTRIAN:
529  return "sidewalk";
530  //case (SVC_BICYCLE | SVC_PEDESTRIAN):
531  // WRITE_WARNING("Ambiguous lane type (biking+driving) for road '" + roadID + "'");
532  // return "sidewalk";
533  case SVC_BICYCLE:
534  return "biking";
535  case 0:
536  // ambiguous
537  return "none";
538  case SVC_RAIL:
539  case SVC_RAIL_URBAN:
540  case SVC_RAIL_ELECTRIC:
541  case SVC_RAIL_FAST:
542  return "rail";
543  case SVC_TRAM:
544  return "tram";
545  default: {
546  // complex permissions
547  if (permissions == SVCAll) {
548  return "driving";
549  } else if (isRailway(permissions)) {
550  return "rail";
551  } else if ((permissions & SVC_PASSENGER) != 0) {
552  return "driving";
553  } else {
554  return "restricted";
555  }
556  }
557  }
558 }
559 
560 
562 NWWriter_OpenDrive::getLeftLaneBorder(const NBEdge* edge, int laneIndex, double widthOffset) {
563  const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
564  if (laneIndex == -1) {
565  // leftmost lane
566  laneIndex = lefthand ? 0 : (int)edge->getNumLanes() - 1;
567  }
569  // PositionVector result = edge->getLaneShape(laneIndex);
570  // (and the moveo2side)
571  // However, the lanes in SUMO have a small lateral gap (SUMO_const_laneOffset) to account for markings
572  // In OpenDRIVE this gap does not exists so we have to do all lateral
573  // computations based on the reference line
574  // This assumes that the 'stop line' for all lanes is colinear!
575  const int leftmost = lefthand ? 0 : (int)edge->getNumLanes() - 1;
576  widthOffset -= (edge->getLaneWidth(leftmost) / 2);
577  // collect lane widths from left border of edge to left border of lane to connect to
578  if (lefthand) {
579  for (int i = leftmost; i < laneIndex; i++) {
580  widthOffset += edge->getLaneWidth(i);
581  }
582  } else {
583  for (int i = leftmost; i > laneIndex; i--) {
584  widthOffset += edge->getLaneWidth(i);
585  }
586  }
587  PositionVector result = edge->getLaneShape(leftmost);
588  try {
589  result.move2side(widthOffset);
590  } catch (InvalidArgument&) { }
591  return result;
592 }
593 
595 NWWriter_OpenDrive::getRightLaneBorder(const NBEdge* edge, int laneIndex) {
596  return getLeftLaneBorder(edge, laneIndex, edge->getLaneWidth(laneIndex));
597 }
598 
599 
600 double
602  OutputDevice& device,
603  OutputDevice& elevationDevice,
604  PositionVector init,
605  double length,
606  double offset) {
607  assert(init.size() == 3 || init.size() == 4);
608 
609  // avoid division by 0
610  length = MAX2(POSITION_EPS, length);
611 
612  const Position p = init.front();
613  const double hdg = init.angleAt2D(0);
614 
615  // backup elevation values
616  const PositionVector initZ = init;
617  // translate to u,v coordinates
618  init.add(-p.x(), -p.y(), -p.z());
619  init.rotate2D(-hdg);
620 
621  // parametric coefficients
622  double aU, bU, cU, dU;
623  double aV, bV, cV, dV;
624  double aZ, bZ, cZ, dZ;
625 
626  // unfactor the Bernstein polynomials of degree 2 (or 3) and collect the coefficients
627  if (init.size() == 3) {
628  //f(x, a, b ,c) = a + (2*b - 2*a)*x + (a - 2*b + c)*x*x
629  aU = init[0].x();
630  bU = 2 * init[1].x() - 2 * init[0].x();
631  cU = init[0].x() - 2 * init[1].x() + init[2].x();
632  dU = 0;
633 
634  aV = init[0].y();
635  bV = 2 * init[1].y() - 2 * init[0].y();
636  cV = init[0].y() - 2 * init[1].y() + init[2].y();
637  dV = 0;
638 
639  // elevation is not parameteric on [0:1] but on [0:length]
640  aZ = initZ[0].z();
641  bZ = (2 * initZ[1].z() - 2 * initZ[0].z()) / length;
642  cZ = (initZ[0].z() - 2 * initZ[1].z() + initZ[2].z()) / (length * length);
643  dZ = 0;
644 
645  } else {
646  // f(x, a, b, c, d) = a + (x*((3*b) - (3*a))) + ((x*x)*((3*a) + (3*c) - (6*b))) + ((x*x*x)*((3*b) - (3*c) - a + d))
647  aU = init[0].x();
648  bU = 3 * init[1].x() - 3 * init[0].x();
649  cU = 3 * init[0].x() - 6 * init[1].x() + 3 * init[2].x();
650  dU = -init[0].x() + 3 * init[1].x() - 3 * init[2].x() + init[3].x();
651 
652  aV = init[0].y();
653  bV = 3 * init[1].y() - 3 * init[0].y();
654  cV = 3 * init[0].y() - 6 * init[1].y() + 3 * init[2].y();
655  dV = -init[0].y() + 3 * init[1].y() - 3 * init[2].y() + init[3].y();
656 
657  // elevation is not parameteric on [0:1] but on [0:length]
658  aZ = initZ[0].z();
659  bZ = (3 * initZ[1].z() - 3 * initZ[0].z()) / length;
660  cZ = (3 * initZ[0].z() - 6 * initZ[1].z() + 3 * initZ[2].z()) / (length * length);
661  dZ = (-initZ[0].z() + 3 * initZ[1].z() - 3 * initZ[2].z() + initZ[3].z()) / (length * length * length);
662  }
663 
664  device.openTag("geometry");
665  device.writeAttr("s", offset);
666  device.writeAttr("x", p.x());
667  device.writeAttr("y", p.y());
668  device.writeAttr("hdg", hdg);
669  device.writeAttr("length", length);
670 
671  device.openTag("paramPoly3");
672  device.writeAttr("aU", aU);
673  device.writeAttr("bU", bU);
674  device.writeAttr("cU", cU);
675  device.writeAttr("dU", dU);
676  device.writeAttr("aV", aV);
677  device.writeAttr("bV", bV);
678  device.writeAttr("cV", cV);
679  device.writeAttr("dV", dV);
680  device.closeTag();
681  device.closeTag();
682 
683  // write elevation
684  elevationDevice.openTag("elevation");
685  elevationDevice.writeAttr("s", offset);
686  elevationDevice.writeAttr("a", aZ);
687  elevationDevice.writeAttr("b", bZ);
688  elevationDevice.writeAttr("c", cZ);
689  elevationDevice.writeAttr("d", dZ);
690  elevationDevice.closeTag();
691 
692  return offset + length;
693 }
694 
695 
696 bool
697 NWWriter_OpenDrive::writeGeomSmooth(const PositionVector& shape, double speed, OutputDevice& device, OutputDevice& elevationDevice, double straightThresh, double& length) {
698 #ifdef DEBUG_SMOOTH_GEOM
699  if (DEBUGCOND) {
700  std::cout << "writeGeomSmooth\n n=" << shape.size() << " shape=" << toString(shape) << "\n";
701  }
702 #endif
703  bool ok = true;
704  const double longThresh = speed; // 16.0; // make user-configurable (should match the sampling rate of the source data)
705  const double curveCutout = longThresh / 2; // 8.0; // make user-configurable (related to the maximum turning rate)
706  // the length of the segment that is added for cutting a corner can be bounded by 2*curveCutout (prevent the segment to be classified as 'long')
707  assert(longThresh >= 2 * curveCutout);
708  assert(shape.size() > 2);
709  // add intermediate points wherever there is a strong angular change between long segments
710  // assume the geometry is simplified so as not to contain consecutive colinear points
711  PositionVector shape2 = shape;
712  double maxAngleDiff = 0;
713  double offset = 0;
714  for (int j = 1; j < (int)shape.size() - 1; ++j) {
715  //const double hdg = shape.angleAt2D(j);
716  const Position& p0 = shape[j - 1];
717  const Position& p1 = shape[j];
718  const Position& p2 = shape[j + 1];
719  const double dAngle = fabs(GeomHelper::angleDiff(p0.angleTo2D(p1), p1.angleTo2D(p2)));
720  const double length1 = p0.distanceTo2D(p1);
721  const double length2 = p1.distanceTo2D(p2);
722  maxAngleDiff = MAX2(maxAngleDiff, dAngle);
723 #ifdef DEBUG_SMOOTH_GEOM
724  if (DEBUGCOND) {
725  std::cout << " j=" << j << " dAngle=" << RAD2DEG(dAngle) << " length1=" << length1 << " length2=" << length2 << "\n";
726  }
727 #endif
728  if (dAngle > straightThresh
729  && (length1 > longThresh || j == 1)
730  && (length2 > longThresh || j == (int)shape.size() - 2)) {
731  shape2.insertAtClosest(shape.positionAtOffset2D(offset + length1 - MIN2(length1 - POSITION_EPS, curveCutout)), false);
732  shape2.insertAtClosest(shape.positionAtOffset2D(offset + length1 + MIN2(length2 - POSITION_EPS, curveCutout)), false);
733  shape2.removeClosest(p1);
734  }
735  offset += length1;
736  }
737  const int numPoints = (int)shape2.size();
738 #ifdef DEBUG_SMOOTH_GEOM
739  if (DEBUGCOND) {
740  std::cout << " n=" << numPoints << " shape2=" << toString(shape2) << "\n";
741  }
742 #endif
743 
744  if (maxAngleDiff < straightThresh) {
745  length = writeGeomLines(shape2, device, elevationDevice, 0);
746 #ifdef DEBUG_SMOOTH_GEOM
747  if (DEBUGCOND) {
748  std::cout << " special case: all lines. maxAngleDiff=" << maxAngleDiff << "\n";
749  }
750 #endif
751  return ok;
752  }
753 
754  // write the long segments as lines, short segments as curves
755  offset = 0;
756  for (int j = 0; j < numPoints - 1; ++j) {
757  const Position& p0 = shape2[j];
758  const Position& p1 = shape2[j + 1];
759  PositionVector line;
760  line.push_back(p0);
761  line.push_back(p1);
762  const double lineLength = line.length2D();
763  if (lineLength >= longThresh) {
764  offset = writeGeomLines(line, device, elevationDevice, offset);
765 #ifdef DEBUG_SMOOTH_GEOM
766  if (DEBUGCOND) {
767  std::cout << " writeLine=" << toString(line) << "\n";
768  }
769 #endif
770  } else {
771  // find control points
772  PositionVector begShape;
773  PositionVector endShape;
774  if (j == 0 || j == numPoints - 2) {
775  // keep the angle of the first/last segment but end at the front of the shape
776  begShape = line;
777  begShape.add(p0 - begShape.back());
778  } else if (j == 1 || p0.distanceTo2D(shape2[j - 1]) > longThresh) {
779  // use the previous segment if it is long or the first one
780  begShape.push_back(shape2[j - 1]);
781  begShape.push_back(p0);
782  } else {
783  // end at p0 with mean angle of the previous and current segment
784  begShape.push_back(shape2[j - 1]);
785  begShape.push_back(p1);
786  begShape.add(p0 - begShape.back());
787  }
788 
789  if (j == 0 || j == numPoints - 2) {
790  // keep the angle of the first/last segment but start at the end of the shape
791  endShape = line;
792  endShape.add(p1 - endShape.front());
793  } else if (j == numPoints - 3 || p1.distanceTo2D(shape2[j + 2]) > longThresh) {
794  // use the next segment if it is long or the final one
795  endShape.push_back(p1);
796  endShape.push_back(shape2[j + 2]);
797  } else {
798  // start at p1 with mean angle of the current and next segment
799  endShape.push_back(p0);
800  endShape.push_back(shape2[j + 2]);
801  endShape.add(p1 - endShape.front());
802  }
803  const double extrapolateLength = MIN2((double)25, lineLength / 4);
804  PositionVector init = NBNode::bezierControlPoints(begShape, endShape, false, extrapolateLength, extrapolateLength, ok, nullptr, straightThresh);
805  if (init.size() == 0) {
806  // could not compute control points, write line
807  offset = writeGeomLines(line, device, elevationDevice, offset);
808 #ifdef DEBUG_SMOOTH_GEOM
809  if (DEBUGCOND) {
810  std::cout << " writeLine lineLength=" << lineLength << " begShape" << j << "=" << toString(begShape) << " endShape" << j << "=" << toString(endShape) << " init" << j << "=" << toString(init) << "\n";
811  }
812 #endif
813  } else {
814  // write bezier
815  const double curveLength = init.bezier(12).length2D();
816  offset = writeGeomPP3(device, elevationDevice, init, curveLength, offset);
817 #ifdef DEBUG_SMOOTH_GEOM
818  if (DEBUGCOND) {
819  std::cout << " writeCurve lineLength=" << lineLength << " curveLength=" << curveLength << " begShape" << j << "=" << toString(begShape) << " endShape" << j << "=" << toString(endShape) << " init" << j << "=" << toString(init) << "\n";
820  }
821 #endif
822  }
823  }
824  }
825  length = offset;
826  return ok;
827 }
828 
829 
830 void
832  // check if the shape is flat
833  bool flat = true;
834  double z = shape.size() == 0 ? 0 : shape[0].z();
835  for (int i = 1; i < (int)shape.size(); ++i) {
836  if (fabs(shape[i].z() - z) > NUMERICAL_EPS) {
837  flat = false;
838  break;
839  }
840  }
841  device << " <elevationProfile>\n";
842  if (flat) {
843  device << " <elevation s=\"0\" a=\"" << z << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
844  } else {
845  device << elevationDevice.getString();
846  }
847  device << " </elevationProfile>\n";
848 
849 }
850 
851 
852 void
854  if (e->getNumLanes() > 1) {
855  // compute 'stop line' of rightmost lane
856  const PositionVector shape0 = e->getLaneShape(0);
857  assert(shape0.size() >= 2);
858  const Position& from = shape0[-2];
859  const Position& to = shape0[-1];
860  PositionVector stopLine;
861  stopLine.push_back(to);
862  stopLine.push_back(to - PositionVector::sideOffset(from, to, -1000.0));
863  // endpoints of all other lanes should be on the stop line
864  for (int lane = 1; lane < e->getNumLanes(); ++lane) {
865  const double dist = stopLine.distance2D(e->getLaneShape(lane)[-1]);
866  if (dist > NUMERICAL_EPS) {
867  WRITE_WARNING("Uneven stop line at lane '" + e->getLaneID(lane) + "' (dist=" + toString(dist) + ") cannot be represented in OpenDRIVE.");
868  }
869  }
870  }
871 }
872 
873 void
875  if (e->knowsParameter("roadObjects")) {
876  device.openTag("objects");
877  device.setPrecision(8); // geometry hdg requires higher precision
879  for (std::string id : StringTokenizer(e->getParameter("roadObjects", "")).getVector()) {
880  SUMOPolygon* p = shc.getPolygons().get(id);
881  if (p == nullptr) {
882  WRITE_WARNING("Road object polygon '" + id + "' not found for edge '" + e->getID() + "'");
883  } else if (p->getShape().size() != 4) {
884  WRITE_WARNING("Cannot convert road object polygon '" + id + "' with " + toString(p->getShape().size()) + " points for edge '" + e->getID() + "'");
885  } else {
886  const PositionVector& shape = p->getShape();
887  device.openTag("object");
888  Position center = shape.getPolygonCenter();
889  PositionVector sideline = shape.getSubpartByIndex(0, 2);
890  PositionVector ortholine = shape.getSubpartByIndex(1, 2);
891  const double absAngle = sideline.angleAt2D(0);
892  const double length = sideline.length2D();
893  const double width = ortholine.length2D();
894  const double edgeOffset = road.nearest_offset_to_point2D(center);
895  if (edgeOffset == GeomHelper::INVALID_OFFSET) {
896  WRITE_WARNING("Cannot map road object polygon '" + id + "' with center " + toString(center) + " onto edge '" + e->getID() + "'");
897  continue;
898  }
899  Position edgePos = road.positionAtOffset2D(edgeOffset);
900  const double edgeAngle = road.rotationAtOffset(edgeOffset);
901  const double relAngle = absAngle - edgeAngle;
902  double sideOffset = center.distanceTo2D(edgePos);
903  // determine sign of sideOffset
904  PositionVector tmp = road.getSubpart2D(MAX2(0.0, edgeOffset - 1), MIN2(road.length2D(), edgeOffset + 1));
905  tmp.move2side(sideOffset);
906  if (tmp.distance2D(center) < sideOffset) {
907  sideOffset *= -1;
908  }
909  //std::cout << " id=" << id
910  // << " shape=" << shape
911  // << " center=" << center
912  // << " edgeOffset=" << edgeOffset
913  // << "\n";
914  device.writeAttr("id", id);
915  device.writeAttr("type", p->getShapeType());
916  device.writeAttr("name", p->getParameter("name", ""));
917  device.writeAttr("s", edgeOffset);
918  device.writeAttr("t", sideOffset);
919  device.writeAttr("width", width);
920  device.writeAttr("length", length);
921  device.writeAttr("hdg", relAngle);
922  device.closeTag();
923  }
924  }
925  device.setPrecision(gPrecision);
926  device.closeTag();
927  } else {
928  device << " <objects/>\n";
929  }
930 }
931 
932 /****************************************************************************/
933 
SVC_RAIL_FAST
vehicle that is allowed to drive on high-speed rail tracks
Definition: SUMOVehicleClass.h:192
OptionsCont::isSet
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
Definition: OptionsCont.cpp:135
NWWriter_OpenDrive::addPedestrianConnection
static void addPedestrianConnection(const NBEdge *inEdge, const NBEdge *outEdge, std::vector< NBEdge::Connection > &parallel)
Definition: NWWriter_OpenDrive.cpp:325
SVC_PEDESTRIAN
pedestrian
Definition: SUMOVehicleClass.h:156
NBEdge::Connection::toEdge
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:212
MIN2
T MIN2(T a, T b)
Definition: StdDefs.h:73
PositionVector::getPolygonCenter
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
Definition: PositionVector.cpp:400
PositionVector::getSubpartByIndex
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
Definition: PositionVector.cpp:789
NBEdge::Connection::vmax
double vmax
maximum velocity
Definition: NBEdge.h:254
WRITE_WARNING
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:275
GeoConvHelper::getConvBoundary
const Boundary & getConvBoundary() const
Returns the converted boundary.
Definition: GeoConvHelper.cpp:489
NBEdgeCont
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:60
OutputDevice_String
An output device that encapsulates an ofstream.
Definition: OutputDevice_String.h:39
GeomHelper::angleDiff
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:180
NBNetBuilder
Instance responsible for building networks.
Definition: NBNetBuilder.h:109
Boundary::ymin
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:130
OutputDevice
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:63
NBNodeCont::end
std::map< std::string, NBNode * >::const_iterator end() const
Returns the pointer to the end of the stored nodes.
Definition: NBNodeCont.h:120
NUMERICAL_EPS
#define NUMERICAL_EPS
Definition: config.h:148
PositionVector::getSubpart2D
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
Definition: PositionVector.cpp:746
Position::z
double z() const
Returns the z-position.
Definition: Position.h:66
OptionsCont.h
PositionVector::rotate2D
void rotate2D(double angle)
Definition: PositionVector.cpp:1503
NBNode::bezierControlPoints
static PositionVector bezierControlPoints(const PositionVector &begShape, const PositionVector &endShape, bool isTurnaround, double extrapolateBeg, double extrapolateEnd, bool &ok, NBNode *recordError=0, double straightThresh=DEG2RAD(5), int shapeFlag=0)
get bezier control points
Definition: NBNode.cpp:533
MsgHandler.h
LINKDIR_PARTRIGHT
The link is a partial right direction.
Definition: SUMOXMLDefinitions.h:1190
NWWriter_OpenDrive::writeEmptyCenterLane
static void writeEmptyCenterLane(OutputDevice &device, const std::string &mark, double markWidth)
Definition: NWWriter_OpenDrive.cpp:505
NBEdge::isTurningDirectionAt
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2756
NWWriter_OpenDrive::writeNetwork
static void writeNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Writes the network into a openDRIVE-file.
Definition: NWWriter_OpenDrive.cpp:55
OptionsCont::getString
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
Definition: OptionsCont.cpp:201
OutputDevice::setPrecision
void setPrecision(int precision=gPrecision)
Sets the precison or resets it to default.
Definition: OutputDevice.cpp:221
NBEdgeCont.h
PositionVector::sideOffset
static Position sideOffset(const Position &beg, const Position &end, const double amount)
get a side position of position vector using a offset
Definition: PositionVector.cpp:1096
NWWriter_OpenDrive::getRightLaneBorder
static PositionVector getRightLaneBorder(const NBEdge *edge, int laneIndex=-1)
Definition: NWWriter_OpenDrive.cpp:595
GeoConvHelper.h
Boundary::xmax
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:124
ShapeContainer
Storage for geometrical objects.
Definition: ShapeContainer.h:49
NBNodeCont::begin
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:115
OptionsCont::getBool
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Definition: OptionsCont.cpp:222
SVC_BICYCLE
vehicle is a bicycle
Definition: SUMOVehicleClass.h:179
OptionsCont::getOptions
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:57
NWWriter_OpenDrive::writeGeomLines
static double writeGeomLines(const PositionVector &shape, OutputDevice &device, OutputDevice &elevationDevice, double offset=0)
write geometry as sequence of lines (sumo style)
Definition: NWWriter_OpenDrive.cpp:483
RAD2DEG
#define RAD2DEG(x)
Definition: GeomHelper.h:38
NBEdge::getPermissions
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3404
LinkDirection
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
Definition: SUMOXMLDefinitions.h:1176
PositionVector
A list of positions.
Definition: PositionVector.h:45
NWWriter_OpenDrive::getLeftLaneBorder
static PositionVector getLeftLaneBorder(const NBEdge *edge, int laneIndex=-1, double widthOffset=0)
get the left border of the given lane (the leftmost one by default)
Definition: NWWriter_OpenDrive.cpp:562
GeoConvHelper
static methods for processing the coordinates conversion for the current net
Definition: GeoConvHelper.h:55
SVC_RAIL
vehicle is a not electrified rail
Definition: SUMOVehicleClass.h:188
SVC_RAIL_URBAN
vehicle is a city rail
Definition: SUMOVehicleClass.h:186
GeoConvHelper::usingGeoProjection
bool usingGeoProjection() const
Returns whether a transformation from geo to metric coordinates will be performed.
Definition: GeoConvHelper.cpp:281
GeoConvHelper::getProjString
const std::string & getProjString() const
Returns the original projection definition.
Definition: GeoConvHelper.cpp:507
NBNetBuilder::getEdgeCont
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:150
NBNodeCont
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:59
NBEdge::Connection::fromLane
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:209
OutputDevice_String::getString
std::string getString() const
Returns the current content as a string.
Definition: OutputDevice_String.cpp:43
PositionVector::angleAt2D
double angleAt2D(int pos) const
get angle in certain position of position vector
Definition: PositionVector.cpp:1221
Parameterised::getParameter
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
Definition: Parameterised.cpp:72
NBEdge
The representation of a single edge during network building.
Definition: NBEdge.h:91
OutputDevice::closeTag
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Definition: OutputDevice.cpp:253
LINKDIR_RIGHT
The link is a (hard) right direction.
Definition: SUMOXMLDefinitions.h:1186
MAX2
T MAX2(T a, T b)
Definition: StdDefs.h:79
NWWriter_OpenDrive::getID
static int getID(const std::string &origID, StringBijection< int > &map, int &lastID)
Definition: NWWriter_OpenDrive.cpp:516
PositionVector::add
void add(double xoff, double yoff, double zoff)
Definition: PositionVector.cpp:617
NBEdge::Connection::toLane
int toLane
The lane the connections yields in.
Definition: NBEdge.h:215
SVC_TRAM
vehicle is a light rail
Definition: SUMOVehicleClass.h:184
PositionVector::nearest_offset_to_point2D
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
Definition: PositionVector.cpp:817
OutputDevice::writeAttr
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:255
NBEdge::getToNode
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:498
StringBijection< int >
Boundary::xmin
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:118
NBEdge::getLaneWidth
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:587
GeoConvHelper::getFinal
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
Definition: GeoConvHelper.h:105
SVCPermissions
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
Definition: SUMOVehicleClass.h:218
GeomHelper::INVALID_OFFSET
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:51
StringBijection::insert
void insert(const std::string str, const T key, bool checkDuplicates=true)
Definition: StringBijection.h:71
StringBijection::get
T get(const std::string &str) const
Definition: StringBijection.h:97
NBEdge::getLaneID
std::string getLaneID(int lane) const
get lane ID
Definition: NBEdge.cpp:3093
StringTokenizer
Definition: StringTokenizer.h:61
NBNode::getDirection
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
Definition: NBNode.cpp:1933
SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
Definition: SUMOVehicleClass.h:159
StringUtils::escapeXML
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
Definition: StringUtils.cpp:190
DEBUGCOND
#define DEBUGCOND
Definition: NWWriter_OpenDrive.cpp:43
Boundary
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:41
SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
Definition: SUMOVehicleClass.h:190
NBEdge::getNumLanes
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:477
NBNode::numNormalConnections
int numNormalConnections() const
return the number of lane-to-lane connections at this junction (excluding crossings)
Definition: NBNode.cpp:3140
OutputDevice.h
NBNetBuilder.h
NWWriter_OpenDrive::writeNormalEdge
static void writeNormalEdge(OutputDevice &device, const NBEdge *e, int edgeID, int fromNodeID, int toNodeID, const bool origNames, const double straightThresh, const ShapeContainer &shc)
write normal edge to device
Definition: NWWriter_OpenDrive.cpp:221
isRailway
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
Definition: SUMOVehicleClass.cpp:363
Position
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:38
Position::x
double x() const
Returns the x-position.
Definition: Position.h:56
GeoConvHelper::getOffsetBase
const Position getOffsetBase() const
Returns the network base.
Definition: GeoConvHelper.cpp:501
OptionsCont
A storage for options typed value containers)
Definition: OptionsCont.h:89
Shape::getShapeType
const std::string & getShapeType() const
Returns the (abstract) type of the Shape.
Definition: Shape.h:75
LINKDIR_LEFT
The link is a (hard) left direction.
Definition: SUMOXMLDefinitions.h:1184
NWWriter_OpenDrive::getLaneType
static std::string getLaneType(SVCPermissions permissions)
Definition: NWWriter_OpenDrive.cpp:526
PositionVector::length2D
double length2D() const
Returns the length.
Definition: PositionVector.cpp:497
SUMOPolygon::getShape
const PositionVector & getShape() const
Returns whether the shape of the polygon.
Definition: SUMOPolygon.h:81
NBEdgeCont::end
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:192
DEG2RAD
#define DEG2RAD(x)
Definition: GeomHelper.h:37
NBEdge::getLanes
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:656
NBEdge::getStreetName
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:600
PositionVector::distance2D
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
Definition: PositionVector.cpp:1259
Position::angleTo2D
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position
Definition: Position.h:253
Position::distanceTo2D
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:243
NBEdge::getIncomingEdges
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1211
INVALID_ID
#define INVALID_ID
Definition: NWWriter_OpenDrive.cpp:40
NWWriter_OpenDrive::checkLaneGeometries
static void checkLaneGeometries(const NBEdge *e)
check if the lane geometries are compatible with OpenDRIVE assumptions (colinear stop line)
Definition: NWWriter_OpenDrive.cpp:853
OptionsCont::getFloat
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
Definition: OptionsCont.cpp:208
NWWriter_OpenDrive::writeElevationProfile
static void writeElevationProfile(const PositionVector &shape, OutputDevice &device, const OutputDevice_String &elevationDevice)
Definition: NWWriter_OpenDrive.cpp:831
NBEdge::getLaneShape
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:879
OutputDevice::openTag
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
Definition: OutputDevice.cpp:239
SUMOPolygon
Definition: SUMOPolygon.h:46
NBNodeCont.h
toString
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:47
StringUtils.h
OutputDevice::getDevice
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
Definition: OutputDevice.cpp:54
Position::y
double y() const
Returns the y-position.
Definition: Position.h:61
PositionVector::positionAtOffset2D
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
Definition: PositionVector.cpp:273
PositionVector::rotationAtOffset
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Definition: PositionVector.cpp:294
NBEdge::getSpeed
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:571
NBNode::geometryLike
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3026
InvalidArgument
Definition: UtilExceptions.h:56
SVCAll
const SVCPermissions SVCAll
all VClasses are allowed
Definition: SUMOVehicleClass.cpp:146
OutputDevice_String.h
NBNode::getIncomingEdges
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:255
NamedObjectCont::get
T get(const std::string &id) const
Retrieves an item.
Definition: NamedObjectCont.h:98
NBNodeCont::size
int size() const
Returns the number of nodes stored in this container.
Definition: NBNodeCont.h:263
OutputDevice::lf
void lf()
writes a line feed if applicable
Definition: OutputDevice.h:233
config.h
StringBijection::hasString
bool hasString(const std::string &str) const
Definition: StringBijection.h:116
StringTokenizer.h
PositionVector::bezier
PositionVector bezier(int numPoints)
return a bezier interpolation
Definition: PositionVector.cpp:1682
gPrecision
int gPrecision
the precision for floating point outputs
Definition: StdDefs.cpp:26
StdDefs.h
NBNode
Represents a single node (junction) during network building.
Definition: NBNode.h:67
ShapeContainer::getPolygons
const Polygons & getPolygons() const
Returns all polygons.
Definition: ShapeContainer.h:149
NBNetBuilder::getShapeCont
ShapeContainer & getShapeCont()
Definition: NBNetBuilder.h:190
NWWriter_OpenDrive::writeGeomSmooth
static bool writeGeomSmooth(const PositionVector &shape, double speed, OutputDevice &device, OutputDevice &elevationDevice, double straightThresh, double &length)
Definition: NWWriter_OpenDrive.cpp:697
NBNetBuilder::getNodeCont
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:155
NBEdge::Connection
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:189
NBNode.h
NWWriter_OpenDrive::writeGeomPP3
static double writeGeomPP3(OutputDevice &device, OutputDevice &elevationDevice, PositionVector init, double length, double offset=0)
write geometry as a single bezier curve (paramPoly3)
Definition: NWWriter_OpenDrive.cpp:601
LINKDIR_PARTLEFT
The link is a partial left direction.
Definition: SUMOXMLDefinitions.h:1188
Named::getID
const std::string & getID() const
Returns the id.
Definition: Named.h:76
NBEdgeCont::begin
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:184
POSITION_EPS
#define POSITION_EPS
Definition: config.h:172
NBEdge::getConnections
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:934
NBEdge::getFromNode
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:491
PositionVector::move2side
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount
Definition: PositionVector.cpp:1103
Parameterised::knowsParameter
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
Definition: Parameterised.cpp:66
NWWriter_OpenDrive::writeRoadObjects
static void writeRoadObjects(OutputDevice &device, const NBEdge *e, const ShapeContainer &shc)
write road objects referenced as edge parameters
Definition: NWWriter_OpenDrive.cpp:874
Boundary::ymax
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:136
NWWriter_OpenDrive.h
NWWriter_OpenDrive::writeInternalEdge
static int writeInternalEdge(OutputDevice &device, OutputDevice &junctionDevice, const NBEdge *inEdge, int nodeID, int edgeID, int inEdgeID, int outEdgeID, int connectionID, const std::vector< NBEdge::Connection > &parallel, const bool isOuterEdge, const double straightThresh, const std::string &centerMark)
write internal edge to device, return next connectionID
Definition: NWWriter_OpenDrive.cpp:341
NBEdge::getID
const std::string & getID() const
Definition: NBEdge.h:1380