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-2015 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"
35 #include <netbuild/NBEdge.h>
36 #include <netbuild/NBEdgeCont.h>
37 #include <netbuild/NBNode.h>
38 #include <netbuild/NBNodeCont.h>
39 #include <netbuild/NBNetBuilder.h>
43 #include <utils/common/StdDefs.h>
46 
47 #ifdef CHECK_MEMORY_LEAKS
48 #include <foreign/nvwa/debug_new.h>
49 #endif // CHECK_MEMORY_LEAKS
50 
51 #define MIN_TURN_DIAMETER 2.0
52 
53 
54 // ===========================================================================
55 // method definitions
56 // ===========================================================================
57 // ---------------------------------------------------------------------------
58 // static methods
59 // ---------------------------------------------------------------------------
60 void
62  // check whether an opendrive-file shall be generated
63  if (!oc.isSet("opendrive-output")) {
64  return;
65  }
66  const bool origNames = oc.getBool("output.original-names");
67  // some internal mapping containers
68  int edgeID = 1;
69  int nodeID = 1;
70  StringBijection<int> edgeMap;
71  StringBijection<int> nodeMap;
72  //
73  OutputDevice& device = OutputDevice::getDevice(oc.getString("opendrive-output"));
74  device << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
75  device.openTag("OpenDRIVE");
76  time_t now = time(0);
77  std::string dstr(ctime(&now));
78  const NBNodeCont& nc = nb.getNodeCont();
79  const NBEdgeCont& ec = nb.getEdgeCont();
81  // write header
82  device.openTag("header");
83  device.writeAttr("revMajor", "1");
84  device.writeAttr("revMinor", "3");
85  device.writeAttr("name", "");
86  device.writeAttr("version", "1.00");
87  device.writeAttr("date", dstr.substr(0, dstr.length() - 1));
88  device.writeAttr("north", b.ymax());
89  device.writeAttr("south", b.ymin());
90  device.writeAttr("east", b.xmax());
91  device.writeAttr("west", b.xmin());
92  device.writeAttr("maxRoad", ec.size());
93  device.writeAttr("maxJunc", nc.size());
94  device.writeAttr("maxPrg", 0);
95  device.closeTag();
96 
97  // write normal edges (road)
98  for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
99  const NBEdge* e = (*i).second;
100  device << " <road name=\"" << StringUtils::escapeXML(e->getStreetName()) << "\" length=\"" << e->getLength() << "\" id=\"" << getID(e->getID(), edgeMap, edgeID) << "\" junction=\"-1\">\n";
101  device << " <link>\n";
102  device << " <predecessor elementType=\"junction\" elementId=\"" << getID(e->getFromNode()->getID(), nodeMap, nodeID) << "\"/>\n";
103  device << " <successor elementType=\"junction\" elementId=\"" << getID(e->getToNode()->getID(), nodeMap, nodeID) << "\"/>\n";
104  device << " </link>\n";
105  device << " <type s=\"0\" type=\"town\"/>\n";
106  // for the shape we need to use the leftmost border of the leftmost lane
107  const std::vector<NBEdge::Lane>& lanes = e->getLanes();
109  writePlanView(ls, device);
110  device << " <elevationProfile><elevation s=\"0\" a=\"0\" b=\"0\" c=\"0\" d=\"0\"/></elevationProfile>\n";
111  device << " <lateralProfile/>\n";
112  device << " <lanes>\n";
113  device << " <laneSection s=\"0\">\n";
114  writeEmptyCenterLane(device, "solid", 0.13);
115  device << " <right>\n";
116  for (int j = e->getNumLanes(); --j >= 0;) {
117  device << " <lane id=\"-" << e->getNumLanes() - j << "\" type=\"" << getLaneType(e->getPermissions(j)) << "\" level=\"0\">\n";
118  device << " <link/>\n";
119  // this could be used for geometry-link junctions without u-turn,
120  // predecessor and sucessors would be lane indices,
121  // road predecessor / succesfors would be of type 'road' rather than
122  // 'junction'
123  //device << " <predecessor id=\"-1\"/>\n";
124  //device << " <successor id=\"-1\"/>\n";
125  //device << " </link>\n";
126  device << " <width sOffset=\"0\" a=\"" << e->getLaneWidth(j) << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
127  std::string markType = "broken";
128  if (j == 0) {
129  markType = "solid";
130  }
131  device << " <roadMark sOffset=\"0\" type=\"" << markType << "\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
132  device << " <speed sOffset=\"0\" max=\"" << lanes[j].speed << "\"/>\n";
133  device << " </lane>\n";
134  }
135  device << " </right>\n";
136  device << " </laneSection>\n";
137  device << " </lanes>\n";
138  device << " <objects/>\n";
139  device << " <signals/>\n";
140  if (origNames) {
141  device << " <userData sumoId=\"" << e->getID() << "\"/>\n";
142  }
143  device << " </road>\n";
144  }
145  device << "\n";
146  // write junction-internal edges (road)
147  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
148  NBNode* n = (*i).second;
149  const std::vector<NBEdge*>& incoming = (*i).second->getIncomingEdges();
150  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
151  const NBEdge* inEdge = *j;
152  const std::vector<NBEdge::Connection>& elv = inEdge->getConnections();
153  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
154  const NBEdge::Connection& c = *k;
155  const NBEdge* outEdge = c.toEdge;
156  if (outEdge == 0) {
157  continue;
158  }
159  PositionVector shape = c.shape;
160  if (c.haveVia) {
161  shape.append(c.viaShape);
162  }
163  const SUMOReal width = c.toEdge->getLaneWidth(c.toLane);
164  // @todo: this if-clause is a hack which assures that the code also works with connections of zero length, what may be possible
165  // probably, it would make sense to mark such connections and connect the incoming/outgoing streets directly in such cases.
166  if (shape.length() > POSITION_EPS) {
167  try {
168  shape.move2side(-width / 2.);
169  } catch (InvalidArgument&) {
170  shape.clear();
171  }
172  } else {
173  shape.clear();
174  }
175  if (inEdge->isTurningDirectionAt(outEdge)
176  && getLeftBorder(inEdge).back().distanceTo2D(getLeftBorder(outEdge).front()) < MIN_TURN_DIAMETER) {
177  shape.clear(); // simplified geometry for sharp turn-arounds
178  }
179  // we need to fix start and endpoints in case the start and
180  // end segments were not in line with the incoming and outgoing lanes
181  if (shape.size() > 1) {
182  shape[0] = getLeftBorder(inEdge).back();
183  shape[-1] = getLeftBorder(outEdge).front();
184  } else {
185  shape.clear();
186  shape.push_back(getLeftBorder(inEdge).back());
187  shape.push_back(getLeftBorder(outEdge).front());
188  }
189 
190  device << " <road name=\"" << c.getInternalLaneID() << "\" length=\"" << shape.length() << "\" id=\"" << getID(c.getInternalLaneID(), edgeMap, edgeID) << "\" junction=\"" << getID(n->getID(), nodeMap, nodeID) << "\">\n";
191  device << " <link>\n";
192  device << " <predecessor elementType=\"road\" elementId=\"" << getID(inEdge->getID(), edgeMap, edgeID) << "\"/>\n";
193  device << " <successor elementType=\"road\" elementId=\"" << getID(outEdge->getID(), edgeMap, edgeID) << "\"/>\n";
194  device << " </link>\n";
195  device << " <type s=\"0\" type=\"town\"/>\n";
196  writePlanView(shape, device);
197  device << " <elevationProfile><elevation s=\"0\" a=\"0\" b=\"0\" c=\"0\" d=\"0\"/></elevationProfile>\n";
198  device << " <lateralProfile/>\n";
199  device << " <lanes>\n";
200  device << " <laneSection s=\"0\">\n";
201  writeEmptyCenterLane(device, "none", 0);
202  device << " <right>\n";
203  device << " <lane id=\"-1\" type=\"" << getLaneType(outEdge->getPermissions(c.toLane)) << "\" level=\"0\">\n";
204  device << " <link>\n";
205  device << " <predecessor id=\"-" << inEdge->getNumLanes() - c.fromLane << "\"/>\n";
206  device << " <successor id=\"-" << outEdge->getNumLanes() - c.toLane << "\"/>\n";
207  device << " </link>\n";
208  device << " <width sOffset=\"0\" a=\"" << width << "\" b=\"0\" c=\"0\" d=\"0\"/>\n";
209  device << " <roadMark sOffset=\"0\" type=\"none\" weight=\"standard\" color=\"standard\" width=\"0.13\"/>\n";
210  device << " </lane>\n";
211  device << " </right>\n";
212  device << " </laneSection>\n";
213  device << " </lanes>\n";
214  device << " <objects/>\n";
215  device << " <signals/>\n";
216  device << " </road>\n";
217  }
218  }
219  }
220 
221  // write junctions (junction)
222  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
223  NBNode* n = (*i).second;
224  device << " <junction name=\"" << n->getID() << "\" id=\"" << getID(n->getID(), nodeMap, nodeID) << "\">\n";
225  unsigned int index = 0;
226  const std::vector<NBEdge*>& incoming = n->getIncomingEdges();
227  for (std::vector<NBEdge*>::const_iterator j = incoming.begin(); j != incoming.end(); ++j) {
228  const NBEdge* inEdge = *j;
229  const std::vector<NBEdge::Connection>& elv = inEdge->getConnections();
230  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
231  const NBEdge::Connection& c = *k;
232  const NBEdge* outEdge = c.toEdge;
233  if (outEdge == 0) {
234  continue;
235  }
236  device << " <connection id=\""
237  << index << "\" incomingRoad=\"" << getID(inEdge->getID(), edgeMap, edgeID)
238  << "\" connectingRoad=\""
239  << getID(c.getInternalLaneID(), edgeMap, edgeID)
240  << "\" contactPoint=\"start\">\n";
241  device << " <laneLink from=\"-" << inEdge->getNumLanes() - c.fromLane
242  << "\" to=\"-1" // every connection has its own edge
243  << "\"/>\n";
244  device << " </connection>\n";
245  ++index;
246  }
247  }
248  device << " </junction>\n";
249  }
250 
251  device.closeTag();
252  device.close();
253 }
254 
255 
256 void
258  device << " <planView>\n";
259  SUMOReal offset = 0;
260  for (unsigned int j = 0; j < shape.size() - 1; ++j) {
261  const Position& p = shape[j];
262  const SUMOReal hdg = shape.angleAt2D(j);
263  const SUMOReal length = p.distanceTo(shape[j + 1]);
264  device << std::setprecision(8); // hdg requires higher precision
265  device << " <geometry s=\"" << offset << "\" x=\"" << p.x() << "\" y=\"" << p.y() << "\" hdg=\"" << hdg << "\" length=\"" << length << "\"><line/></geometry>\n";
266  device << std::setprecision(OUTPUT_ACCURACY);
267  offset += length;
268  }
269  device << " </planView>\n";
270 }
271 
272 
273 void
274 NWWriter_OpenDrive::writeEmptyCenterLane(OutputDevice& device, const std::string& mark, SUMOReal markWidth) {
275  device << " <center>\n";
276  device << " <lane id=\"0\" type=\"none\" level= \"0\">\n";
277  device << " <link/>\n";
278  device << " <roadMark sOffset=\"0\" type=\"" << mark << "\" weight=\"standard\" color=\"standard\" width=\"" << markWidth << "\"/>\n";
279  device << " <width sOffset=\"0\" a=\"0\" b=\"0\" c=\"0\" d=\"0\"/>\n";
280  device << " </lane>\n";
281  device << " </center>\n";
282 }
283 
284 
285 int
286 NWWriter_OpenDrive::getID(const std::string& origID, StringBijection<int>& map, int& lastID) {
287  if (map.hasString(origID)) {
288  return map.get(origID);
289  }
290  map.insert(origID, lastID++);
291  return lastID - 1;
292 }
293 
294 
295 std::string
297  switch (permissions) {
298  case SVC_PEDESTRIAN:
299  return "sidewalk";
300  //case (SVC_BICYCLE | SVC_PEDESTRIAN):
301  // WRITE_WARNING("Ambiguous lane type (biking+driving) for road '" + roadID + "'");
302  // return "sidewalk";
303  case SVC_BICYCLE:
304  return "biking";
305  case 0:
306  // ambiguous
307  return "none";
308  case SVC_TRAM:
309  return "tram";
310  default:
311  return "driving";
312  }
313 }
314 
315 
318  const int leftmost = (int)edge->getNumLanes() - 1;
319  PositionVector result = edge->getLaneShape(leftmost);
320  try {
321  result.move2side(-edge->getLaneWidth(leftmost) / 2);
322  } catch (InvalidArgument&) { }
323  return result;
324 }
325 /****************************************************************************/
326 
static void writePlanView(const PositionVector &shape, OutputDevice &device)
const PositionVector & getLaneShape(unsigned int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:532
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:148
int toLane
The lane the connections yields in.
Definition: NBEdge.h:166
is a pedestrian
NBEdge * toEdge
The edge the connections yields in.
Definition: NBEdge.h:164
bool hasString(const std::string &str) const
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:500
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
vehicle is a light rail
SUMOReal getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:447
SUMOReal distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:221
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
SUMOReal xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:118
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
#define OUTPUT_ACCURACY
Definition: config.h:164
PositionVector shape
Definition: NBEdge.h:182
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:65
void insert(const std::string str, const T key, bool checkDuplicates=true)
unsigned int size() const
Returns the number of known nodes.
Definition: NBNodeCont.h:273
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:79
int fromLane
The lane the connections starts at.
Definition: NBEdge.h:162
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Returns the edge container.
Definition: NBNetBuilder.h:154
A list of positions.
unsigned int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:345
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:1834
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
#define POSITION_EPS
Definition: config.h:188
std::map< std::string, NBNode * >::const_iterator end() const
Returns the pointer to the end of the stored nodes.
Definition: NBNodeCont.h:135
const Boundary & getConvBoundary() const
Returns the converted boundary.
static PositionVector getLeftBorder(const NBEdge *edge)
get the left border of the leftmost lane
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:2362
SUMOReal length() const
Returns the length.
static std::string getLaneType(SVCPermissions permissions)
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:369
PositionVector viaShape
Definition: NBEdge.h:188
SUMOReal angleAt2D(int pos) const
NBNodeCont & getNodeCont()
Returns the node container.
Definition: NBNetBuilder.h:162
Instance responsible for building networks.
Definition: NBNetBuilder.h:113
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:108
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
#define MIN_TURN_DIAMETER
Represents a single node (junction) during network building.
Definition: NBNode.h:74
T get(const std::string &str) const
void move2side(SUMOReal amount)
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
#define SUMOReal
Definition: config.h:214
SUMOReal ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:130
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:64
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:463
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:761
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:127
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
void append(const PositionVector &v, SUMOReal sameThreshold=2.0)
unsigned int size() const
Returns the number of edges.
Definition: NBEdgeCont.h:282
SUMOReal getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:404
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:361