SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NWWriter_SUMO.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Exporter writing networks using the SUMO format
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
12 // Copyright (C) 2001-2013 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 #include <cmath>
33 #include <algorithm>
37 #include <utils/common/ToString.h>
40 #include <netbuild/NBEdge.h>
41 #include <netbuild/NBEdgeCont.h>
42 #include <netbuild/NBNode.h>
43 #include <netbuild/NBNodeCont.h>
44 #include <netbuild/NBNetBuilder.h>
46 #include <netbuild/NBDistrict.h>
47 #include "NWFrame.h"
48 #include "NWWriter_SUMO.h"
49 
50 #ifdef CHECK_MEMORY_LEAKS
51 #include <foreign/nvwa/debug_new.h>
52 #endif // CHECK_MEMORY_LEAKS
53 
54 
55 
56 // ===========================================================================
57 // method definitions
58 // ===========================================================================
59 // ---------------------------------------------------------------------------
60 // static methods
61 // ---------------------------------------------------------------------------
62 void
64  // check whether a sumo net-file shall be generated
65  if (!oc.isSet("output-file")) {
66  return;
67  }
68  OutputDevice& device = OutputDevice::getDevice(oc.getString("output-file"));
69  device.writeXMLHeader("net", NWFrame::MAJOR_VERSION + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo.sf.net/xsd/net_file.xsd\""); // street names may contain non-ascii chars
70  device.lf();
71  // get involved container
72  const NBNodeCont& nc = nb.getNodeCont();
73  const NBEdgeCont& ec = nb.getEdgeCont();
74  const NBDistrictCont& dc = nb.getDistrictCont();
75 
76  // write network offsets and projection
77  writeLocation(device);
78 
79  // write inner lanes
80  bool origNames = oc.getBool("output.original-names");
81  if (!oc.getBool("no-internal-links")) {
82  bool hadAny = false;
83  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
84  hadAny |= writeInternalEdges(device, *(*i).second, origNames);
85  }
86  if (hadAny) {
87  device.lf();
88  }
89  }
90 
91  // write edges with lanes and connected edges
92  bool noNames = !oc.getBool("output.street-names");
93  for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
94  writeEdge(device, *(*i).second, noNames, origNames);
95  }
96  device.lf();
97 
98  // write tls logics
99  writeTrafficLights(device, nb.getTLLogicCont());
100 
101  // write the nodes (junctions)
102  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
103  writeJunction(device, *(*i).second);
104  }
105  device.lf();
106  const bool includeInternal = !oc.getBool("no-internal-links");
107  if (includeInternal) {
108  // ... internal nodes if not unwanted
109  bool hadAny = false;
110  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
111  hadAny |= writeInternalNodes(device, *(*i).second);
112  }
113  if (hadAny) {
114  device.lf();
115  }
116  }
117 
118  // write the successors of lanes
119  unsigned int numConnections = 0;
120  for (std::map<std::string, NBEdge*>::const_iterator it_edge = ec.begin(); it_edge != ec.end(); it_edge++) {
121  NBEdge* from = it_edge->second;
123  const std::vector<NBEdge::Connection> connections = from->getConnections();
124  numConnections += (unsigned int)connections.size();
125  for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) {
126  writeConnection(device, *from, *it_c, includeInternal);
127  }
128  }
129  if (numConnections > 0) {
130  device.lf();
131  }
132  if (includeInternal) {
133  // ... internal successors if not unwanted
134  bool hadAny = false;
135  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
136  hadAny |= writeInternalConnections(device, *(*i).second);
137  }
138  if (hadAny) {
139  device.lf();
140  }
141  }
142  // write loaded prohibitions
143  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
144  writeProhibitions(device, i->second->getProhibitions());
145  }
146 
147  // write roundabout information
148  const std::vector<EdgeVector>& roundabouts = nb.getRoundabouts();
149  for (std::vector<EdgeVector>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
150  writeRoundabout(device, *i);
151  }
152  if (roundabouts.size() != 0) {
153  device.lf();
154  }
155 
156  // write the districts
157  for (std::map<std::string, NBDistrict*>::const_iterator i = dc.begin(); i != dc.end(); i++) {
158  writeDistrict(device, *(*i).second);
159  }
160  if (dc.size() != 0) {
161  device.lf();
162  }
163  device.close();
164 }
165 
166 
167 bool
168 NWWriter_SUMO::writeInternalEdges(OutputDevice& into, const NBNode& n, bool origNames) {
169  bool ret = false;
170  const EdgeVector& incoming = n.getIncomingEdges();
171  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
172  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
173  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
174  if ((*k).toEdge == 0) {
175  continue;
176  }
177  std::string origID = origNames ? (*k).origID : "";
178  writeInternalEdge(into, (*k).id, (*k).vmax, (*k).shape, origID);
179  if ((*k).haveVia) {
180  writeInternalEdge(into, (*k).viaID, (*k).viaVmax, (*k).viaShape, origID);
181  }
182  ret = true;
183  }
184  }
185  return ret;
186 }
187 
188 
189 void
190 NWWriter_SUMO::writeInternalEdge(OutputDevice& into, const std::string& id, SUMOReal vmax, const PositionVector& shape,
191  const std::string& origID) {
192  SUMOReal length = MAX2(shape.length(), (SUMOReal)POSITION_EPS); // microsim needs positive length
193  into.openTag(SUMO_TAG_EDGE);
194  into.writeAttr(SUMO_ATTR_ID, id);
196  into.openTag(SUMO_TAG_LANE);
197  into.writeAttr(SUMO_ATTR_ID, id + "_0");
198  into.writeAttr(SUMO_ATTR_INDEX, 0);
199  into.writeAttr(SUMO_ATTR_SPEED, vmax);
200  into.writeAttr(SUMO_ATTR_LENGTH, length);
201  into.writeAttr(SUMO_ATTR_SHAPE, shape);
202  if (origID != "") {
203  into.openTag(SUMO_TAG_PARAM);
204  into.writeAttr(SUMO_ATTR_KEY, "origId");
205  into.writeAttr(SUMO_ATTR_VALUE, origID);
206  into.closeTag();
207  into.closeTag();
208  } else {
209  into.closeTag();
210  }
211  into.closeTag();
212 }
213 
214 
215 void
216 NWWriter_SUMO::writeEdge(OutputDevice& into, const NBEdge& e, bool noNames, bool origNames) {
217  // write the edge's begin
220  into.writeAttr(SUMO_ATTR_TO, e.getToNode()->getID());
221  if (!noNames && e.getStreetName() != "") {
223  }
225  if (e.getTypeName() != "") {
227  }
228  if (e.isMacroscopicConnector()) {
230  }
231  // write the spread type if not default ("right")
234  }
235  if (e.hasLoadedLength()) {
237  }
238  if (!e.hasDefaultGeometry()) {
240  }
241  // write the lanes
242  const std::vector<NBEdge::Lane>& lanes = e.getLanes();
243  SUMOReal length = e.getLoadedLength();
244  if (length <= 0) {
245  length = (SUMOReal) .1;
246  }
247  for (unsigned int i = 0; i < (unsigned int) lanes.size(); i++) {
248  writeLane(into, e.getID(), e.getLaneID(i), lanes[i], length, i, origNames);
249  }
250  // close the edge
251  into.closeTag();
252 }
253 
254 
255 void
256 NWWriter_SUMO::writeLane(OutputDevice& into, const std::string& eID, const std::string& lID, const NBEdge::Lane& lane,
257  SUMOReal length, unsigned int index, bool origNames) {
258  // output the lane's attributes
260  // the first lane of an edge will be the depart lane
261  into.writeAttr(SUMO_ATTR_INDEX, index);
262  // write the list of allowed/disallowed vehicle classes
263  writePermissions(into, lane.permissions);
264  writePreferences(into, lane.preferred);
265  // some further information
266  if (lane.speed == 0) {
267  WRITE_WARNING("Lane #" + toString(index) + " of edge '" + eID + "' has a maximum velocity of 0.");
268  } else if (lane.speed < 0) {
269  throw ProcessError("Negative velocity (" + toString(lane.speed) + " on edge '" + eID + "' lane#" + toString(index) + ".");
270  }
271  if (lane.offset > 0) {
272  length = length - lane.offset;
273  }
274  into.writeAttr(SUMO_ATTR_SPEED, lane.speed);
275  into.writeAttr(SUMO_ATTR_LENGTH, length);
276  if (lane.offset != NBEdge::UNSPECIFIED_OFFSET) {
278  }
279  if (lane.width != NBEdge::UNSPECIFIED_WIDTH) {
280  into.writeAttr(SUMO_ATTR_WIDTH, lane.width);
281  }
282  PositionVector shape = lane.shape;
283  if (lane.offset > 0) {
284  shape = shape.getSubpart(0, shape.length() - lane.offset);
285  }
286  into.writeAttr(SUMO_ATTR_SHAPE, shape);
287  if (origNames && lane.origID != "") {
288  into.openTag(SUMO_TAG_PARAM);
289  into.writeAttr(SUMO_ATTR_KEY, "origId");
290  into.writeAttr(SUMO_ATTR_VALUE, lane.origID);
291  into.closeTag();
292  into.closeTag();
293  } else {
294  into.closeTag();
295  }
296 }
297 
298 
299 void
301  // write the attributes
303  into.writeAttr(SUMO_ATTR_TYPE, n.getType());
305  // write the incoming lanes
306  std::string incLanes;
307  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
308  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
309  unsigned int noLanes = (*i)->getNumLanes();
310  for (unsigned int j = 0; j < noLanes; j++) {
311  incLanes += (*i)->getLaneID(j);
312  if (i != incoming.end() - 1 || j < noLanes - 1) {
313  incLanes += ' ';
314  }
315  }
316  }
317  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
318  // write the internal lanes
319  std::string intLanes;
320  if (!OptionsCont::getOptions().getBool("no-internal-links")) {
321  unsigned int l = 0;
322  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
323  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
324  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
325  if ((*k).toEdge == 0) {
326  continue;
327  }
328  if (l != 0) {
329  intLanes += ' ';
330  }
331  if (!(*k).haveVia) {
332  intLanes += (*k).id + "_0";
333  } else {
334  intLanes += (*k).viaID + "_0";
335  }
336  l++;
337  }
338  }
339  }
340  into.writeAttr(SUMO_ATTR_INTLANES, intLanes);
341  // close writing
343  if (n.getType() == NODETYPE_DEAD_END) {
344  into.closeTag();
345  } else {
346  // write right-of-way logics
347  n.writeLogic(into);
348  into.closeTag();
349  }
350 }
351 
352 
353 bool
355  bool ret = false;
356  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
357  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
358  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
359  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
360  if ((*k).toEdge == 0 || !(*k).haveVia) {
361  continue;
362  }
363  Position pos = (*k).shape[-1];
364  into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0");
366  NWFrame::writePositionLong(pos, into);
367  std::string incLanes = (*k).id + "_0";
368  if ((*k).foeIncomingLanes.length() != 0) {
369  incLanes += " " + (*k).foeIncomingLanes;
370  }
371  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
372  into.writeAttr(SUMO_ATTR_INTLANES, (*k).foeInternalLanes);
373  into.closeTag();
374  ret = true;
375  }
376  }
377  return ret;
378 }
379 
380 
381 void
383  bool includeInternal, ConnectionStyle style) {
384  assert(c.toEdge != 0);
386  into.writeAttr(SUMO_ATTR_FROM, from.getID());
387  into.writeAttr(SUMO_ATTR_TO, c.toEdge->getID());
390  if (c.mayDefinitelyPass) {
392  }
393  if (style != PLAIN) {
394  if (includeInternal) {
395  into.writeAttr(SUMO_ATTR_VIA, c.id + "_0");
396  }
397  // set information about the controlling tl if any
398  if (c.tlID != "") {
399  into.writeAttr(SUMO_ATTR_TLID, c.tlID);
401  }
402  if (style == SUMONET) {
403  // write the direction information
404  LinkDirection dir = from.getToNode()->getDirection(&from, c.toEdge);
405  assert(dir != LINKDIR_NODIR);
406  into.writeAttr(SUMO_ATTR_DIR, toString(dir));
407  // write the state information
408  const LinkState linkState = from.getToNode()->getLinkState(
409  &from, c.toEdge, c.toLane, c.mayDefinitelyPass, c.tlID);
410  into.writeAttr(SUMO_ATTR_STATE, linkState);
411  }
412  }
413  into.closeTag();
414 }
415 
416 
417 bool
419  bool ret = false;
420  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
421  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
422  NBEdge* from = *i;
423  const std::vector<NBEdge::Connection>& connections = from->getConnections();
424  for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) {
425  const NBEdge::Connection& c = *j;
426  assert(c.toEdge != 0);
427  if (c.haveVia) {
428  // internal split
429  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, c.viaID + "_0");
430  writeInternalConnection(into, c.viaID, c.toEdge->getID(), c.toLane, "");
431  } else {
432  // no internal split
433  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, "");
434  }
435  ret = true;
436  }
437  }
438  return ret;
439 }
440 
441 
442 void
444  const std::string& from, const std::string& to, int toLane, const std::string& via) {
446  into.writeAttr(SUMO_ATTR_FROM, from);
447  into.writeAttr(SUMO_ATTR_TO, to);
449  into.writeAttr(SUMO_ATTR_TO_LANE, toLane);
450  if (via != "") {
451  into.writeAttr(SUMO_ATTR_VIA, via);
452  }
453  into.writeAttr(SUMO_ATTR_DIR, "s");
454  into.writeAttr(SUMO_ATTR_STATE, "M");
455  into.closeTag();
456 }
457 
458 
459 void
461  std::vector<std::string> edgeIDs;
462  std::vector<std::string> nodeIDs;
463  for (EdgeVector::const_iterator j = r.begin(); j != r.end(); ++j) {
464  edgeIDs.push_back((*j)->getID());
465  nodeIDs.push_back((*j)->getToNode()->getID());
466  }
467  // make output deterministic
468  std::sort(edgeIDs.begin(), edgeIDs.end());
469  std::sort(nodeIDs.begin(), nodeIDs.end());
471  into.writeAttr(SUMO_ATTR_NODES, joinToString(nodeIDs, " "));
472  into.writeAttr(SUMO_ATTR_EDGES, joinToString(edgeIDs, " "));
473  into.closeTag();
474 }
475 
476 
477 void
479  std::vector<SUMOReal> sourceW = d.getSourceWeights();
481  std::vector<SUMOReal> sinkW = d.getSinkWeights();
483  // write the head and the id of the district
485  if (d.getShape().size() > 0) {
487  }
488  size_t i;
489  // write all sources
490  const std::vector<NBEdge*>& sources = d.getSourceEdges();
491  for (i = 0; i < sources.size(); i++) {
492  // write the head and the id of the source
493  into.openTag(SUMO_TAG_TAZSOURCE).writeAttr(SUMO_ATTR_ID, sources[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sourceW[i]);
494  into.closeTag();
495  }
496  // write all sinks
497  const std::vector<NBEdge*>& sinks = d.getSinkEdges();
498  for (i = 0; i < sinks.size(); i++) {
499  // write the head and the id of the sink
500  into.openTag(SUMO_TAG_TAZSINK).writeAttr(SUMO_ATTR_ID, sinks[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sinkW[i]);
501  into.closeTag();
502  }
503  // write the tail
504  into.closeTag();
505 }
506 
507 
508 std::string
510  SUMOReal time = STEPS2TIME(steps);
511  if (time == std::floor(time)) {
512  return toString(int(time));
513  } else {
514  return toString(time);
515  }
516 }
517 
518 
519 void
521  for (NBConnectionProhibits::const_iterator j = prohibitions.begin(); j != prohibitions.end(); j++) {
522  NBConnection prohibited = (*j).first;
523  const NBConnectionVector& prohibiting = (*j).second;
524  for (NBConnectionVector::const_iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
525  NBConnection prohibitor = *k;
529  into.closeTag();
530  }
531  }
532 }
533 
534 
535 std::string
537  return c.getFrom()->getID() + "->" + c.getTo()->getID();
538 }
539 
540 
541 void
543  std::vector<NBTrafficLightLogic*> logics = tllCont.getComputed();
544  for (std::vector<NBTrafficLightLogic*>::iterator it = logics.begin(); it != logics.end(); it++) {
546  into.writeAttr(SUMO_ATTR_ID, (*it)->getID());
547  into.writeAttr(SUMO_ATTR_TYPE, (*it)->getType());
548  into.writeAttr(SUMO_ATTR_PROGRAMID, (*it)->getProgramID());
549  into.writeAttr(SUMO_ATTR_OFFSET, writeSUMOTime((*it)->getOffset()));
550  // write the phases
551  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = (*it)->getPhases();
552  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator j = phases.begin(); j != phases.end(); ++j) {
553  into.openTag(SUMO_TAG_PHASE);
554  into.writeAttr(SUMO_ATTR_DURATION, writeSUMOTime(j->duration));
555  into.writeAttr(SUMO_ATTR_STATE, j->state);
556  into.closeTag();
557  }
558  into.closeTag();
559  }
560  if (logics.size() > 0) {
561  into.lf();
562  }
563 }
564 
565 
566 void
568  const GeoConvHelper& geoConvHelper = GeoConvHelper::getFinal();
570  into.writeAttr(SUMO_ATTR_NET_OFFSET, geoConvHelper.getOffsetBase());
571  into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, geoConvHelper.getConvBoundary());
572  if (geoConvHelper.usingGeoProjection()) {
574  }
575  into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, geoConvHelper.getOrigBoundary());
576  if (geoConvHelper.usingGeoProjection()) {
577  into.setPrecision();
578  }
579  into.writeAttr(SUMO_ATTR_ORIG_PROJ, geoConvHelper.getProjString());
580  into.closeTag();
581  into.lf();
582 }
583 
584 
585 void
587  if (permissions == SVCFreeForAll) {
588  return;
589  } else if (permissions == 0) {
590  // special case: since all-empty encodes FreeForAll we must list all disallowed
592  return;
593  } else {
594  std::pair<std::string, bool> encoding = getPermissionEncoding(permissions);
595  if (encoding.second) {
596  into.writeAttr(SUMO_ATTR_ALLOW, encoding.first);
597  } else {
598  into.writeAttr(SUMO_ATTR_DISALLOW, encoding.first);
599  }
600  }
601 }
602 
603 
604 void
606  if (preferred == SVCFreeForAll || preferred == 0) {
607  return;
608  } else {
610  }
611 }
612 /****************************************************************************/
613