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-2012 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>
36 #include <utils/common/ToString.h>
39 #include <netbuild/NBEdge.h>
40 #include <netbuild/NBEdgeCont.h>
41 #include <netbuild/NBNode.h>
42 #include <netbuild/NBNodeCont.h>
43 #include <netbuild/NBNetBuilder.h>
45 #include <netbuild/NBDistrict.h>
46 #include "NWFrame.h"
47 #include "NWWriter_SUMO.h"
48 
49 #ifdef CHECK_MEMORY_LEAKS
50 #include <foreign/nvwa/debug_new.h>
51 #endif // CHECK_MEMORY_LEAKS
52 
53 
54 
55 // ===========================================================================
56 // method definitions
57 // ===========================================================================
58 // ---------------------------------------------------------------------------
59 // static methods
60 // ---------------------------------------------------------------------------
61 void
63  // check whether a sumo net-file shall be generated
64  if (!oc.isSet("output-file")) {
65  return;
66  }
67  OutputDevice& device = OutputDevice::getDevice(oc.getString("output-file"));
68  device.writeXMLHeader("net", SUMOSAXAttributes::ENCODING, 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
69  device.lf();
70  // get involved container
71  const NBNodeCont& nc = nb.getNodeCont();
72  const NBEdgeCont& ec = nb.getEdgeCont();
73  const NBDistrictCont& dc = nb.getDistrictCont();
74 
75  // write network offsets and projection
76  writeLocation(device);
77 
78  // write inner lanes
79  bool origNames = oc.getBool("output.original-names");
80  if (!oc.getBool("no-internal-links")) {
81  bool hadAny = false;
82  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
83  hadAny |= writeInternalEdges(device, *(*i).second, origNames);
84  }
85  if (hadAny) {
86  device.lf();
87  }
88  }
89 
90  // write edges with lanes and connected edges
91  bool noNames = !oc.getBool("output.street-names");
92  for (std::map<std::string, NBEdge*>::const_iterator i = ec.begin(); i != ec.end(); ++i) {
93  writeEdge(device, *(*i).second, noNames, origNames);
94  }
95  device.lf();
96 
97  // write tls logics
98  writeTrafficLights(device, nb.getTLLogicCont());
99 
100  // write the nodes (junctions)
101  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
102  writeJunction(device, *(*i).second);
103  }
104  device.lf();
105  const bool includeInternal = !oc.getBool("no-internal-links");
106  if (includeInternal) {
107  // ... internal nodes if not unwanted
108  bool hadAny = false;
109  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
110  hadAny |= writeInternalNodes(device, *(*i).second);
111  }
112  if (hadAny) {
113  device.lf();
114  }
115  }
116 
117  // write the successors of lanes
118  unsigned int numConnections = 0;
119  for (std::map<std::string, NBEdge*>::const_iterator it_edge = ec.begin(); it_edge != ec.end(); it_edge++) {
120  NBEdge* from = it_edge->second;
122  const std::vector<NBEdge::Connection> connections = from->getConnections();
123  numConnections += (unsigned int)connections.size();
124  for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) {
125  writeConnection(device, *from, *it_c, includeInternal);
126  }
127  }
128  if (numConnections > 0) {
129  device.lf();
130  }
131  if (includeInternal) {
132  // ... internal successors if not unwanted
133  bool hadAny = false;
134  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
135  hadAny |= writeInternalConnections(device, *(*i).second);
136  }
137  if (hadAny) {
138  device.lf();
139  }
140  }
141  // write loaded prohibitions
142  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
143  writeProhibitions(device, i->second->getProhibitions());
144  }
145 
146  // write roundabout information
147  const std::vector<std::set<NBEdge*> >& roundabouts = nb.getRoundabouts();
148  for (std::vector<std::set<NBEdge*> >::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
149  writeRoundabout(device, *i);
150  }
151  if (roundabouts.size() != 0) {
152  device.lf();
153  }
154 
155  // write the districts
156  for (std::map<std::string, NBDistrict*>::const_iterator i = dc.begin(); i != dc.end(); i++) {
157  writeDistrict(device, *(*i).second);
158  }
159  if (dc.size() != 0) {
160  device.lf();
161  }
162  device.close();
163 }
164 
165 
166 bool
167 NWWriter_SUMO::writeInternalEdges(OutputDevice& into, const NBNode& n, bool origNames) {
168  bool ret = false;
169  const EdgeVector& incoming = n.getIncomingEdges();
170  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
171  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
172  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
173  if ((*k).toEdge == 0) {
174  continue;
175  }
176  std::string origID = origNames ? (*k).origID : "";
177  writeInternalEdge(into, (*k).id, (*k).vmax, (*k).shape, origID);
178  if ((*k).haveVia) {
179  writeInternalEdge(into, (*k).viaID, (*k).viaVmax, (*k).viaShape, origID);
180  }
181  ret = true;
182  }
183  }
184  return ret;
185 }
186 
187 
188 void
189 NWWriter_SUMO::writeInternalEdge(OutputDevice& into, const std::string& id, SUMOReal vmax, const PositionVector& shape,
190  const std::string& origID) {
191  SUMOReal length = MAX2(shape.length(), (SUMOReal)POSITION_EPS); // microsim needs positive length
192  into.openTag(SUMO_TAG_EDGE);
193  into.writeAttr(SUMO_ATTR_ID, id);
195  into.closeOpener();
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.closeOpener();
204  into.openTag(SUMO_TAG_PARAM);
205  into.writeAttr(SUMO_ATTR_KEY, "origId");
206  into.writeAttr(SUMO_ATTR_VALUE, origID);
207  into.closeTag(true);
208  into.closeTag();
209  } else {
210  into.closeTag(true);
211  }
212  into.closeTag();
213 }
214 
215 
216 void
217 NWWriter_SUMO::writeEdge(OutputDevice& into, const NBEdge& e, bool noNames, bool origNames) {
218  // write the edge's begin
221  into.writeAttr(SUMO_ATTR_TO, e.getToNode()->getID());
222  if (!noNames && e.getStreetName() != "") {
224  }
226  if (e.getTypeName() != "") {
228  }
229  if (e.isMacroscopicConnector()) {
231  }
232  // write the spread type if not default ("right")
235  }
236  if (e.hasLoadedLength()) {
238  }
239  if (!e.hasDefaultGeometry()) {
241  }
242  into.closeOpener();
243  // write the lanes
244  const std::vector<NBEdge::Lane>& lanes = e.getLanes();
245  SUMOReal length = e.getLoadedLength();
246  if (length <= 0) {
247  length = (SUMOReal) .1;
248  }
249  for (unsigned int i = 0; i < (unsigned int) lanes.size(); i++) {
250  writeLane(into, e.getID(), e.getLaneID(i), lanes[i], length, i, origNames);
251  }
252  // close the edge
253  into.closeTag();
254 }
255 
256 
257 void
258 NWWriter_SUMO::writeLane(OutputDevice& into, const std::string& eID, const std::string& lID, const NBEdge::Lane& lane,
259  SUMOReal length, unsigned int index, bool origNames) {
260  // output the lane's attributes
262  // the first lane of an edge will be the depart lane
263  into.writeAttr(SUMO_ATTR_INDEX, index);
264  // write the list of allowed/disallowed vehicle classes
265  writePermissions(into, lane.permissions);
266  writePreferences(into, lane.preferred);
267  // some further information
268  if (lane.speed == 0) {
269  WRITE_WARNING("Lane #" + toString(index) + " of edge '" + eID + "' has a maximum velocity of 0.");
270  } else if (lane.speed < 0) {
271  throw ProcessError("Negative velocity (" + toString(lane.speed) + " on edge '" + eID + "' lane#" + toString(index) + ".");
272  }
273  if (lane.offset > 0) {
274  length = length - lane.offset;
275  }
276  into.writeAttr(SUMO_ATTR_SPEED, lane.speed);
277  into.writeAttr(SUMO_ATTR_LENGTH, length);
278  if (lane.offset != NBEdge::UNSPECIFIED_OFFSET) {
280  }
281  if (lane.width != NBEdge::UNSPECIFIED_WIDTH) {
282  into.writeAttr(SUMO_ATTR_WIDTH, lane.width);
283  }
284  PositionVector shape = lane.shape;
285  if (lane.offset > 0) {
286  shape = shape.getSubpart(0, shape.length() - lane.offset);
287  }
288  into.writeAttr(SUMO_ATTR_SHAPE, shape);
289  if (origNames && lane.origID != "") {
290  into.closeOpener();
291  into.openTag(SUMO_TAG_PARAM);
292  into.writeAttr(SUMO_ATTR_KEY, "origId");
293  into.writeAttr(SUMO_ATTR_VALUE, lane.origID);
294  into.closeTag(true);
295  into.closeTag();
296  } else {
297  into.closeTag(true);
298  }
299 }
300 
301 
302 void
304  // write the attributes
306  into.writeAttr(SUMO_ATTR_TYPE, n.getType());
308  // write the incoming lanes
309  std::string incLanes;
310  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
311  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
312  unsigned int noLanes = (*i)->getNumLanes();
313  for (unsigned int j = 0; j < noLanes; j++) {
314  incLanes += (*i)->getLaneID(j);
315  if (i != incoming.end() - 1 || j < noLanes - 1) {
316  incLanes += ' ';
317  }
318  }
319  }
320  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
321  // write the internal lanes
322  std::string intLanes;
323  if (!OptionsCont::getOptions().getBool("no-internal-links")) {
324  unsigned int l = 0;
325  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
326  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
327  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
328  if ((*k).toEdge == 0) {
329  continue;
330  }
331  if (l != 0) {
332  intLanes += ' ';
333  }
334  if (!(*k).haveVia) {
335  intLanes += (*k).id + "_0";
336  } else {
337  intLanes += (*k).viaID + "_0";
338  }
339  l++;
340  }
341  }
342  }
343  into.writeAttr(SUMO_ATTR_INTLANES, intLanes);
344  // close writing
346  if (n.getType() == NODETYPE_DEAD_END) {
347  into.closeTag(true);
348  } else {
349  into.closeOpener();
350  // write right-of-way logics
351  n.writeLogic(into);
352  into.closeTag();
353  }
354 }
355 
356 
357 bool
359  bool ret = false;
360  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
361  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
362  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
363  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
364  if ((*k).toEdge == 0 || !(*k).haveVia) {
365  continue;
366  }
367  Position pos = (*k).shape[-1];
368  into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0");
370  NWFrame::writePositionLong(pos, into);
371  std::string incLanes = (*k).id + "_0";
372  if ((*k).foeIncomingLanes.length() != 0) {
373  incLanes += " " + (*k).foeIncomingLanes;
374  }
375  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
376  into.writeAttr(SUMO_ATTR_INTLANES, (*k).foeInternalLanes);
377  into.closeTag(true);
378  ret = true;
379  }
380  }
381  return ret;
382 }
383 
384 
385 void
387  bool includeInternal, ConnectionStyle style) {
388  assert(c.toEdge != 0);
390  into.writeAttr(SUMO_ATTR_FROM, from.getID());
391  into.writeAttr(SUMO_ATTR_TO, c.toEdge->getID());
394  if (c.mayDefinitelyPass) {
396  }
397  if (style != PLAIN) {
398  if (includeInternal) {
399  into.writeAttr(SUMO_ATTR_VIA, c.id + "_0");
400  }
401  // set information about the controlling tl if any
402  if (c.tlID != "") {
403  into.writeAttr(SUMO_ATTR_TLID, c.tlID);
405  }
406  if (style == SUMONET) {
407  // write the direction information
408  LinkDirection dir = from.getToNode()->getDirection(&from, c.toEdge);
409  assert(dir != LINKDIR_NODIR);
410  into.writeAttr(SUMO_ATTR_DIR, toString(dir));
411  // write the state information
412  const LinkState linkState = from.getToNode()->getLinkState(
413  &from, c.toEdge, c.toLane, c.mayDefinitelyPass, c.tlID);
414  into.writeAttr(SUMO_ATTR_STATE, linkState);
415  }
416  }
417  into.closeTag(true);
418 }
419 
420 
421 bool
423  bool ret = false;
424  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
425  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
426  NBEdge* from = *i;
427  const std::vector<NBEdge::Connection>& connections = from->getConnections();
428  for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) {
429  const NBEdge::Connection& c = *j;
430  assert(c.toEdge != 0);
431  if (c.haveVia) {
432  // internal split
433  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, c.viaID + "_0");
434  writeInternalConnection(into, c.viaID, c.toEdge->getID(), c.toLane, "");
435  } else {
436  // no internal split
437  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, "");
438  }
439  ret = true;
440  }
441  }
442  return ret;
443 }
444 
445 
446 void
448  const std::string& from, const std::string& to, int toLane, const std::string& via) {
450  into.writeAttr(SUMO_ATTR_FROM, from);
451  into.writeAttr(SUMO_ATTR_TO, to);
453  into.writeAttr(SUMO_ATTR_TO_LANE, toLane);
454  if (via != "") {
455  into.writeAttr(SUMO_ATTR_VIA, via);
456  }
457  into.writeAttr(SUMO_ATTR_DIR, "s");
458  into.writeAttr(SUMO_ATTR_STATE, "M");
459  into.closeTag(true);
460 }
461 
462 
463 void
464 NWWriter_SUMO::writeRoundabout(OutputDevice& into, const std::set<NBEdge*>& r) {
465  std::set<std::string> nodes;
466  for (std::set<NBEdge*>::const_iterator j = r.begin(); j != r.end(); ++j) {
467  nodes.insert((*j)->getToNode()->getID());
468  }
469  std::string nodeString;
470  for (std::set<std::string>::const_iterator j = nodes.begin(); j != nodes.end(); ++j) {
471  if (j != nodes.begin()) {
472  nodeString += " ";
473  }
474  nodeString += *j;
475  }
477 }
478 
479 
480 void
482  std::vector<SUMOReal> sourceW = d.getSourceWeights();
484  std::vector<SUMOReal> sinkW = d.getSinkWeights();
486  // write the head and the id of the district
488  if (d.getShape().size() > 0) {
490  }
491  into.closeOpener();
492  size_t i;
493  // write all sources
494  const std::vector<NBEdge*>& sources = d.getSourceEdges();
495  for (i = 0; i < sources.size(); i++) {
496  // write the head and the id of the source
497  into.openTag(SUMO_TAG_TAZSOURCE).writeAttr(SUMO_ATTR_ID, sources[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sourceW[i]);
498  into.closeTag(true);
499  }
500  // write all sinks
501  const std::vector<NBEdge*>& sinks = d.getSinkEdges();
502  for (i = 0; i < sinks.size(); i++) {
503  // write the head and the id of the sink
504  into.openTag(SUMO_TAG_TAZSINK).writeAttr(SUMO_ATTR_ID, sinks[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sinkW[i]);
505  into.closeTag(true);
506  }
507  // write the tail
508  into.closeTag();
509 }
510 
511 
512 std::string
514  SUMOReal time = STEPS2TIME(steps);
515  if (time == std::floor(time)) {
516  return toString(int(time));
517  } else {
518  return toString(time);
519  }
520 }
521 
522 
523 void
525  for (NBConnectionProhibits::const_iterator j = prohibitions.begin(); j != prohibitions.end(); j++) {
526  NBConnection prohibited = (*j).first;
527  const NBConnectionVector& prohibiting = (*j).second;
528  for (NBConnectionVector::const_iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
529  NBConnection prohibitor = *k;
533  into.closeTag(true);
534  }
535  }
536 }
537 
538 
539 std::string
541  return c.getFrom()->getID() + "->" + c.getTo()->getID();
542 }
543 
544 
545 void
547  std::vector<NBTrafficLightLogic*> logics = tllCont.getComputed();
548  for (std::vector<NBTrafficLightLogic*>::iterator it = logics.begin(); it != logics.end(); it++) {
550  into.writeAttr(SUMO_ATTR_ID, (*it)->getID());
552  into.writeAttr(SUMO_ATTR_PROGRAMID, (*it)->getProgramID());
553  into.writeAttr(SUMO_ATTR_OFFSET, writeSUMOTime((*it)->getOffset()));
554  into.closeOpener();
555  // write the phases
556  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = (*it)->getPhases();
557  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator j = phases.begin(); j != phases.end(); ++j) {
558  into.openTag(SUMO_TAG_PHASE);
559  into.writeAttr(SUMO_ATTR_DURATION, writeSUMOTime(j->duration));
560  into.writeAttr(SUMO_ATTR_STATE, j->state);
561  into.closeTag(true);
562  }
563  into.closeTag();
564  }
565  if (logics.size() > 0) {
566  into.lf();
567  }
568 }
569 
570 
571 void
573  const GeoConvHelper& geoConvHelper = GeoConvHelper::getFinal();
575  into.writeAttr(SUMO_ATTR_NET_OFFSET, geoConvHelper.getOffsetBase());
576  into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, geoConvHelper.getConvBoundary());
577  if (geoConvHelper.usingGeoProjection()) {
579  }
580  into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, geoConvHelper.getOrigBoundary());
581  if (geoConvHelper.usingGeoProjection()) {
582  into.setPrecision();
583  }
584  into.writeAttr(SUMO_ATTR_ORIG_PROJ, geoConvHelper.getProjString());
585  into.closeTag(true);
586  into.lf();
587 }
588 
589 
590 void
592  if (permissions == SVCFreeForAll) {
593  return;
594  } else if (permissions == 0) {
595  // special case: since all-empty encodes FreeForAll we must list all disallowed
597  return;
598  } else {
599  std::pair<std::string, bool> encoding = getPermissionEncoding(permissions);
600  if (encoding.second) {
601  into.writeAttr(SUMO_ATTR_ALLOW, encoding.first);
602  } else {
603  into.writeAttr(SUMO_ATTR_DISALLOW, encoding.first);
604  }
605  }
606 }
607 
608 
609 void
611  if (preferred == SVCFreeForAll || preferred == 0) {
612  return;
613  } else {
615  }
616 }
617 /****************************************************************************/
618