SUMO - Simulation of Urban MObility
NWWriter_OpenDrive.cpp
Go to the documentation of this file.
1 /****************************************************************************/
8 // Exporter writing networks using the openDRIVE format
9 /****************************************************************************/
10 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
11 // Copyright (C) 2011-2016 DLR (http://www.dlr.de/) and contributors
12 /****************************************************************************/
13 //
14 // This file is part of SUMO.
15 // SUMO is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation, either version 3 of the License, or
18 // (at your option) any later version.
19 //
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #ifdef _MSC_VER
27 #include <windows_config.h>
28 #else
29 #include <config.h>
30 #endif
31 
32 #include <ctime>
33 #include "NWWriter_OpenDrive.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>
43 #include <utils/geom/bezier.h>
45 #include <utils/common/StdDefs.h>
48 
49 #ifdef CHECK_MEMORY_LEAKS
50 #include <foreign/nvwa/debug_new.h>
51 #endif // CHECK_MEMORY_LEAKS
52 
53 //#define DEBUG_SMOOTH_GEOM
54 #define DEBUGCOND true
55 
56 #define MIN_TURN_DIAMETER 2.0
57 
58 
59 // ===========================================================================
60 // method definitions
61 // ===========================================================================
62 // ---------------------------------------------------------------------------
63 // static methods
64 // ---------------------------------------------------------------------------
65 void
67  // check whether an opendrive-file shall be generated
68  if (!oc.isSet("opendrive-output")) {
69  return;
70  }
71  const bool origNames = oc.getBool("output.original-names");
72  // some internal mapping containers
73  int edgeID = 1;
74  int nodeID = 1;
75  StringBijection<int> edgeMap;
76  StringBijection<int> nodeMap;
77  //
78  OutputDevice& device = OutputDevice::getDevice(oc.getString("opendrive-output"));
79  device << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
80  device.openTag("OpenDRIVE");
81  time_t now = time(0);
82  std::string dstr(ctime(&now));
83  const NBNodeCont& nc = nb.getNodeCont();
84  const NBEdgeCont& ec = nb.getEdgeCont();
86  // write header
87  device.openTag("header");
88  device.writeAttr("revMajor", "1");
89  device.writeAttr("revMinor", "4");
90  device.writeAttr("name", "");
91  device.writeAttr("version", "1.00");
92  device.writeAttr("date", dstr.substr(0, dstr.length() - 1));
93  device.writeAttr("north", b.ymax());
94  device.writeAttr("south", b.ymin());
95  device.writeAttr("east", b.xmax());
96  device.writeAttr("west", b.xmin());
97  device.writeAttr("maxRoad", ec.size());
98  device.writeAttr("maxJunc", nc.size());
99  device.writeAttr("maxPrg", 0);
100  device.closeTag();
101 
102  // write normal edges (road)
103  for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
104  const NBEdge* e = (*i).second;
105  device << " <road name=\"" << StringUtils::escapeXML(e->getStreetName()) << "\" length=\"" << e->getLength() << "\" id=\"" << getID(e->getID(), edgeMap, edgeID) << "\" junction=\"-1\">\n";
106  device << " <link>\n";
107  device << " <predecessor elementType=\"junction\" elementId=\"" << getID(e->getFromNode()->getID(), nodeMap, nodeID) << "\"/>\n";
108  device << " <successor elementType=\"junction\" elementId=\"" << getID(e->getToNode()->getID(), nodeMap, nodeID) << "\"/>\n";
109  device << " </link>\n";
110  device << " <type s=\"0\" type=\"town\"/>\n";
111  device << " <planView>\n";
112  device << std::setprecision(8); // geometry hdg requires higher precision
113  // for the shape we need to use the leftmost border of the leftmost lane
114  const std::vector<NBEdge::Lane>& lanes = e->getLanes();
116 #ifdef DEBUG_SMOOTH_GEOM
117  if (DEBUGCOND) {
118  std::cout << "write planview for edge " << e->getID() << "\n";
119  }
120 #endif
121  OutputDevice_String elevationOSS(false, 3);
122  elevationOSS.setPrecision(8);
123  if (ls.size() == 2 || e->getPermissions() == SVC_PEDESTRIAN) {
124  // foot paths may contain sharp angles
125  writeGeomLines(ls, device, elevationOSS);
126  } else {
127  writeGeomSmooth(ls, e->getSpeed(), device, elevationOSS);
128  }
129  device << std::setprecision(OUTPUT_ACCURACY);
130  device << " </planView>\n";
131  writeElevationProfile(ls, device, elevationOSS);
132  device << " <lateralProfile/>\n";
133  device << " <lanes>\n";
134  device << " <laneSection s=\"0\">\n";
135  writeEmptyCenterLane(device, "solid", 0.13);
136  device << " <right>\n";
137  for (int j = e->getNumLanes(); --j >= 0;) {
138  device << " <lane id=\"-" << e->getNumLanes() - j << "\" type=\"" << getLaneType(e->getPermissions(j)) << "\" level=\"0\">\n";
139  device << " <link/>\n";
140  // this could be used for geometry-link junctions without u-turn,
141  // predecessor and sucessors would be lane indices,
142  // road predecessor / succesfors would be of type 'road' rather than
143  // 'junction'
144  //device << " <predecessor id=\"-1\"/>\n";
145  //device << " <successor id=\"-1\"/>\n";
146  //device << " </link>\n";
147  device << " <width sOffset=\"0\" a=\"" << e->getLaneWidth(j) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
148  std::string markType = "broken";
149  if (j == 0) {
150  markType = "solid";
151  }
152  device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
153  device << " <speed sOffset=\"0\" max=\"" << lanes[j].speed << "\"/>\n";
154  device << " </lane>\n";
155  }
156  device << " </right>\n";
157  device << " </laneSection>\n";
158  device << " </lanes>\n";
159  device << " <objects/>\n";
160  device << " <signals/>\n";
161  if (origNames) {
162  device << " <userData sumoId=\"" << e->getID() << "\"/>\n";
163  }
164  device << " </road>\n";
165  }
166  device << "\n";
167  // write junction-internal edges (road)
168  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
169  NBNode* n = (*i).second;
170  const std::vector<NBEdge*>& incoming = (*i).second->getIncomingEdges();
171  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
172  const NBEdge* inEdge = *j;
173  const std::vector<NBEdge::Connection>& elv = inEdge->getConnections();
174  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
175  const NBEdge::Connection& c = *k;
176  const NBEdge* outEdge = c.toEdge;
177  if (outEdge == 0) {
178  continue;
179  }
180  const SUMOReal width = c.toEdge->getLaneWidth(c.toLane);
181  const PositionVector begShape = getLeftLaneBorder(inEdge, c.fromLane);
182  const PositionVector endShape = getLeftLaneBorder(outEdge, c.toLane);
183 
184  SUMOReal length;
185  PositionVector fallBackShape;
186  PositionVector init = NBNode::bezierControlPoints(begShape, endShape, inEdge->isTurningDirectionAt(outEdge), 25, 25);
187  if (init.size() == 0) {
188  fallBackShape.push_back(begShape.back());
189  fallBackShape.push_back(endShape.front());
190  length = fallBackShape.length2D();
191  } else {
192  length = bezier(init, 12).length2D();
193  }
194 
195  device << " <road name=\"" << c.getInternalLaneID() << "\" length=\"" << length << "\" id=\"" << getID(c.getInternalLaneID(), edgeMap, edgeID) << "\" junction=\"" << getID(n->getID(), nodeMap, nodeID) << "\">\n";
196  device << " <link>\n";
197  device << " <predecessor elementType=\"road\" elementId=\"" << getID(inEdge->getID(), edgeMap, edgeID) << "\" contactPoint=\"end\"/>\n";
198  device << " <successor elementType=\"road\" elementId=\"" << getID(outEdge->getID(), edgeMap, edgeID) << "\" contactPoint=\"start\"/>\n";
199  device << " </link>\n";
200  device << " <type s=\"0\" type=\"town\"/>\n";
201  device << " <planView>\n";
202  device << std::setprecision(8); // geometry hdg requires higher precision
203  OutputDevice_String elevationOSS(false, 3);
204  if (init.size() == 0) {
205  writeGeomLines(fallBackShape, device, elevationOSS);
206  } else {
207  writeGeomPP3(device, elevationOSS, init, length);
208  }
209  device << std::setprecision(OUTPUT_ACCURACY);
210  device << " </planView>\n";
211  writeElevationProfile(fallBackShape, device, elevationOSS);
212  device << " <lateralProfile/>\n";
213  device << " <lanes>\n";
214  device << " <laneSection s=\"0\">\n";
215  writeEmptyCenterLane(device, "none", 0);
216  device << " <right>\n";
217  device << " <lane id=\"-1\" type=\"" << getLaneType(outEdge->getPermissions(c.toLane)) << "\" level=\"0\">\n";
218  device << " <link>\n";
219  device << " <predecessor id=\"-" << inEdge->getNumLanes() - c.fromLane << "\"/>\n";
220  device << " <successor id=\"-" << outEdge->getNumLanes() - c.toLane << "\"/>\n";
221  device << " </link>\n";
222  device << " <width sOffset=\"0\" a=\"" << width << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
223  device << " <roadMark sOffset=\"0\" type=\"none\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
224  device << " </lane>\n";
225  device << " </right>\n";
226  device << " </laneSection>\n";
227  device << " </lanes>\n";
228  device << " <objects/>\n";
229  device << " <signals/>\n";
230  device << " </road>\n";
231  }
232  }
233  }
234 
235  // write junctions (junction)
236  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
237  NBNode* n = (*i).second;
238  device << " <junction name=\"" << n->getID() << "\" id=\"" << getID(n->getID(), nodeMap, nodeID) << "\">\n";
239  int index = 0;
240  const std::vector<NBEdge*>& incoming = n->getIncomingEdges();
241  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
242  const NBEdge* inEdge = *j;
243  const std::vector<NBEdge::Connection>& elv = inEdge->getConnections();
244  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
245  const NBEdge::Connection& c = *k;
246  const NBEdge* outEdge = c.toEdge;
247  if (outEdge == 0) {
248  continue;
249  }
250  device << " <connection id=\""
251  << index << "\" incomingRoad=\"" << getID(inEdge->getID(), edgeMap, edgeID)
252  << "\" connectingRoad=\""
253  << getID(c.getInternalLaneID(), edgeMap, edgeID)
254  << "\" contactPoint=\"start\">\n";
255  device << " <laneLink from=\"-" << inEdge->getNumLanes() - c.fromLane
256  << "\" to=\"-1" // every connection has its own edge
257  << "\"/>\n";
258  device << " </connection>\n";
259  ++index;
260  }
261  }
262  device << " </junction>\n";
263  }
264 
265  device.closeTag();
266  device.close();
267 }
268 
269 
270 SUMOReal
271 NWWriter_OpenDrive::writeGeomLines(const PositionVector& shape, OutputDevice& device, OutputDevice& elevationDevice, SUMOReal offset) {
272  for (int j = 0; j < (int)shape.size() - 1; ++j) {
273  const Position& p = shape[j];
274  const Position& p2 = shape[j + 1];
275  const SUMOReal hdg = shape.angleAt2D(j);
276  const SUMOReal length = p.distanceTo2D(p2);
277  device << " <geometry s=\"" << offset << "\" x=\"" << p.x() << "\" y=\"" << p.y() << "\" hdg=\"" << hdg << "\" length=\"" << length << "\"><line/></geometry>\n";
278  elevationDevice << " <elevation s=\"" << offset << "\" a=\"" << p.z() << "\" b=\"" << (p2.z() - p.z()) / length << "\" c=\"0\" d=\"0\"/>\n";
279  offset += length;
280  }
281  return offset;
282 }
283 
284 
285 void
286 NWWriter_OpenDrive::writeEmptyCenterLane(OutputDevice& device, const std::string& mark, SUMOReal markWidth) {
287  device << " <center>\n";
288  device << " <lane id=\"0\" type=\"none\" level= \"0\">\n";
289  device << " <link/>\n";
290  device << " <roadMark sOffset=\"0\" type=\"" << mark << "\" weight=\"standard\" color=\"standard\" width=\"" << markWidth << "\"/>\n";
291  device << " <width sOffset=\"0\" a=\"0\" b=\"0\" c=\"0\" d=\"0\"/>\n";
292  device << " </lane>\n";
293  device << " </center>\n";
294 }
295 
296 
297 int
298 NWWriter_OpenDrive::getID(const std::string& origID, StringBijection<int>& map, int& lastID) {
299  if (map.hasString(origID)) {
300  return map.get(origID);
301  }
302  map.insert(origID, lastID++);
303  return lastID - 1;
304 }
305 
306 
307 std::string
309  switch (permissions) {
310  case SVC_PEDESTRIAN:
311  return "sidewalk";
312  //case (SVC_BICYCLE | SVC_PEDESTRIAN):
313  // WRITE_WARNING("Ambiguous lane type (biking+driving) for road '" + roadID + "'");
314  // return "sidewalk";
315  case SVC_BICYCLE:
316  return "biking";
317  case 0:
318  // ambiguous
319  return "none";
320  case SVC_RAIL:
321  case SVC_RAIL_URBAN:
322  case SVC_RAIL_ELECTRIC:
323  return "rail";
324  case SVC_TRAM:
325  return "tram";
326  default: {
327  // complex permissions
328  if (permissions == SVCAll) {
329  return "driving";
330  } else if (isRailway(permissions)) {
331  return "rail";
332  } else if ((permissions & SVC_PASSENGER) != 0) {
333  return "driving";
334  } else {
335  return "restricted";
336  }
337  }
338  }
339 }
340 
341 
343 NWWriter_OpenDrive::getLeftLaneBorder(const NBEdge* edge, int laneIndex) {
344  if (laneIndex == -1) {
345  // leftmost lane
346  laneIndex = (int)edge->getNumLanes() - 1;
347  }
348  const int leftmost = (int)edge->getNumLanes() - 1;
349  SUMOReal widthOffset = -(edge->getLaneWidth(leftmost) / 2);
350 
351  // collect lane widths from left border of edge to left border of lane to connect to
352  for (int i = leftmost; i > laneIndex; i--) {
353  widthOffset += edge->getLaneWidth(i);
354  }
355 
356  PositionVector result = edge->getLaneShape(leftmost);
357  try {
358  result.move2side(widthOffset);
359  } catch (InvalidArgument&) { }
360  return result;
361 }
362 
363 
364 SUMOReal
366  OutputDevice& device,
367  OutputDevice& elevationDevice,
368  PositionVector init,
369  SUMOReal length,
370  SUMOReal offset) {
371  assert(init.size() == 3 || init.size() == 4);
372 
373  const Position p = init.front();
374  const SUMOReal hdg = init.angleAt2D(0);
375  // translate to u,v coordinates
376  init.add(-p.x(), -p.y(), -p.z());
377  init.rotate2D(-hdg);
378 
379  // parametric coefficients
380  SUMOReal aU, bU, cU, dU;
381  SUMOReal aV, bV, cV, dV;
382  SUMOReal aZ, bZ, cZ, dZ;
383 
384  // unfactor the Bernstein polynomials of degree 2 (or 3) and collect the coefficients
385  if (init.size() == 3) {
386  //f(x, a, b ,c) = a + (2*b - 2*a)*x + (a - 2*b + c)*x*x
387  aU = init[0].x();
388  bU = 2 * init[1].x() - 2 * init[0].x();
389  cU = init[0].x() - 2 * init[1].x() + init[2].x();
390  dU = 0;
391 
392  aV = init[0].y();
393  bV = 2 * init[1].y() - 2 * init[0].y();
394  cV = init[0].y() - 2 * init[1].y() + init[2].y();
395  dV = 0;
396 
397  // elevation is not parameteric on [0:1] but on [0:length]
398  aZ = init[0].z();
399  bZ = (2 * init[1].z() - 2 * init[0].z()) / length;
400  cZ = (init[0].z() - 2 * init[1].z() + init[2].z()) / (length * length);
401  dZ = 0;
402 
403  } else {
404  // 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))
405  aU = init[0].x();
406  bU = 3 * init[1].x() - 3 * init[0].x();
407  cU = 3 * init[0].x() - 6 * init[1].x() + 3 * init[2].x();
408  dU = -init[0].x() + 3 * init[1].x() - 3 * init[2].x() + init[3].x();
409 
410  aV = init[0].y();
411  bV = 3 * init[1].y() - 3 * init[0].y();
412  cV = 3 * init[0].y() - 6 * init[1].y() + 3 * init[2].y();
413  dV = -init[0].y() + 3 * init[1].y() - 3 * init[2].y() + init[3].y();
414 
415  // elevation is not parameteric on [0:1] but on [0:length]
416  aZ = init[0].z();
417  bZ = (3 * init[1].z() - 3 * init[0].z()) / length;
418  cZ = (3 * init[0].z() - 6 * init[1].z() + 3 * init[2].z()) / (length * length);
419  dZ = (-init[0].z() + 3 * init[1].z() - 3 * init[2].z() + init[3].z()) / (length * length * length);
420  }
421 
422  device.openTag("geometry");
423  device.writeAttr("s", offset);
424  device.writeAttr("x", p.x());
425  device.writeAttr("y", p.y());
426  device.writeAttr("hdg", hdg);
427  device.writeAttr("length", length);
428 
429  device.openTag("paramPoly3");
430  device.writeAttr("aU", aU);
431  device.writeAttr("bU", bU);
432  device.writeAttr("cU", cU);
433  device.writeAttr("dU", dU);
434  device.writeAttr("aV", aV);
435  device.writeAttr("bV", bV);
436  device.writeAttr("cV", cV);
437  device.writeAttr("dV", dV);
438  device.closeTag();
439  device.closeTag();
440 
441  // write elevation
442  elevationDevice.openTag("elevation");
443  elevationDevice.writeAttr("s", offset);
444  elevationDevice.writeAttr("a", aZ);
445  elevationDevice.writeAttr("b", bZ);
446  elevationDevice.writeAttr("c", cZ);
447  elevationDevice.writeAttr("d", dZ);
448  elevationDevice.closeTag();
449 
450  return offset + length;
451 }
452 
453 
454 void
456 #ifdef DEBUG_SMOOTH_GEOM
457  if (DEBUGCOND) {
458  std::cout << "writeGeomSmooth\n n=" << shape.size() << " shape=" << toString(shape) << "\n";
459  }
460 #endif
461  const SUMOReal angleThresh = DEG2RAD(5); // changes below thresh are considered to be straight (make configurable)
462  const SUMOReal longThresh = speed; // 16.0; // make user-configurable (should match the sampling rate of the source data)
463  const SUMOReal curveCutout = longThresh / 2; // 8.0; // make user-configurable (related to the maximum turning rate)
464  // 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')
465  assert(longThresh >= 2 * curveCutout);
466  assert(shape.size() > 2);
467  // add intermediate points wherever there is a strong angular change between long segments
468  // assume the geometry is simplified so as not to contain consecutive colinear points
469  PositionVector shape2 = shape;
470  SUMOReal maxAngleDiff = 0;
471  SUMOReal offset = 0;
472  for (int j = 1; j < (int)shape.size() - 1; ++j) {
473  //const SUMOReal hdg = shape.angleAt2D(j);
474  const Position& p0 = shape[j - 1];
475  const Position& p1 = shape[j];
476  const Position& p2 = shape[j + 1];
477  const SUMOReal dAngle = fabs(GeomHelper::angleDiff(p0.angleTo2D(p1), p1.angleTo2D(p2)));
478  const SUMOReal length1 = p0.distanceTo2D(p1);
479  const SUMOReal length2 = p1.distanceTo2D(p2);
480  maxAngleDiff = MAX2(maxAngleDiff, dAngle);
481 #ifdef DEBUG_SMOOTH_GEOM
482  if (DEBUGCOND) {
483  std::cout << " j=" << j << " dAngle=" << RAD2DEG(dAngle) << " length1=" << length1 << " length2=" << length2 << "\n";
484  }
485 #endif
486  if (dAngle > angleThresh
487  && (length1 > longThresh || j == 1)
488  && (length2 > longThresh || j == (int)shape.size() - 2)) {
489  shape2.insertAtClosest(shape.positionAtOffset2D(offset + length1 - MIN2(length1 - POSITION_EPS, curveCutout)));
490  shape2.insertAtClosest(shape.positionAtOffset2D(offset + length1 + MIN2(length2 - POSITION_EPS, curveCutout)));
491  shape2.removeClosest(p1);
492  }
493  offset += length1;
494  }
495  const int numPoints = (int)shape2.size();
496 #ifdef DEBUG_SMOOTH_GEOM
497  if (DEBUGCOND) {
498  std::cout << " n=" << numPoints << " shape2=" << toString(shape2) << "\n";
499  }
500 #endif
501 
502  if (maxAngleDiff < angleThresh) {
503  writeGeomLines(shape2, device, elevationDevice, 0);
504 #ifdef DEBUG_SMOOTH_GEOM
505  if (DEBUGCOND) {
506  std::cout << " special case: all lines. maxAngleDiff=" << maxAngleDiff << "\n";
507  }
508 #endif
509  return;
510  }
511 
512  // write the long segments as lines, short segments as curves
513  offset = 0;
514  for (int j = 0; j < numPoints - 1; ++j) {
515  const Position& p0 = shape2[j];
516  const Position& p1 = shape2[j + 1];
517  PositionVector line;
518  line.push_back(p0);
519  line.push_back(p1);
520  const SUMOReal lineLength = line.length2D();
521  if (lineLength >= longThresh) {
522  offset = writeGeomLines(line, device, elevationDevice, offset);
523 #ifdef DEBUG_SMOOTH_GEOM
524  if (DEBUGCOND) {
525  std::cout << " writeLine=" << toString(line) << "\n";
526  }
527 #endif
528  } else {
529  // find control points
530  PositionVector begShape;
531  PositionVector endShape;
532  if (j == 0) {
533  // keep the angle of the first segment but end at the front of the shape
534  begShape = line;
535  begShape.add(p0 - begShape.back());
536  } else if (j == 1 || p0.distanceTo2D(shape2[j - 1]) > longThresh) {
537  // use the previous segment if it is long or the first one
538  begShape.push_back(shape2[j - 1]);
539  begShape.push_back(p0);
540  } else {
541  // end at p0 with mean angle of the previous and current segment
542  begShape.push_back(shape2[j - 1]);
543  begShape.push_back(p1);
544  begShape.add(p0 - begShape.back());
545  }
546  if (j == numPoints - 2) {
547  // keep the angle of the last segment but start at the end of the shape
548  endShape = line;
549  endShape.add(p1 - endShape.front());
550  } else if (j == numPoints - 3 || p1.distanceTo2D(shape2[j + 2]) > longThresh) {
551  // use the next segment if it is long or the final one
552  endShape.push_back(p1);
553  endShape.push_back(shape2[j + 2]);
554  } else {
555  // start at p1 with mean angle of the current and next segment
556  endShape.push_back(p0);
557  endShape.push_back(shape2[j + 2]);
558  endShape.add(p1 - endShape.front());
559  }
560 
561  PositionVector init = NBNode::bezierControlPoints(begShape, endShape, false, 25, 25);
562  if (init.size() == 0) {
563  // could not compute control points, write line
564  offset = writeGeomLines(line, device, elevationDevice, offset);
565 #ifdef DEBUG_SMOOTH_GEOM
566  if (DEBUGCOND) {
567  std::cout << " writeLine lineLength=" << lineLength << " begShape=" << toString(begShape) << " endShape=" << toString(endShape) << " init=" << toString(init) << "\n";
568  }
569 #endif
570  } else {
571  // write bezier
572  const SUMOReal curveLength = bezier(init, 12).length2D();
573  offset = writeGeomPP3(device, elevationDevice, init, curveLength, offset);
574 #ifdef DEBUG_SMOOTH_GEOM
575  if (DEBUGCOND) {
576  std::cout << " writeCurve lineLength=" << lineLength << " curveLength=" << curveLength << " begShape=" << toString(begShape) << " endShape=" << toString(endShape) << " init=" << toString(init) << "\n";
577  }
578 #endif
579  }
580  }
581  }
582 }
583 
584 
585 void
587  // check if the shape is flat
588  bool flat = true;
589  SUMOReal z = shape.size() == 0 ? 0 : shape[0].z();
590  for (int i = 1; i < (int)shape.size(); ++i) {
591  if (fabs(shape[i].z() - z) > NUMERICAL_EPS) {
592  flat = false;
593  break;
594  }
595  }
596  device << " <elevationProfile>\n";
597  if (flat) {
598  device << " <elevation s=\"0\" a=\"" << z << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
599  } else {
600  device << elevationDevice.getString();
601  }
602  device << " </elevationProfile>\n";
603 
604 }
605 
606 
607 /****************************************************************************/
608 
static SUMOReal writeGeomLines(const PositionVector &shape, OutputDevice &device, OutputDevice &elevationDevice, SUMOReal offset=0)
write geometry as sequence of lines (sumo style)
#define DEBUGCOND
static SUMOReal writeGeomPP3(OutputDevice &device, OutputDevice &elevationDevice, PositionVector init, SUMOReal length, SUMOReal offset=0)
write geometry as a single bezier curve (paramPoly3)
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:257
const EdgeVector & getIncomingEdges() const
Returns this node&#39;s incoming edges.
Definition: NBNode.h:240
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:150
int toLane
The lane the connections yields in.
Definition: NBEdge.h:168
std::string getString() const
Returns the current content as a string.
is a pedestrian
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:166
int size() const
Returns the number of edges.
Definition: NBEdgeCont.h:282
bool hasString(const std::string &str) const
vehicle is a not electrified rail
SUMOReal ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:124
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition: NBEdge.h:522
vehicle is a bicycle
int SVCPermissions
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
The representation of a single edge during network building.
Definition: NBEdge.h:70
static std::string escapeXML(const std::string &orig)
Replaces the standard escapes by their XML entities.
SUMOReal xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:112
static void writeGeomSmooth(const PositionVector &shape, SUMOReal speed, OutputDevice &device, OutputDevice &elevationDevice)
write geometry as sequence of lines and bezier curves
void setPrecision(int precision=OUTPUT_ACCURACY)
Sets the precison or resets it to default.
vehicle is a light rail
T MAX2(T a, T b)
Definition: StdDefs.h:75
SUMOReal getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:469
#define RAD2DEG(x)
Definition: GeomHelper.h:46
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
const SVCPermissions SVCAll
static SUMOReal angleDiff(const SUMOReal angle1, const SUMOReal angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:178
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
Position positionAtOffset2D(SUMOReal pos, SUMOReal lateralOffset=0) const
Returns the position at the given length.
SUMOReal xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:118
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
vehicle is a (possibly fast moving) electric rail
vehicle is a city rail
#define OUTPUT_ACCURACY
Definition: config.h:163
void rotate2D(SUMOReal angle)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
const std::string & getID() const
Returns the id.
Definition: Named.h:66
SUMOReal length2D() const
Returns the length.
void insert(const std::string str, const T key, bool checkDuplicates=true)
static void writeNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Writes the network into a openDRIVE-file.
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:198
std::string getInternalLaneID() const
Definition: NBEdge.cpp:80
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:164
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Returns the edge container.
Definition: NBNetBuilder.h:153
A list of positions.
void add(SUMOReal xoff, SUMOReal yoff, SUMOReal zoff)
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:347
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2038
static void writeEmptyCenterLane(OutputDevice &device, const std::string &mark, SUMOReal markWidth)
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
T MIN2(T a, T b)
Definition: StdDefs.h:69
void bezier(int npts, SUMOReal b[], int cpts, SUMOReal p[])
Definition: bezier.cpp:101
#define POSITION_EPS
Definition: config.h:187
std::map< std::string, NBNode * >::const_iterator end() const
Returns the pointer to the end of the stored nodes.
Definition: NBNodeCont.h:134
#define DEG2RAD(x)
Definition: GeomHelper.h:45
const Boundary & getConvBoundary() const
Returns the converted boundary.
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:55
vehicle is a passenger car (a "normal" car)
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:190
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:2575
static std::string getLaneType(SVCPermissions permissions)
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:371
SUMOReal angleAt2D(int pos) const
get angle in certain position of position vector
NBNodeCont & getNodeCont()
Returns the node container.
Definition: NBNetBuilder.h:161
Instance responsible for building networks.
Definition: NBNetBuilder.h:112
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
A storage for options typed value containers)
Definition: OptionsCont.h:99
static PositionVector getLeftLaneBorder(const NBEdge *edge, int laneIndex=-1)
get the left border of the given lane (the leftmost one by default)
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
Represents a single node (junction) during network building.
Definition: NBNode.h:74
T get(const std::string &str) const
SUMOReal distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:232
void move2side(SUMOReal amount)
move position vector to side using certain ammount
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
bool closeTag()
Closes the most recently opened tag.
#define SUMOReal
Definition: config.h:213
SUMOReal ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:130
int size() const
Returns the number of known nodes.
Definition: NBNodeCont.h:271
#define NUMERICAL_EPS
Definition: config.h:160
static PositionVector bezierControlPoints(const PositionVector &begShape, const PositionVector &endShape, bool isTurnaround, SUMOReal extrapolateBeg, SUMOReal extrapolateEnd)
Definition: NBNode.cpp:496
SUMOReal getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:451
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
static int getID(const std::string &origID, StringBijection< int > &map, int &lastID)
const std::string & getStreetName() const
Returns the street name of this edge.
Definition: NBEdge.h:485
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:786
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:126
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:554
static void writeElevationProfile(const PositionVector &shape, OutputDevice &device, const OutputDevice_String &elevationDevice)
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
SUMOReal angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:243
An output device that encapsulates an ofstream.
SUMOReal getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:424
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:363