SUMO - Simulation of Urban MObility
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.dlr.de/
14 // Copyright (C) 2001-2016 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::isReadable(dbf_file)) {
82  WRITE_ERROR("File not accessible: " + dbf_file);
83  }
84  if (!FileHelpers::isReadable(shp_file)) {
85  WRITE_ERROR("File not accessible: " + shp_file);
86  }
87  if (!FileHelpers::isReadable(shx_file)) {
88  WRITE_ERROR("File not accessible: " + 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 #if GDAL_VERSION_MAJOR < 2
129  OGRRegisterAll();
130  OGRDataSource* poDS = OGRSFDriverRegistrar::Open(mySHPName.c_str(), FALSE);
131 #else
132  GDALAllRegister();
133  GDALDataset* poDS = (GDALDataset*)GDALOpenEx(mySHPName.c_str(), GDAL_OF_VECTOR | GA_ReadOnly, NULL, NULL, NULL);
134 #endif
135  if (poDS == NULL) {
136  WRITE_ERROR("Could not open shape description '" + mySHPName + "'.");
137  return;
138  }
139 
140  // begin file parsing
141  OGRLayer* poLayer = poDS->GetLayer(0);
142  poLayer->ResetReading();
143 
144  // build coordinate transformation
145  OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
146  OGRSpatialReference destTransf;
147  // use wgs84 as destination
148  destTransf.SetWellKnownGeogCS("WGS84");
149  OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(origTransf, &destTransf);
150  if (poCT == NULL) {
151  if (myOptions.isSet("shapefile.guess-projection")) {
152  OGRSpatialReference origTransf2;
153  origTransf2.SetWellKnownGeogCS("WGS84");
154  poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
155  }
156  if (poCT == 0) {
157  WRITE_WARNING("Could not create geocoordinates converter; check whether proj.4 is installed.");
158  }
159  }
160 
161  OGRFeature* poFeature;
162  poLayer->ResetReading();
163  while ((poFeature = poLayer->GetNextFeature()) != NULL) {
164  // read in edge attributes
165  std::string id, name, from_node, to_node;
166  if (!getStringEntry(poFeature, "shapefile.street-id", "LINK_ID", true, id)) {
167  WRITE_ERROR("Needed field '" + id + "' (from node id) is missing.");
168  }
169  if (id == "") {
170  WRITE_ERROR("Could not obtain edge id.");
171  return;
172  }
173 
174  getStringEntry(poFeature, "shapefile.street-id", "ST_NAME", true, name);
175  name = StringUtils::replace(name, "&", "&amp;");
176 
177  if (!getStringEntry(poFeature, "shapefile.from-id", "REF_IN_ID", true, from_node)) {
178  WRITE_ERROR("Needed field '" + from_node + "' (from node id) is missing.");
179  }
180  if (!getStringEntry(poFeature, "shapefile.to-id", "NREF_IN_ID", true, to_node)) {
181  WRITE_ERROR("Needed field '" + to_node + "' (to node id) is missing.");
182  }
183 
184  if (from_node == "" || to_node == "") {
185  from_node = toString(myRunningNodeID++);
186  to_node = toString(myRunningNodeID++);
187  }
188 
189  std::string type;
190  if (myOptions.isSet("shapefile.type-id") && poFeature->GetFieldIndex(myOptions.getString("shapefile.type-id").c_str()) >= 0) {
191  type = poFeature->GetFieldAsString(myOptions.getString("shapefile.type-id").c_str());
192  } else if (poFeature->GetFieldIndex("ST_TYP_AFT") >= 0) {
193  type = poFeature->GetFieldAsString("ST_TYP_AFT");
194  }
195  SUMOReal width = myTypeCont.getWidth(type);
196  SUMOReal speed = getSpeed(*poFeature, id);
197  int nolanes = getLaneNo(*poFeature, id, speed);
198  int priority = getPriority(*poFeature, id);
199  if (nolanes == 0 || speed == 0) {
200  if (myOptions.getBool("shapefile.use-defaults-on-failure")) {
201  nolanes = myTypeCont.getNumLanes("");
202  speed = myTypeCont.getSpeed("");
203  } else {
204  OGRFeature::DestroyFeature(poFeature);
205  WRITE_ERROR("The description seems to be invalid. Please recheck usage of types.");
206  return;
207  }
208  }
209  if (mySpeedInKMH) {
210  speed = speed / (SUMOReal) 3.6;
211  }
212 
213 
214  // read in the geometry
215  OGRGeometry* poGeometry = poFeature->GetGeometryRef();
216  OGRwkbGeometryType gtype = poGeometry->getGeometryType();
217  assert(gtype == wkbLineString);
218  UNUSED_PARAMETER(gtype); // ony used for assertion
219  OGRLineString* cgeom = (OGRLineString*) poGeometry;
220  if (poCT != 0) {
221  // try transform to wgs84
222  cgeom->transform(poCT);
223  }
224 
225  PositionVector shape;
226  for (int j = 0; j < cgeom->getNumPoints(); j++) {
227  Position pos((SUMOReal) cgeom->getX(j), (SUMOReal) cgeom->getY(j));
229  WRITE_WARNING("Unable to project coordinates for edge '" + id + "'.");
230  }
231  shape.push_back_noDoublePos(pos);
232  }
233 
234  // build from-node
235  NBNode* from = myNodeCont.retrieve(from_node);
236  if (from == 0) {
237  Position from_pos = shape[0];
238  from = myNodeCont.retrieve(from_pos);
239  if (from == 0) {
240  from = new NBNode(from_node, from_pos);
241  if (!myNodeCont.insert(from)) {
242  WRITE_ERROR("Node '" + from_node + "' could not be added");
243  delete from;
244  continue;
245  }
246  }
247  }
248  // build to-node
249  NBNode* to = myNodeCont.retrieve(to_node);
250  if (to == 0) {
251  Position to_pos = shape[-1];
252  to = myNodeCont.retrieve(to_pos);
253  if (to == 0) {
254  to = new NBNode(to_node, to_pos);
255  if (!myNodeCont.insert(to)) {
256  WRITE_ERROR("Node '" + to_node + "' could not be added");
257  delete to;
258  continue;
259  }
260  }
261  }
262 
263  if (from == to) {
264  WRITE_WARNING("Edge '" + id + "' connects identical nodes, skipping.");
265  continue;
266  }
267 
268  // retrieve the information whether the street is bi-directional
269  std::string dir;
270  int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL");
271  if (index >= 0 && poFeature->IsFieldSet(index)) {
272  dir = poFeature->GetFieldAsString(index);
273  }
274  // add positive direction if wanted
275  if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) {
276  if (myEdgeCont.retrieve(id) == 0) {
277  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
278  NBEdge* edge = new NBEdge(id, from, to, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape, name, id, spread);
279  myEdgeCont.insert(edge);
280  checkSpread(edge);
281  }
282  }
283  // add negative direction if wanted
284  if (dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) {
285  if (myEdgeCont.retrieve("-" + id) == 0) {
286  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
287  NBEdge* edge = new NBEdge("-" + id, to, from, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), name, id, spread);
288  myEdgeCont.insert(edge);
289  checkSpread(edge);
290  }
291  }
292  //
293  OGRFeature::DestroyFeature(poFeature);
294  }
295 #if GDAL_VERSION_MAJOR < 2
296  OGRDataSource::DestroyDataSource(poDS);
297 #else
298  GDALClose(poDS);
299 #endif
301 #else
302  WRITE_ERROR("SUMO was compiled without GDAL support.");
303 #endif
304 }
305 
306 #ifdef HAVE_GDAL
307 SUMOReal
308 NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) {
309  if (myOptions.isSet("shapefile.type-id")) {
310  return myTypeCont.getSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
311  }
312  // try to get definitions as to be found in SUMO-XML-definitions
313  // idea by John Michael Calandrino
314  int index = poFeature.GetDefnRef()->GetFieldIndex("speed");
315  if (index >= 0 && poFeature.IsFieldSet(index)) {
316  return (SUMOReal) poFeature.GetFieldAsDouble(index);
317  }
318  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED");
319  if (index >= 0 && poFeature.IsFieldSet(index)) {
320  return (SUMOReal) poFeature.GetFieldAsDouble(index);
321  }
322  // try to get the NavTech-information
323  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT");
324  if (index >= 0 && poFeature.IsFieldSet(index)) {
325  std::string def = poFeature.GetFieldAsString(index);
326  return NINavTeqHelper::getSpeed(edgeid, def);
327  }
328  return -1;
329 }
330 
331 
332 int
333 NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid,
334  SUMOReal speed) {
335  if (myOptions.isSet("shapefile.type-id")) {
336  return (int) myTypeCont.getNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
337  }
338  // try to get definitions as to be found in SUMO-XML-definitions
339  // idea by John Michael Calandrino
340  int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes");
341  if (index >= 0 && poFeature.IsFieldSet(index)) {
342  return (int) poFeature.GetFieldAsInteger(index);
343  }
344  index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES");
345  if (index >= 0 && poFeature.IsFieldSet(index)) {
346  return (int) poFeature.GetFieldAsInteger(index);
347  }
348  index = poFeature.GetDefnRef()->GetFieldIndex("rnol");
349  if (index >= 0 && poFeature.IsFieldSet(index)) {
350  return (int) poFeature.GetFieldAsInteger(index);
351  }
352  index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT");
353  if (index >= 0 && poFeature.IsFieldSet(index)) {
354  std::string def = poFeature.GetFieldAsString(index);
355  return NINavTeqHelper::getLaneNumber(edgeid, def, speed);
356  }
357  return 0;
358 }
359 
360 
361 int
362 NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) {
363  if (myOptions.isSet("shapefile.type-id")) {
364  return myTypeCont.getPriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
365  }
366  // try to get definitions as to be found in SUMO-XML-definitions
367  // idea by John Michael Calandrino
368  int index = poFeature.GetDefnRef()->GetFieldIndex("priority");
369  if (index >= 0 && poFeature.IsFieldSet(index)) {
370  return poFeature.GetFieldAsInteger(index);
371  }
372  index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY");
373  if (index >= 0 && poFeature.IsFieldSet(index)) {
374  return poFeature.GetFieldAsInteger(index);
375  }
376  // try to determine priority from NavTechs FUNC_CLASS attribute
377  index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS");
378  if (index >= 0 && poFeature.IsFieldSet(index)) {
379  return poFeature.GetFieldAsInteger(index);
380  }
381  return 0;
382 }
383 
384 void
385 NIImporter_ArcView::checkSpread(NBEdge* e) {
386  NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode());
387  if (ret != 0) {
390  }
391 }
392 
393 bool
394 NIImporter_ArcView::getStringEntry(OGRFeature* poFeature, const std::string& optionName, const char* defaultName, bool prune, std::string& into) {
395  std::string v(defaultName);
396  if (myOptions.isSet(optionName)) {
397  v = myOptions.getString(optionName);
398  }
399  if (poFeature->GetFieldIndex(v.c_str()) < 0) {
400  if (myOptions.isSet(optionName)) {
401  into = v;
402  return false;
403  }
404  into = "";
405  return true;
406  }
407  into = poFeature->GetFieldAsString((char*)v.c_str());
408  if (prune) {
409  into = StringUtils::prune(into);
410  }
411  return true;
412 }
413 
414 
415 
416 #endif
417 
418 
419 
420 /****************************************************************************/
421 
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:110
SUMOReal getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:185
int myNameAddition
A running number to assure unique edge ids.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:80
NBTypeCont & getTypeCont()
Returns the type container.
Definition: NBNetBuilder.h:169
~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.
SUMOReal getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:221
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:58
std::string mySHPName
The name of the shape file.
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.
int getPriority(const std::string &type) const
Returns the priority for the given type.
Definition: NBTypeCont.cpp:191
const OptionsCont & myOptions
The options to use.
void load()
Loads the shape files.
PositionVector reverse() const
reverse position vector
int getNumLanes(const std::string &type) const
Returns the number of lanes for the given type.
Definition: NBTypeCont.cpp:179
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static const SUMOReal UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:240
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:39
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
NBEdge * getConnectionTo(NBNode *n) const
Definition: NBNode.cpp:1745
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:162
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
NBEdgeCont & getEdgeCont()
Returns the edge container.
Definition: NBNetBuilder.h:153
A list of positions.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
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:202
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:55
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:206
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.
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:56
NBNodeCont & getNodeCont()
Returns the node container.
Definition: NBNetBuilder.h:161
Instance responsible for building networks.
Definition: NBNetBuilder.h:112
NBNodeCont & myNodeCont
The container to add nodes to.
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:247
A storage for options typed value containers)
Definition: OptionsCont.h:99
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:81
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge&#39;s lateral offset shal...
Represents a single node (junction) during network building.
Definition: NBNode.h:74
#define SUMOReal
Definition: config.h:213
void push_back_noDoublePos(const Position &p)
insert in back a non double position
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:409
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:63
NBEdgeCont & myEdgeCont
The container to add edges to.
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:203
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:665
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:416
bool mySpeedInKMH
Whether the speed is given in km/h.
A storage for available types of edges.
Definition: NBTypeCont.h:62
static int getLaneNumber(const std::string &id, const std::string &laneNoS, SUMOReal speed)
Returns the lane number evaluating the given Navteq-description.