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-sim.org/
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  std::set<NBNode*> roundaboutNodes;
103  const bool checkLaneFoesAll = oc.getBool("check-lane-foes.all");
104  const bool checkLaneFoesRoundabout = !checkLaneFoesAll && oc.getBool("check-lane-foes.roundabout");
105  if (checkLaneFoesRoundabout) {
106  const std::vector<EdgeVector>& roundabouts = nb.getRoundabouts();
107  for (std::vector<EdgeVector>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
108  for (EdgeVector::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
109  roundaboutNodes.insert((*j)->getToNode());
110  }
111  }
112  }
113  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
114  const bool checkLaneFoes = checkLaneFoesAll || (checkLaneFoesRoundabout && roundaboutNodes.count((*i).second) > 0);
115  writeJunction(device, *(*i).second, checkLaneFoes);
116  }
117  device.lf();
118  const bool includeInternal = !oc.getBool("no-internal-links");
119  if (includeInternal) {
120  // ... internal nodes if not unwanted
121  bool hadAny = false;
122  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
123  hadAny |= writeInternalNodes(device, *(*i).second);
124  }
125  if (hadAny) {
126  device.lf();
127  }
128  }
129 
130  // write the successors of lanes
131  unsigned int numConnections = 0;
132  for (std::map<std::string, NBEdge*>::const_iterator it_edge = ec.begin(); it_edge != ec.end(); it_edge++) {
133  NBEdge* from = it_edge->second;
135  const std::vector<NBEdge::Connection> connections = from->getConnections();
136  numConnections += (unsigned int)connections.size();
137  for (std::vector<NBEdge::Connection>::const_iterator it_c = connections.begin(); it_c != connections.end(); it_c++) {
138  writeConnection(device, *from, *it_c, includeInternal);
139  }
140  }
141  if (numConnections > 0) {
142  device.lf();
143  }
144  if (includeInternal) {
145  // ... internal successors if not unwanted
146  bool hadAny = false;
147  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
148  hadAny |= writeInternalConnections(device, *(*i).second);
149  }
150  if (hadAny) {
151  device.lf();
152  }
153  }
154  // write loaded prohibitions
155  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
156  writeProhibitions(device, i->second->getProhibitions());
157  }
158 
159  // write roundabout information
160  const std::vector<EdgeVector>& roundabouts = nb.getRoundabouts();
161  // make output deterministic
162  std::vector<std::vector<std::string> > edgeIDs;
163  for (std::vector<EdgeVector>::const_iterator i = roundabouts.begin(); i != roundabouts.end(); ++i) {
164  std::vector<std::string> tEdgeIDs;
165  for (EdgeVector::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
166  tEdgeIDs.push_back((*j)->getID());
167  }
168  std::sort(tEdgeIDs.begin(), tEdgeIDs.end());
169  edgeIDs.push_back(tEdgeIDs);
170  }
171  std::sort(edgeIDs.begin(), edgeIDs.end());
172  // write
173  for (std::vector<std::vector<std::string> >::const_iterator i = edgeIDs.begin(); i != edgeIDs.end(); ++i) {
174  writeRoundabout(device, *i, ec);
175  }
176  if (roundabouts.size() != 0) {
177  device.lf();
178  }
179 
180  // write the districts
181  for (std::map<std::string, NBDistrict*>::const_iterator i = dc.begin(); i != dc.end(); i++) {
182  writeDistrict(device, *(*i).second);
183  }
184  if (dc.size() != 0) {
185  device.lf();
186  }
187  device.close();
188 }
189 
190 
191 bool
192 NWWriter_SUMO::writeInternalEdges(OutputDevice& into, const NBNode& n, bool origNames) {
193  bool ret = false;
194  const EdgeVector& incoming = n.getIncomingEdges();
195  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
196  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
197  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
198  if ((*k).toEdge == 0) {
199  continue;
200  }
201  std::string origID = origNames ? (*k).origID : "";
202  writeInternalEdge(into, (*k).id, (*k).vmax, (*k).shape, origID);
203  if ((*k).haveVia) {
204  writeInternalEdge(into, (*k).viaID, (*k).viaVmax, (*k).viaShape, origID);
205  }
206  ret = true;
207  }
208  }
209  return ret;
210 }
211 
212 
213 void
214 NWWriter_SUMO::writeInternalEdge(OutputDevice& into, const std::string& id, SUMOReal vmax, const PositionVector& shape,
215  const std::string& origID) {
216  SUMOReal length = MAX2(shape.length(), (SUMOReal)POSITION_EPS); // microsim needs positive length
217  into.openTag(SUMO_TAG_EDGE);
218  into.writeAttr(SUMO_ATTR_ID, id);
220  into.openTag(SUMO_TAG_LANE);
221  into.writeAttr(SUMO_ATTR_ID, id + "_0");
222  into.writeAttr(SUMO_ATTR_INDEX, 0);
223  into.writeAttr(SUMO_ATTR_SPEED, vmax);
224  into.writeAttr(SUMO_ATTR_LENGTH, length);
225  into.writeAttr(SUMO_ATTR_SHAPE, shape);
226  if (origID != "") {
227  into.openTag(SUMO_TAG_PARAM);
228  into.writeAttr(SUMO_ATTR_KEY, "origId");
229  into.writeAttr(SUMO_ATTR_VALUE, origID);
230  into.closeTag();
231  into.closeTag();
232  } else {
233  into.closeTag();
234  }
235  into.closeTag();
236 }
237 
238 
239 void
240 NWWriter_SUMO::writeEdge(OutputDevice& into, const NBEdge& e, bool noNames, bool origNames) {
241  // write the edge's begin
244  into.writeAttr(SUMO_ATTR_TO, e.getToNode()->getID());
245  if (!noNames && e.getStreetName() != "") {
247  }
249  if (e.getTypeName() != "") {
251  }
252  if (e.isMacroscopicConnector()) {
254  }
255  // write the spread type if not default ("right")
258  }
259  if (e.hasLoadedLength()) {
261  }
262  if (!e.hasDefaultGeometry()) {
264  }
265  // write the lanes
266  const std::vector<NBEdge::Lane>& lanes = e.getLanes();
267 
268  SUMOReal length = e.getLoadedLength();
269  if (OptionsCont::getOptions().getBool("no-internal-links") && !e.hasLoadedLength()) {
270  // use length to junction center even if a modified geometry was given
271  PositionVector geom = e.getGeometry();
274  length = geom.length();
275  }
276  if (length <= 0) {
277  length = (SUMOReal)POSITION_EPS;
278  }
279  for (unsigned int i = 0; i < (unsigned int) lanes.size(); i++) {
280  writeLane(into, e.getID(), e.getLaneID(i), lanes[i], length, i, origNames);
281  }
282  // close the edge
283  into.closeTag();
284 }
285 
286 
287 void
288 NWWriter_SUMO::writeLane(OutputDevice& into, const std::string& eID, const std::string& lID, const NBEdge::Lane& lane,
289  SUMOReal length, unsigned int index, bool origNames) {
290  // output the lane's attributes
292  // the first lane of an edge will be the depart lane
293  into.writeAttr(SUMO_ATTR_INDEX, index);
294  // write the list of allowed/disallowed vehicle classes
295  writePermissions(into, lane.permissions);
296  writePreferences(into, lane.preferred);
297  // some further information
298  if (lane.speed == 0) {
299  WRITE_WARNING("Lane #" + toString(index) + " of edge '" + eID + "' has a maximum velocity of 0.");
300  } else if (lane.speed < 0) {
301  throw ProcessError("Negative velocity (" + toString(lane.speed) + " on edge '" + eID + "' lane#" + toString(index) + ".");
302  }
303  if (lane.offset > 0) {
304  length = length - lane.offset;
305  }
306  into.writeAttr(SUMO_ATTR_SPEED, lane.speed);
307  into.writeAttr(SUMO_ATTR_LENGTH, length);
308  if (lane.offset != NBEdge::UNSPECIFIED_OFFSET) {
310  }
311  if (lane.width != NBEdge::UNSPECIFIED_WIDTH) {
312  into.writeAttr(SUMO_ATTR_WIDTH, lane.width);
313  }
314  PositionVector shape = lane.shape;
315  if (lane.offset > 0) {
316  shape = shape.getSubpart(0, shape.length() - lane.offset);
317  }
318  into.writeAttr(SUMO_ATTR_SHAPE, shape);
319  if (origNames && lane.origID != "") {
320  into.openTag(SUMO_TAG_PARAM);
321  into.writeAttr(SUMO_ATTR_KEY, "origId");
322  into.writeAttr(SUMO_ATTR_VALUE, lane.origID);
323  into.closeTag();
324  into.closeTag();
325  } else {
326  into.closeTag();
327  }
328 }
329 
330 
331 void
332 NWWriter_SUMO::writeJunction(OutputDevice& into, const NBNode& n, const bool checkLaneFoes) {
333  // write the attributes
335  into.writeAttr(SUMO_ATTR_TYPE, n.getType());
337  // write the incoming lanes
338  std::string incLanes;
339  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
340  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
341  unsigned int noLanes = (*i)->getNumLanes();
342  for (unsigned int j = 0; j < noLanes; j++) {
343  incLanes += (*i)->getLaneID(j);
344  if (i != incoming.end() - 1 || j < noLanes - 1) {
345  incLanes += ' ';
346  }
347  }
348  }
349  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
350  // write the internal lanes
351  std::string intLanes;
352  if (!OptionsCont::getOptions().getBool("no-internal-links")) {
353  unsigned int l = 0;
354  for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
355  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
356  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
357  if ((*k).toEdge == 0) {
358  continue;
359  }
360  if (l != 0) {
361  intLanes += ' ';
362  }
363  if (!(*k).haveVia) {
364  intLanes += (*k).id + "_0";
365  } else {
366  intLanes += (*k).viaID + "_0";
367  }
368  l++;
369  }
370  }
371  }
372  into.writeAttr(SUMO_ATTR_INTLANES, intLanes);
373  // close writing
375  if (n.getType() == NODETYPE_DEAD_END) {
376  into.closeTag();
377  } else {
378  // write right-of-way logics
379  n.writeLogic(into, checkLaneFoes);
380  into.closeTag();
381  }
382 }
383 
384 
385 bool
387  bool ret = false;
388  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
389  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
390  const std::vector<NBEdge::Connection>& elv = (*i)->getConnections();
391  for (std::vector<NBEdge::Connection>::const_iterator k = elv.begin(); k != elv.end(); ++k) {
392  if ((*k).toEdge == 0 || !(*k).haveVia) {
393  continue;
394  }
395  Position pos = (*k).shape[-1];
396  into.openTag(SUMO_TAG_JUNCTION).writeAttr(SUMO_ATTR_ID, (*k).viaID + "_0");
398  NWFrame::writePositionLong(pos, into);
399  std::string incLanes = (*k).id + "_0";
400  if ((*k).foeIncomingLanes.length() != 0) {
401  incLanes += " " + (*k).foeIncomingLanes;
402  }
403  into.writeAttr(SUMO_ATTR_INCLANES, incLanes);
404  into.writeAttr(SUMO_ATTR_INTLANES, (*k).foeInternalLanes);
405  into.closeTag();
406  ret = true;
407  }
408  }
409  return ret;
410 }
411 
412 
413 void
415  bool includeInternal, ConnectionStyle style) {
416  assert(c.toEdge != 0);
418  into.writeAttr(SUMO_ATTR_FROM, from.getID());
419  into.writeAttr(SUMO_ATTR_TO, c.toEdge->getID());
422  if (c.mayDefinitelyPass) {
424  }
425  if (style != PLAIN) {
426  if (includeInternal) {
427  into.writeAttr(SUMO_ATTR_VIA, c.id + "_0");
428  }
429  // set information about the controlling tl if any
430  if (c.tlID != "") {
431  into.writeAttr(SUMO_ATTR_TLID, c.tlID);
433  }
434  if (style == SUMONET) {
435  // write the direction information
436  LinkDirection dir = from.getToNode()->getDirection(&from, c.toEdge);
437  assert(dir != LINKDIR_NODIR);
438  into.writeAttr(SUMO_ATTR_DIR, toString(dir));
439  // write the state information
440  const LinkState linkState = from.getToNode()->getLinkState(
441  &from, c.toEdge, c.toLane, c.mayDefinitelyPass, c.tlID);
442  into.writeAttr(SUMO_ATTR_STATE, linkState);
443  }
444  }
445  into.closeTag();
446 }
447 
448 
449 bool
451  bool ret = false;
452  const std::vector<NBEdge*>& incoming = n.getIncomingEdges();
453  for (std::vector<NBEdge*>::const_iterator i = incoming.begin(); i != incoming.end(); ++i) {
454  NBEdge* from = *i;
455  const std::vector<NBEdge::Connection>& connections = from->getConnections();
456  for (std::vector<NBEdge::Connection>::const_iterator j = connections.begin(); j != connections.end(); ++j) {
457  const NBEdge::Connection& c = *j;
458  assert(c.toEdge != 0);
459  if (c.haveVia) {
460  // internal split
461  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, c.viaID + "_0");
462  writeInternalConnection(into, c.viaID, c.toEdge->getID(), c.toLane, "");
463  } else {
464  // no internal split
465  writeInternalConnection(into, c.id, c.toEdge->getID(), c.toLane, "");
466  }
467  ret = true;
468  }
469  }
470  return ret;
471 }
472 
473 
474 void
476  const std::string& from, const std::string& to, int toLane, const std::string& via) {
478  into.writeAttr(SUMO_ATTR_FROM, from);
479  into.writeAttr(SUMO_ATTR_TO, to);
481  into.writeAttr(SUMO_ATTR_TO_LANE, toLane);
482  if (via != "") {
483  into.writeAttr(SUMO_ATTR_VIA, via);
484  }
485  into.writeAttr(SUMO_ATTR_DIR, "s");
486  into.writeAttr(SUMO_ATTR_STATE, "M");
487  into.closeTag();
488 }
489 
490 
491 void
492 NWWriter_SUMO::writeRoundabout(OutputDevice& into, const std::vector<std::string>& edgeIDs,
493  const NBEdgeCont& ec) {
494  std::vector<std::string> nodeIDs;
495  for (std::vector<std::string>::const_iterator i = edgeIDs.begin(); i != edgeIDs.end(); ++i) {
496  nodeIDs.push_back(ec.retrieve(*i)->getToNode()->getID());
497  }
498  std::sort(nodeIDs.begin(), nodeIDs.end());
500  into.writeAttr(SUMO_ATTR_NODES, joinToString(nodeIDs, " "));
501  into.writeAttr(SUMO_ATTR_EDGES, joinToString(edgeIDs, " "));
502  into.closeTag();
503 }
504 
505 
506 void
508  std::vector<SUMOReal> sourceW = d.getSourceWeights();
510  std::vector<SUMOReal> sinkW = d.getSinkWeights();
512  // write the head and the id of the district
514  if (d.getShape().size() > 0) {
516  }
517  size_t i;
518  // write all sources
519  const std::vector<NBEdge*>& sources = d.getSourceEdges();
520  for (i = 0; i < sources.size(); i++) {
521  // write the head and the id of the source
522  into.openTag(SUMO_TAG_TAZSOURCE).writeAttr(SUMO_ATTR_ID, sources[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sourceW[i]);
523  into.closeTag();
524  }
525  // write all sinks
526  const std::vector<NBEdge*>& sinks = d.getSinkEdges();
527  for (i = 0; i < sinks.size(); i++) {
528  // write the head and the id of the sink
529  into.openTag(SUMO_TAG_TAZSINK).writeAttr(SUMO_ATTR_ID, sinks[i]->getID()).writeAttr(SUMO_ATTR_WEIGHT, sinkW[i]);
530  into.closeTag();
531  }
532  // write the tail
533  into.closeTag();
534 }
535 
536 
537 std::string
539  SUMOReal time = STEPS2TIME(steps);
540  if (time == std::floor(time)) {
541  return toString(int(time));
542  } else {
543  return toString(time);
544  }
545 }
546 
547 
548 void
550  for (NBConnectionProhibits::const_iterator j = prohibitions.begin(); j != prohibitions.end(); j++) {
551  NBConnection prohibited = (*j).first;
552  const NBConnectionVector& prohibiting = (*j).second;
553  for (NBConnectionVector::const_iterator k = prohibiting.begin(); k != prohibiting.end(); k++) {
554  NBConnection prohibitor = *k;
558  into.closeTag();
559  }
560  }
561 }
562 
563 
564 std::string
566  return c.getFrom()->getID() + "->" + c.getTo()->getID();
567 }
568 
569 
570 void
572  std::vector<NBTrafficLightLogic*> logics = tllCont.getComputed();
573  for (std::vector<NBTrafficLightLogic*>::iterator it = logics.begin(); it != logics.end(); it++) {
575  into.writeAttr(SUMO_ATTR_ID, (*it)->getID());
576  into.writeAttr(SUMO_ATTR_TYPE, (*it)->getType());
577  into.writeAttr(SUMO_ATTR_PROGRAMID, (*it)->getProgramID());
578  into.writeAttr(SUMO_ATTR_OFFSET, writeSUMOTime((*it)->getOffset()));
579  // write the phases
580  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = (*it)->getPhases();
581  for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator j = phases.begin(); j != phases.end(); ++j) {
582  into.openTag(SUMO_TAG_PHASE);
583  into.writeAttr(SUMO_ATTR_DURATION, writeSUMOTime(j->duration));
584  into.writeAttr(SUMO_ATTR_STATE, j->state);
585  into.closeTag();
586  }
587  into.closeTag();
588  }
589  if (logics.size() > 0) {
590  into.lf();
591  }
592 }
593 
594 
595 void
597  const GeoConvHelper& geoConvHelper = GeoConvHelper::getFinal();
599  into.writeAttr(SUMO_ATTR_NET_OFFSET, geoConvHelper.getOffsetBase());
600  into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, geoConvHelper.getConvBoundary());
601  if (geoConvHelper.usingGeoProjection()) {
603  }
604  into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, geoConvHelper.getOrigBoundary());
605  if (geoConvHelper.usingGeoProjection()) {
606  into.setPrecision();
607  }
608  into.writeAttr(SUMO_ATTR_ORIG_PROJ, geoConvHelper.getProjString());
609  into.closeTag();
610  into.lf();
611 }
612 
613 
614 void
616  if (permissions == SVCFreeForAll) {
617  return;
618  } else if (permissions == 0) {
619  // special case: since all-empty encodes FreeForAll we must list all disallowed
621  return;
622  } else {
623  std::pair<std::string, bool> encoding = getPermissionEncoding(permissions);
624  if (encoding.second) {
625  into.writeAttr(SUMO_ATTR_ALLOW, encoding.first);
626  } else {
627  into.writeAttr(SUMO_ATTR_DISALLOW, encoding.first);
628  }
629  }
630 }
631 
632 
633 void
635  if (preferred == SVCFreeForAll || preferred == 0) {
636  return;
637  } else {
639  }
640 }
641 /****************************************************************************/
642