SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBNetBuilder.cpp
Go to the documentation of this file.
1 /****************************************************************************/
12 // Instance responsible for building networks
13 /****************************************************************************/
14 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
15 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
16 /****************************************************************************/
17 //
18 // This file is part of SUMO.
19 // SUMO is free software: you can redistribute it and/or modify
20 // it under the terms of the GNU General Public License as published by
21 // the Free Software Foundation, either version 3 of the License, or
22 // (at your option) any later version.
23 //
24 /****************************************************************************/
25 
26 
27 // ===========================================================================
28 // included modules
29 // ===========================================================================
30 #ifdef _MSC_VER
31 #include <windows_config.h>
32 #else
33 #include <config.h>
34 #endif
35 
36 #include <string>
37 #include <fstream>
38 #include "NBNetBuilder.h"
39 #include "NBNodeCont.h"
40 #include "NBEdgeCont.h"
42 #include "NBDistrictCont.h"
43 #include "NBDistrict.h"
44 #include "NBDistribution.h"
45 #include "NBRequest.h"
46 #include "NBTypeCont.h"
51 #include <utils/common/ToString.h>
53 #include "NBAlgorithms.h"
54 #include "NBAlgorithms_Ramps.h"
55 
56 #ifdef HAVE_INTERNAL
57 #include <internal/HeightMapper.h>
58 #endif
59 
60 #ifdef CHECK_MEMORY_LEAKS
61 #include <foreign/nvwa/debug_new.h>
62 #endif // CHECK_MEMORY_LEAKS
63 
64 
65 // ===========================================================================
66 // method definitions
67 // ===========================================================================
69  myEdgeCont(myTypeCont),
70  myHaveSeenRoundabouts(false)
71 {}
72 
73 
75 
76 
77 void
79  // we possibly have to load the edges to keep
80  if (oc.isSet("keep-edges.input-file")) {
81  std::ifstream strm(oc.getString("keep-edges.input-file").c_str());
82  if (!strm.good()) {
83  throw ProcessError("Could not load names of edges too keep from '" + oc.getString("keep-edges.input-file") + "'.");
84  }
85  std::ostringstream oss;
86  bool first = true;
87  while (strm.good()) {
88  if (!first) {
89  oss << ',';
90  }
91  std::string name;
92  strm >> name;
93  oss << name;
94  first = false;
95  }
96  oc.set("keep-edges.explicit", oss.str());
97  }
98  // apply options to type control
99  myTypeCont.setDefaults(oc.getInt("default.lanenumber"), oc.getFloat("default.speed"), oc.getInt("default.priority"));
100  // apply options to edge control
102  // apply options to traffic light logics control
104 }
105 
106 
107 void
109  const std::set<std::string>& explicitTurnarounds,
110  bool removeElements) {
111  GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
112 
113 
114  // MODIFYING THE SETS OF NODES AND EDGES
115 
116  // Removes edges that are connecting the same node
117  PROGRESS_BEGIN_MESSAGE("Removing self-loops");
120  //
121  if (oc.exists("remove-edges.isolated") && oc.getBool("remove-edges.isolated")) {
122  PROGRESS_BEGIN_MESSAGE("Finding isolated roads");
125  }
126  //
127  if (oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload")) {
128  if (oc.isSet("keep-edges.explicit")) {
129  PROGRESS_BEGIN_MESSAGE("Removing unwished edges");
132  }
133  }
134  // join junctions (may create new "geometry"-nodes so it needs to come before removing these
135  if (oc.exists("junctions.join-exclude") && oc.isSet("junctions.join-exclude")) {
136  myNodeCont.addJoinExclusion(oc.getStringVector("junctions.join-exclude"));
137  }
139  if (oc.getBool("junctions.join")) {
140  PROGRESS_BEGIN_MESSAGE("Joining junction clusters");
141  // preliminary geometry computations to determine the length of edges
142  // This depends on turning directions and sorting of edge list
143  // in case junctions are joined geometry computations have to be repeated
146  myNodeCont.computeNodeShapes(oc.getBool("lefthand"));
148  // preliminary roundabout computations to avoid destroying roundabouts
149  if (oc.getBool("roundabouts.guess") || (oc.isDefault("roundabouts.guess") && myHaveSeenRoundabouts)) {
150  assert(myRoundabouts.size() == 0);
152  for (std::vector<EdgeVector>::const_iterator it_round = myRoundabouts.begin();
153  it_round != myRoundabouts.end(); ++it_round) {
154  std::vector<std::string> nodeIDs;
155  for (EdgeVector::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
156  nodeIDs.push_back((*it_edge)->getToNode()->getID());
157  }
158  myNodeCont.addJoinExclusion(nodeIDs);
159  }
160  myRoundabouts.clear();
161  }
162  numJoined += myNodeCont.joinJunctions(oc.getFloat("junctions.join-dist"), myDistrictCont, myEdgeCont, myTLLCont);
163  // reset geometry to avoid influencing subsequent steps (ramps.guess)
164  myEdgeCont.computeLaneShapes();
166  }
167  if (numJoined > 0) {
168  // bit of a misnomer since we're already done
169  WRITE_MESSAGE(" Joined " + toString(numJoined) + " junction cluster(s).");
170  }
171  //
172  if (removeElements) {
173  unsigned int no = 0;
174  const bool removeGeometryNodes = oc.exists("geometry.remove") && oc.getBool("geometry.remove");
175  PROGRESS_BEGIN_MESSAGE("Removing empty nodes" + std::string(removeGeometryNodes ? " and geometry nodes" : ""));
178  WRITE_MESSAGE(" " + toString(no) + " nodes removed.");
179  }
180 
181  // MOVE TO ORIGIN
182  // compute new boundary after network modifications have taken place
183  Boundary boundary;
184  for (std::map<std::string, NBNode*>::const_iterator it = myNodeCont.begin(); it != myNodeCont.end(); ++it) {
185  boundary.add(it->second->getPosition());
186  }
187  for (std::map<std::string, NBEdge*>::const_iterator it = myEdgeCont.begin(); it != myEdgeCont.end(); ++it) {
188  boundary.add(it->second->getGeometry().getBoxBoundary());
189  }
190  geoConvHelper.setConvBoundary(boundary);
191 
192  if (!oc.getBool("offset.disable-normalization") && oc.isDefault("offset.x") && oc.isDefault("offset.y")) {
193  moveToOrigin(geoConvHelper);
194  }
195  geoConvHelper.computeFinal(); // information needed for location element fixed at this point
196 
197  if (oc.exists("geometry.min-dist") && oc.isSet("geometry.min-dist")) {
198  PROGRESS_BEGIN_MESSAGE("Reducing geometries");
199  myEdgeCont.reduceGeometries(oc.getFloat("geometry.min-dist"));
201  }
202  // @note: removing geometry can create similar edges so joinSimilarEdges must come afterwards
203  // @note: likewise splitting can destroy similarities so joinSimilarEdges must come before
204  if (removeElements) {
205  PROGRESS_BEGIN_MESSAGE("Joining similar edges");
209  }
210  //
211  if (oc.exists("geometry.split") && oc.getBool("geometry.split")) {
212  PROGRESS_BEGIN_MESSAGE("Splitting geometry edges");
215  }
216  // guess ramps
217  if ((oc.exists("ramps.guess") && oc.getBool("ramps.guess")) || (oc.exists("ramps.set") && oc.isSet("ramps.set"))) {
218  PROGRESS_BEGIN_MESSAGE("Guessing and setting on-/off-ramps");
222  }
223  // guess sidewalks
224  if (oc.getBool("sidewalks.guess")) {
225  const int sidewalks = myEdgeCont.guessSidewalks(oc.getFloat("default.sidewalk-width"),
226  oc.getFloat("sidewalks.guess.min-speed"),
227  oc.getFloat("sidewalks.guess.max-speed"));
228  WRITE_MESSAGE("Guessed " + toString(sidewalks) + " sidewalks.");
229  }
230 
231  // check whether any not previously setable connections may be set now
233  //
234  if (oc.exists("geometry.max-angle")) {
236  oc.getFloat("geometry.max-angle"),
237  oc.getFloat("geometry.min-radius"),
238  oc.getBool("geometry.min-radius.fix"));
239  }
240 
241  // GEOMETRY COMPUTATION
242  //
243  PROGRESS_BEGIN_MESSAGE("Computing turning directions");
246  //
247  PROGRESS_BEGIN_MESSAGE("Sorting nodes' edges");
251  //
252  PROGRESS_BEGIN_MESSAGE("Computing node shapes");
253  if (oc.exists("geometry.junction-mismatch-threshold")) {
254  myNodeCont.computeNodeShapes(oc.getBool("lefthand"), oc.getFloat("geometry.junction-mismatch-threshold"));
255  } else {
256  myNodeCont.computeNodeShapes(oc.getBool("lefthand"));
257  }
259  //
260  PROGRESS_BEGIN_MESSAGE("Computing edge shapes");
263 
264  // APPLY SPEED MODIFICATIONS
265  if (oc.exists("speed.offset")) {
266  const SUMOReal speedOffset = oc.getFloat("speed.offset");
267  const SUMOReal speedFactor = oc.getFloat("speed.factor");
268  if (speedOffset != 0 || speedFactor != 1) {
269  PROGRESS_BEGIN_MESSAGE("Applying speed modifications");
270  for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
271  (*i).second->setSpeed(-1, (*i).second->getSpeed() * speedFactor + speedOffset);
272  }
274  }
275  }
276 
277  // CONNECTIONS COMPUTATION
278  //
279  PROGRESS_BEGIN_MESSAGE("Computing node types");
282  //
283  bool buildCrossingsAndWalkingAreas = false;
284  if (oc.getBool("crossings.guess")) {
285  buildCrossingsAndWalkingAreas = true;
286  int crossings = 0;
287  for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
288  crossings += (*i).second->guessCrossings();
289  }
290  WRITE_MESSAGE("Guessed " + toString(crossings) + " pedestrian crossings.");
291  }
292  if (!oc.getBool("no-internal-links") && !buildCrossingsAndWalkingAreas) {
293  // recheck whether we had crossings in the input
294  for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
295  if (i->second->getCrossings().size() > 0) {
296  buildCrossingsAndWalkingAreas = true;
297  break;
298  }
299  }
300  }
301  //
302  PROGRESS_BEGIN_MESSAGE("Computing priorities");
305  //
306  PROGRESS_BEGIN_MESSAGE("Computing approached edges");
307  myEdgeCont.computeEdge2Edges(oc.getBool("no-left-connections"));
309  //
310  if (oc.getBool("roundabouts.guess") || (oc.isDefault("roundabouts.guess") && myHaveSeenRoundabouts)) {
311  PROGRESS_BEGIN_MESSAGE("Guessing and setting roundabouts");
314  }
315  //
316  PROGRESS_BEGIN_MESSAGE("Computing approaching lanes");
317  myEdgeCont.computeLanes2Edges(buildCrossingsAndWalkingAreas);
319  //
320  PROGRESS_BEGIN_MESSAGE("Dividing of lanes on approached lanes");
321  myNodeCont.computeLanes2Lanes(buildCrossingsAndWalkingAreas);
324  //
325  PROGRESS_BEGIN_MESSAGE("Processing turnarounds");
326  if (!oc.getBool("no-turnarounds")) {
327  myEdgeCont.appendTurnarounds(oc.getBool("no-turnarounds.tls"));
328  } else {
329  myEdgeCont.appendTurnarounds(explicitTurnarounds, oc.getBool("no-turnarounds.tls"));
330  }
332  //
333  PROGRESS_BEGIN_MESSAGE("Rechecking of lane endings");
334  myEdgeCont.recheckLanes(buildCrossingsAndWalkingAreas);
336 
337 
338  // GUESS TLS POSITIONS
339  PROGRESS_BEGIN_MESSAGE("Assigning nodes to traffic lights");
340  if (oc.isSet("tls.set")) {
341  std::vector<std::string> tlControlledNodes = oc.getStringVector("tls.set");
343  for (std::vector<std::string>::const_iterator i = tlControlledNodes.begin(); i != tlControlledNodes.end(); ++i) {
344  NBNode* node = myNodeCont.retrieve(*i);
345  if (node == 0) {
346  WRITE_WARNING("Building a tl-logic for node '" + *i + "' is not possible." + "\n The node '" + *i + "' is not known.");
347  } else {
349  }
350  }
351  }
354  //
355  if (oc.getBool("tls.join")) {
356  PROGRESS_BEGIN_MESSAGE("Joining traffic light nodes");
357  myNodeCont.joinTLS(myTLLCont, oc.getFloat("tls.join-dist"));
359  }
360 
361 
362  // COMPUTING RIGHT-OF-WAY AND TRAFFIC LIGHT PROGRAMS
363  //
364  PROGRESS_BEGIN_MESSAGE("Computing traffic light control information");
367  //
368  PROGRESS_BEGIN_MESSAGE("Computing node logics");
371  //
372  PROGRESS_BEGIN_MESSAGE("Computing traffic light logics");
373  std::pair<unsigned int, unsigned int> numbers = myTLLCont.computeLogics(myEdgeCont, oc);
375  std::string progCount = "";
376  if (numbers.first != numbers.second) {
377  progCount = "(" + toString(numbers.second) + " programs) ";
378  }
379  WRITE_MESSAGE(" " + toString(numbers.first) + " traffic light(s) " + progCount + "computed.");
380  //
381  if (oc.isSet("street-sign-output")) {
382  PROGRESS_BEGIN_MESSAGE("Generating street signs");
385  }
386 
387  // FINISHING INNER EDGES
388  if (!oc.getBool("no-internal-links")) {
389  PROGRESS_BEGIN_MESSAGE("Building inner edges");
390  for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
391  (*i).second->sortOutgoingConnectionsByIndex();
392  }
393  // walking areas shall only be built if crossings are wished as well
394  for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
395  (*i).second->buildInnerEdges(buildCrossingsAndWalkingAreas);
396  }
398  }
399 
400 
401  // report
402  WRITE_MESSAGE("-----------------------------------------------------");
403  WRITE_MESSAGE("Summary:");
405  WRITE_MESSAGE(" Network boundaries:");
406  WRITE_MESSAGE(" Original boundary : " + toString(geoConvHelper.getOrigBoundary()));
407  WRITE_MESSAGE(" Applied offset : " + toString(geoConvHelper.getOffsetBase()));
408  WRITE_MESSAGE(" Converted boundary : " + toString(geoConvHelper.getConvBoundary()));
409  WRITE_MESSAGE("-----------------------------------------------------");
411  // report on very large networks
412  if (MAX2(geoConvHelper.getConvBoundary().xmax(), geoConvHelper.getConvBoundary().ymax()) > 1000000 ||
413  MIN2(geoConvHelper.getConvBoundary().xmin(), geoConvHelper.getConvBoundary().ymin()) < -1000000) {
414  WRITE_WARNING("Network contains very large coordinates and will probably flicker in the GUI. Check for outlying nodes and make sure the network is shifted to the coordinate origin");
415  }
416 }
417 
418 
419 void
421  PROGRESS_BEGIN_MESSAGE("Moving network to origin");
422  Boundary boundary = geoConvHelper.getConvBoundary();
423  const SUMOReal x = -boundary.xmin();
424  const SUMOReal y = -boundary.ymin();
425  for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
426  (*i).second->reshiftPosition(x, y);
427  }
428  for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
429  (*i).second->reshiftPosition(x, y);
430  }
431  for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
432  (*i).second->reshiftPosition(x, y);
433  }
434  geoConvHelper.moveConvertedBy(x, y);
436 }
437 
438 
439 bool
440 NBNetBuilder::transformCoordinates(Position& from, bool includeInBoundary, GeoConvHelper* from_srs) {
441  Position orig(from);
442  bool ok = GeoConvHelper::getProcessing().x2cartesian(from, includeInBoundary);
443 #ifdef HAVE_INTERNAL
444  if (ok) {
445  const HeightMapper& hm = HeightMapper::get();
446  if (hm.ready()) {
447  if (from_srs != 0 && from_srs->usingGeoProjection()) {
448  from_srs->cartesian2geo(orig);
449  }
450  SUMOReal z = hm.getZ(orig);
451  from = Position(from.x(), from.y(), z);
452  }
453  }
454 #else
455  UNUSED_PARAMETER(from_srs);
456 #endif
457  return ok;
458 }
459 
460 
461 bool
462 NBNetBuilder::transformCoordinates(PositionVector& from, bool includeInBoundary, GeoConvHelper* from_srs) {
463  const SUMOReal maxLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
464  if (maxLength > 0 && from.size() > 1) {
465  // transformation to cartesian coordinates must happen before we can check segment length
466  PositionVector copy = from;
467  for (int i = 0; i < (int) from.size(); i++) {
468  transformCoordinates(copy[i], false);
469  }
470  // check lengths and insert new points where needed (in the original
471  // coordinate system)
472  int inserted = 0;
473  for (int i = 0; i < (int)copy.size() - 1; i++) {
474  Position start = from[i + inserted];
475  Position end = from[i + inserted + 1];
476  SUMOReal length = copy[i].distanceTo(copy[i + 1]);
477  const Position step = (end - start) * (maxLength / length);
478  int steps = 0;
479  while (length > maxLength) {
480  length -= maxLength;
481  steps++;
482  from.insertAt(i + inserted + 1, start + (step * steps));
483  inserted++;
484  }
485  }
486  // now perform the transformation again so that height mapping can be
487  // performed for the new points
488  }
489  bool ok = true;
490  for (int i = 0; i < (int) from.size(); i++) {
491  ok = ok && transformCoordinates(from[i], includeInBoundary, from_srs);
492  }
493  return ok;
494 }
495 /****************************************************************************/