SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NIImporter_ArcView.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // Importer for networks stored in ArcView-shape format
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
14 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 
26 // ===========================================================================
27 // included modules
28 // ===========================================================================
29 #ifdef _MSC_VER
30 #include <windows_config.h>
31 #else
32 #include <config.h>
33 #endif
34 
35 #include <string>
37 #include <utils/common/ToString.h>
41 #include <utils/geom/GeomHelper.h>
42 #include <netbuild/NBNetBuilder.h>
43 #include <netbuild/NBHelpers.h>
44 #include <netbuild/NBEdge.h>
45 #include <netbuild/NBEdgeCont.h>
46 #include <netbuild/NBTypeCont.h>
47 #include <netbuild/NBNode.h>
48 #include <netbuild/NBNodeCont.h>
52 #include "NILoader.h"
53 #include "NIImporter_ArcView.h"
54 
55 #ifdef HAVE_GDAL
56 #include <ogrsf_frmts.h>
57 #endif
58 
59 #ifdef CHECK_MEMORY_LEAKS
60 #include <foreign/nvwa/debug_new.h>
61 #endif // CHECK_MEMORY_LEAKS
62 
63 
64 // ===========================================================================
65 // method definitions
66 // ===========================================================================
67 // ---------------------------------------------------------------------------
68 // static methods (interface in this case)
69 // ---------------------------------------------------------------------------
70 void
72  if (!oc.isSet("shapefile-prefix")) {
73  return;
74  }
75  // check whether the correct set of entries is given
76  // and compute both file names
77  std::string dbf_file = oc.getString("shapefile-prefix") + ".dbf";
78  std::string shp_file = oc.getString("shapefile-prefix") + ".shp";
79  std::string shx_file = oc.getString("shapefile-prefix") + ".shx";
80  // check whether the files do exist
81  if (!FileHelpers::exists(dbf_file)) {
82  WRITE_ERROR("File not found: " + dbf_file);
83  }
84  if (!FileHelpers::exists(shp_file)) {
85  WRITE_ERROR("File not found: " + shp_file);
86  }
87  if (!FileHelpers::exists(shx_file)) {
88  WRITE_ERROR("File not found: " + shx_file);
89  }
90  if (MsgHandler::getErrorInstance()->wasInformed()) {
91  return;
92  }
93  // load the arcview files
94  NIImporter_ArcView loader(oc,
95  nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(),
96  dbf_file, shp_file, oc.getBool("speed-in-kmh"));
97  loader.load();
98 }
99 
100 
101 
102 // ---------------------------------------------------------------------------
103 // loader methods
104 // ---------------------------------------------------------------------------
106  NBNodeCont& nc,
107  NBEdgeCont& ec,
108  NBTypeCont& tc,
109  const std::string& dbf_name,
110  const std::string& shp_name,
111  bool speedInKMH)
112  : myOptions(oc), mySHPName(shp_name),
113  myNameAddition(0),
114  myNodeCont(nc), myEdgeCont(ec), myTypeCont(tc),
115  mySpeedInKMH(speedInKMH),
116  myRunningNodeID(0) {
117  UNUSED_PARAMETER(dbf_name);
118 }
119 
120 
122 
123 
124 void
126 #ifdef HAVE_GDAL
127  PROGRESS_BEGIN_MESSAGE("Loading data from '" + mySHPName + "'");
128  OGRRegisterAll();
129  OGRDataSource* poDS = OGRSFDriverRegistrar::Open(mySHPName.c_str(), FALSE);
130  if (poDS == NULL) {
131  WRITE_ERROR("Could not open shape description '" + mySHPName + "'.");
132  return;
133  }
134 
135  // begin file parsing
136  OGRLayer* poLayer = poDS->GetLayer(0);
137  poLayer->ResetReading();
138 
139  // build coordinate transformation
140  OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
141  OGRSpatialReference destTransf;
142  // use wgs84 as destination
143  destTransf.SetWellKnownGeogCS("WGS84");
144  OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(origTransf, &destTransf);
145  if (poCT == NULL) {
146  if (myOptions.isSet("shapefile.guess-projection")) {
147  OGRSpatialReference origTransf2;
148  origTransf2.SetWellKnownGeogCS("WGS84");
149  poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
150  }
151  if (poCT == 0) {
152  WRITE_WARNING("Could not create geocoordinates converter; check whether proj.4 is installed.");
153  }
154  }
155 
156  OGRFeature* poFeature;
157  poLayer->ResetReading();
158  while ((poFeature = poLayer->GetNextFeature()) != NULL) {
159  // read in edge attributes
160  std::string id, name, from_node, to_node;
161  if (!getStringEntry(poFeature, "shapefile.street-id", "LINK_ID", true, id)) {
162  WRITE_ERROR("Needed field '" + id + "' (from node id) is missing.");
163  }
164  if (id == "") {
165  WRITE_ERROR("Could not obtain edge id.");
166  return;
167  }
168 
169  getStringEntry(poFeature, "shapefile.street-id", "ST_NAME", true, name);
170  name = StringUtils::replace(name, "&", "&amp;");
171 
172  if (!getStringEntry(poFeature, "shapefile.from-id", "REF_IN_ID", true, from_node)) {
173  WRITE_ERROR("Needed field '" + from_node + "' (from node id) is missing.");
174  }
175  if (!getStringEntry(poFeature, "shapefile.to-id", "NREF_IN_ID", true, to_node)) {
176  WRITE_ERROR("Needed field '" + to_node + "' (to node id) is missing.");
177  }
178 
179  if (from_node == "" || to_node == "") {
180  from_node = toString(myRunningNodeID++);
181  to_node = toString(myRunningNodeID++);
182  }
183 
184  std::string type;
185  if (myOptions.isSet("shapefile.type-id") && poFeature->GetFieldIndex(myOptions.getString("shapefile.type-id").c_str()) >= 0) {
186  type = poFeature->GetFieldAsString(myOptions.getString("shapefile.type-id").c_str());
187  } else if (poFeature->GetFieldIndex("ST_TYP_AFT") >= 0) {
188  type = poFeature->GetFieldAsString("ST_TYP_AFT");
189  }
190  SUMOReal width = myTypeCont.getWidth(type);
191  SUMOReal speed = getSpeed(*poFeature, id);
192  unsigned int nolanes = getLaneNo(*poFeature, id, speed);
193  int priority = getPriority(*poFeature, id);
194  if (nolanes == 0 || speed == 0) {
195  if (myOptions.getBool("shapefile.use-defaults-on-failure")) {
196  nolanes = myTypeCont.getNumLanes("");
197  speed = myTypeCont.getSpeed("");
198  } else {
199  OGRFeature::DestroyFeature(poFeature);
200  WRITE_ERROR("The description seems to be invalid. Please recheck usage of types.");
201  return;
202  }
203  }
204  if (mySpeedInKMH) {
205  speed = speed / (SUMOReal) 3.6;
206  }
207 
208 
209  // read in the geometry
210  OGRGeometry* poGeometry = poFeature->GetGeometryRef();
211  OGRwkbGeometryType gtype = poGeometry->getGeometryType();
212  assert(gtype == wkbLineString);
213  UNUSED_PARAMETER(gtype); // ony used for assertion
214  OGRLineString* cgeom = (OGRLineString*) poGeometry;
215  if (poCT != 0) {
216  // try transform to wgs84
217  cgeom->transform(poCT);
218  }
219 
220  PositionVector shape;
221  for (int j = 0; j < cgeom->getNumPoints(); j++) {
222  Position pos((SUMOReal) cgeom->getX(j), (SUMOReal) cgeom->getY(j));
224  WRITE_WARNING("Unable to project coordinates for edge '" + id + "'.");
225  }
226  shape.push_back_noDoublePos(pos);
227  }
228 
229  // build from-node
230  NBNode* from = myNodeCont.retrieve(from_node);
231  if (from == 0) {
232  Position from_pos = shape[0];
233  from = myNodeCont.retrieve(from_pos);
234  if (from == 0) {
235  from = new NBNode(from_node, from_pos);
236  if (!myNodeCont.insert(from)) {
237  WRITE_ERROR("Node '" + from_node + "' could not be added");
238  delete from;
239  continue;
240  }
241  }
242  }
243  // build to-node
244  NBNode* to = myNodeCont.retrieve(to_node);
245  if (to == 0) {
246  Position to_pos = shape[-1];
247  to = myNodeCont.retrieve(to_pos);
248  if (to == 0) {
249  to = new NBNode(to_node, to_pos);
250  if (!myNodeCont.insert(to)) {
251  WRITE_ERROR("Node '" + to_node + "' could not be added");
252  delete to;
253  continue;
254  }
255  }
256  }
257 
258  if (from == to) {
259  WRITE_WARNING("Edge '" + id + "' connects identical nodes, skipping.");
260  continue;
261  }
262 
263  // retrieve the information whether the street is bi-directional
264  std::string dir;
265  int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL");
266  if (index >= 0 && poFeature->IsFieldSet(index)) {
267  dir = poFeature->GetFieldAsString(index);
268  }
269  // add positive direction if wanted
270  if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) {
271  if (myEdgeCont.retrieve(id) == 0) {
272  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
273  NBEdge* edge = new NBEdge(id, from, to, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape, "", spread);
274  myEdgeCont.insert(edge);
275  checkSpread(edge);
276  }
277  }
278  // add negative direction if wanted
279  if (dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) {
280  id = "-" + id;
281  if (myEdgeCont.retrieve(id) == 0) {
282  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
283  NBEdge* edge = new NBEdge(id, to, from, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), "", spread);
284  myEdgeCont.insert(edge);
285  checkSpread(edge);
286  }
287  }
288  //
289  OGRFeature::DestroyFeature(poFeature);
290  }
292 #else
293  WRITE_ERROR("SUMO was compiled without GDAL support.");
294 #endif
295 }
296 
297 #ifdef HAVE_GDAL
298 SUMOReal
299 NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) {
300  if (myOptions.isSet("shapefile.type-id")) {
301  return myTypeCont.getSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
302  }
303  // try to get definitions as to be found in SUMO-XML-definitions
304  // idea by John Michael Calandrino
305  int index = poFeature.GetDefnRef()->GetFieldIndex("speed");
306  if (index >= 0 && poFeature.IsFieldSet(index)) {
307  return (SUMOReal) poFeature.GetFieldAsDouble(index);
308  }
309  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED");
310  if (index >= 0 && poFeature.IsFieldSet(index)) {
311  return (SUMOReal) poFeature.GetFieldAsDouble(index);
312  }
313  // try to get the NavTech-information
314  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT");
315  if (index >= 0 && poFeature.IsFieldSet(index)) {
316  std::string def = poFeature.GetFieldAsString(index);
317  return NINavTeqHelper::getSpeed(edgeid, def);
318  }
319  return -1;
320 }
321 
322 
323 unsigned int
324 NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid,
325  SUMOReal speed) {
326  if (myOptions.isSet("shapefile.type-id")) {
327  return (unsigned int) myTypeCont.getNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
328  }
329  // try to get definitions as to be found in SUMO-XML-definitions
330  // idea by John Michael Calandrino
331  int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes");
332  if (index >= 0 && poFeature.IsFieldSet(index)) {
333  return (unsigned int) poFeature.GetFieldAsInteger(index);
334  }
335  index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES");
336  if (index >= 0 && poFeature.IsFieldSet(index)) {
337  return (unsigned int) poFeature.GetFieldAsInteger(index);
338  }
339  index = poFeature.GetDefnRef()->GetFieldIndex("rnol");
340  if (index >= 0 && poFeature.IsFieldSet(index)) {
341  return (unsigned int) poFeature.GetFieldAsInteger(index);
342  }
343  index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT");
344  if (index >= 0 && poFeature.IsFieldSet(index)) {
345  std::string def = poFeature.GetFieldAsString(index);
346  return NINavTeqHelper::getLaneNumber(edgeid, def, speed);
347  }
348  return 0;
349 }
350 
351 
352 int
353 NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) {
354  if (myOptions.isSet("shapefile.type-id")) {
355  return myTypeCont.getPriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
356  }
357  // try to get definitions as to be found in SUMO-XML-definitions
358  // idea by John Michael Calandrino
359  int index = poFeature.GetDefnRef()->GetFieldIndex("priority");
360  if (index >= 0 && poFeature.IsFieldSet(index)) {
361  return poFeature.GetFieldAsInteger(index);
362  }
363  index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY");
364  if (index >= 0 && poFeature.IsFieldSet(index)) {
365  return poFeature.GetFieldAsInteger(index);
366  }
367  // try to determine priority from NavTechs FUNC_CLASS attribute
368  index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS");
369  if (index >= 0 && poFeature.IsFieldSet(index)) {
370  return poFeature.GetFieldAsInteger(index);
371  }
372  return 0;
373 }
374 
375 void
376 NIImporter_ArcView::checkSpread(NBEdge* e) {
377  NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode());
378  if (ret != 0) {
381  }
382 }
383 
384 bool
385 NIImporter_ArcView::getStringEntry(OGRFeature* poFeature, const std::string& optionName, const char* defaultName, bool prune, std::string& into) {
386  std::string v(defaultName);
387  if (myOptions.isSet(optionName)) {
388  v = myOptions.getString(optionName);
389  }
390  if (poFeature->GetFieldIndex(v.c_str()) < 0) {
391  if (myOptions.isSet(optionName)) {
392  into = v;
393  return false;
394  }
395  into = "";
396  return true;
397  }
398  into = poFeature->GetFieldAsString((char*)v.c_str());
399  if (prune) {
400  into = StringUtils::prune(into);
401  }
402  return true;
403 }
404 
405 
406 
407 #endif
408 
409 
410 
411 /****************************************************************************/
412 
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:80
NBTypeCont & getTypeCont()
Returns the type container.
Definition: NBNetBuilder.h:170
~NIImporter_ArcView()
Destructor.
static bool transformCoordinates(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=0)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
int myRunningNodeID
A running number to assure unique node ids.
std::string mySHPName
The name of the shape file.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
NBTypeCont & myTypeCont
The container to get the types from.
The representation of a single edge during network building.
Definition: NBEdge.h:71
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given ArcView Shape files.
const OptionsCont & myOptions
The options to use.
void load()
Loads the shape files.
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:203
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:38
SUMOReal getWidth(const std::string &type) const
Returns the lane width for the given type [m/s].
Definition: NBTypeCont.cpp:134
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:196
PositionVector reverse() const
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
SUMOReal getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:104
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:164
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
int getNumLanes(const std::string &type) const
Returns the number of lanes for the given type.
Definition: NBTypeCont.cpp:98
NBEdgeCont & getEdgeCont()
Returns the edge container.
Definition: NBNetBuilder.h:154
A list of positions.
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:110
static bool exists(std::string path)
Checks whether the given file exists.
Definition: FileHelpers.cpp:57
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:66
Importer for networks stored in ArcView-shape format.
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:198
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:52
NBEdge * getConnectionTo(NBNode *n) const
Definition: NBNode.cpp:1338
static unsigned int getLaneNumber(const std::string &id, const std::string &laneNoS, SUMOReal speed)
Returns the lane number evaluating the given Navteq-description.
static SUMOReal getSpeed(const std::string &id, const std::string &speedClassS)
Returns the speed evaluating the given Navteq-description.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:201
static std::string replace(std::string str, const char *what, const char *by)
NIImporter_ArcView(const OptionsCont &oc, NBNodeCont &nc, NBEdgeCont &ec, NBTypeCont &tc, const std::string &dbf_name, const std::string &shp_name, bool speedInKMH)
Constructor.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:362
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:56
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:251
NBNodeCont & getNodeCont()
Returns the node container.
Definition: NBNetBuilder.h:162
Instance responsible for building networks.
Definition: NBNetBuilder.h:113
NBNodeCont & myNodeCont
The container to add nodes to.
A storage for options typed value containers)
Definition: OptionsCont.h:108
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:79
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge's lateral offset shal...
Represents a single node (junction) during network building.
Definition: NBNode.h:74
#define SUMOReal
Definition: config.h:215
void push_back_noDoublePos(const Position &p)
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:124
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:64
NBEdgeCont & myEdgeCont
The container to add edges to.
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:199
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:484
bool mySpeedInKMH
Whether the speed is given in km/h.
A storage for available types of edges.
Definition: NBTypeCont.h:56
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:354