SUMO - Simulation of Urban MObility
NIImporter_ArcView.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2017 German Aerospace Center (DLR) and others.
4 /****************************************************************************/
5 //
6 // This program and the accompanying materials
7 // are made available under the terms of the Eclipse Public License v2.0
8 // which accompanies this distribution, and is available at
9 // http://www.eclipse.org/legal/epl-v20.html
10 //
11 /****************************************************************************/
21 // Importer for networks stored in ArcView-shape format
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <string>
36 #include <utils/common/ToString.h>
40 #include <utils/geom/GeomHelper.h>
41 #include <netbuild/NBNetBuilder.h>
42 #include <netbuild/NBHelpers.h>
43 #include <netbuild/NBEdge.h>
44 #include <netbuild/NBEdgeCont.h>
45 #include <netbuild/NBTypeCont.h>
46 #include <netbuild/NBNode.h>
47 #include <netbuild/NBNodeCont.h>
51 #include "NILoader.h"
52 #include "NIImporter_ArcView.h"
53 
54 #ifdef HAVE_GDAL
55 #if __GNUC__ > 3
56 #pragma GCC diagnostic push
57 #pragma GCC diagnostic ignored "-Wpedantic"
58 #endif
59 #include <ogrsf_frmts.h>
60 #if __GNUC__ > 3
61 #pragma GCC diagnostic pop
62 #endif
63 #endif
64 
65 
66 // ===========================================================================
67 // method definitions
68 // ===========================================================================
69 // ---------------------------------------------------------------------------
70 // static methods (interface in this case)
71 // ---------------------------------------------------------------------------
72 void
74  if (!oc.isSet("shapefile-prefix")) {
75  return;
76  }
77  // check whether the correct set of entries is given
78  // and compute both file names
79  std::string dbf_file = oc.getString("shapefile-prefix") + ".dbf";
80  std::string shp_file = oc.getString("shapefile-prefix") + ".shp";
81  std::string shx_file = oc.getString("shapefile-prefix") + ".shx";
82  // check whether the files do exist
83  if (!FileHelpers::isReadable(dbf_file)) {
84  WRITE_ERROR("File not accessible: " + dbf_file);
85  }
86  if (!FileHelpers::isReadable(shp_file)) {
87  WRITE_ERROR("File not accessible: " + shp_file);
88  }
89  if (!FileHelpers::isReadable(shx_file)) {
90  WRITE_ERROR("File not accessible: " + shx_file);
91  }
92  if (MsgHandler::getErrorInstance()->wasInformed()) {
93  return;
94  }
95  // load the arcview files
96  NIImporter_ArcView loader(oc,
97  nb.getNodeCont(), nb.getEdgeCont(), nb.getTypeCont(),
98  dbf_file, shp_file, oc.getBool("speed-in-kmh"));
99  loader.load();
100 }
101 
102 
103 
104 // ---------------------------------------------------------------------------
105 // loader methods
106 // ---------------------------------------------------------------------------
108  NBNodeCont& nc,
109  NBEdgeCont& ec,
110  NBTypeCont& tc,
111  const std::string& dbf_name,
112  const std::string& shp_name,
113  bool speedInKMH)
114  : myOptions(oc), mySHPName(shp_name),
115  myNameAddition(0),
116  myNodeCont(nc), myEdgeCont(ec), myTypeCont(tc),
117  mySpeedInKMH(speedInKMH),
118  myRunningNodeID(0) {
119  UNUSED_PARAMETER(dbf_name);
120 }
121 
122 
124 
125 
126 void
128 #ifdef HAVE_GDAL
129  PROGRESS_BEGIN_MESSAGE("Loading data from '" + mySHPName + "'");
130 #if GDAL_VERSION_MAJOR < 2
131  OGRRegisterAll();
132  OGRDataSource* poDS = OGRSFDriverRegistrar::Open(mySHPName.c_str(), FALSE);
133 #else
134  GDALAllRegister();
135  GDALDataset* poDS = (GDALDataset*)GDALOpenEx(mySHPName.c_str(), GDAL_OF_VECTOR | GA_ReadOnly, NULL, NULL, NULL);
136 #endif
137  if (poDS == NULL) {
138  WRITE_ERROR("Could not open shape description '" + mySHPName + "'.");
139  return;
140  }
141 
142  // begin file parsing
143  OGRLayer* poLayer = poDS->GetLayer(0);
144  poLayer->ResetReading();
145 
146  // build coordinate transformation
147  OGRSpatialReference* origTransf = poLayer->GetSpatialRef();
148  OGRSpatialReference destTransf;
149  // use wgs84 as destination
150  destTransf.SetWellKnownGeogCS("WGS84");
151  OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(origTransf, &destTransf);
152  if (poCT == NULL) {
153  if (myOptions.isSet("shapefile.guess-projection")) {
154  OGRSpatialReference origTransf2;
155  origTransf2.SetWellKnownGeogCS("WGS84");
156  poCT = OGRCreateCoordinateTransformation(&origTransf2, &destTransf);
157  }
158  if (poCT == 0) {
159  WRITE_WARNING("Could not create geocoordinates converter; check whether proj.4 is installed.");
160  }
161  }
162 
163  const bool saveOrigIDs = OptionsCont::getOptions().getBool("output.original-names");
164  OGRFeature* poFeature;
165  poLayer->ResetReading();
166  while ((poFeature = poLayer->GetNextFeature()) != NULL) {
167  // read in edge attributes
168  std::string id, name, from_node, to_node;
169  if (!getStringEntry(poFeature, "shapefile.street-id", "LINK_ID", true, id)) {
170  WRITE_ERROR("Needed field '" + id + "' (from node id) is missing.");
171  }
172  if (id == "") {
173  WRITE_ERROR("Could not obtain edge id.");
174  return;
175  }
176 
177  getStringEntry(poFeature, "shapefile.street-id", "ST_NAME", true, name);
178  name = StringUtils::replace(name, "&", "&amp;");
179 
180  if (!getStringEntry(poFeature, "shapefile.from-id", "REF_IN_ID", true, from_node)) {
181  WRITE_ERROR("Needed field '" + from_node + "' (from node id) is missing.");
182  }
183  if (!getStringEntry(poFeature, "shapefile.to-id", "NREF_IN_ID", true, to_node)) {
184  WRITE_ERROR("Needed field '" + to_node + "' (to node id) is missing.");
185  }
186 
187  if (from_node == "" || to_node == "") {
188  from_node = toString(myRunningNodeID++);
189  to_node = toString(myRunningNodeID++);
190  }
191 
192  std::string type;
193  if (myOptions.isSet("shapefile.type-id") && poFeature->GetFieldIndex(myOptions.getString("shapefile.type-id").c_str()) >= 0) {
194  type = poFeature->GetFieldAsString(myOptions.getString("shapefile.type-id").c_str());
195  } else if (poFeature->GetFieldIndex("ST_TYP_AFT") >= 0) {
196  type = poFeature->GetFieldAsString("ST_TYP_AFT");
197  }
198  double width = myTypeCont.getWidth(type);
199  double speed = getSpeed(*poFeature, id);
200  int nolanes = getLaneNo(*poFeature, id, speed);
201  int priority = getPriority(*poFeature, id);
202  if (nolanes == 0 || speed == 0) {
203  if (myOptions.getBool("shapefile.use-defaults-on-failure")) {
204  nolanes = myTypeCont.getNumLanes("");
205  speed = myTypeCont.getSpeed("");
206  } else {
207  OGRFeature::DestroyFeature(poFeature);
208  WRITE_ERROR("Required field 'nolanes' or 'speed' is missing (add fields or set option --shapefile.use-defaults-on-failure).");
209  return;
210  }
211  }
212  if (mySpeedInKMH) {
213  speed = speed / (double) 3.6;
214  }
215 
216 
217  // read in the geometry
218  OGRGeometry* poGeometry = poFeature->GetGeometryRef();
219  OGRwkbGeometryType gtype = poGeometry->getGeometryType();
220  if (gtype != wkbLineString) {
221  OGRFeature::DestroyFeature(poFeature);
222  WRITE_ERROR("Road geometry must be of type 'linestring'.");
223  return;
224  }
225  OGRLineString* cgeom = (OGRLineString*) poGeometry;
226  if (poCT != 0) {
227  // try transform to wgs84
228  cgeom->transform(poCT);
229  }
230 
231  PositionVector shape;
232  for (int j = 0; j < cgeom->getNumPoints(); j++) {
233  Position pos((double) cgeom->getX(j), (double) cgeom->getY(j));
235  WRITE_WARNING("Unable to project coordinates for edge '" + id + "'.");
236  }
237  shape.push_back_noDoublePos(pos);
238  }
239 
240  // build from-node
241  NBNode* from = myNodeCont.retrieve(from_node);
242  if (from == 0) {
243  Position from_pos = shape[0];
244  from = myNodeCont.retrieve(from_pos);
245  if (from == 0) {
246  from = new NBNode(from_node, from_pos);
247  if (!myNodeCont.insert(from)) {
248  WRITE_ERROR("Node '" + from_node + "' could not be added");
249  delete from;
250  continue;
251  }
252  }
253  }
254  // build to-node
255  NBNode* to = myNodeCont.retrieve(to_node);
256  if (to == 0) {
257  Position to_pos = shape[-1];
258  to = myNodeCont.retrieve(to_pos);
259  if (to == 0) {
260  to = new NBNode(to_node, to_pos);
261  if (!myNodeCont.insert(to)) {
262  WRITE_ERROR("Node '" + to_node + "' could not be added");
263  delete to;
264  continue;
265  }
266  }
267  }
268 
269  if (from == to) {
270  WRITE_WARNING("Edge '" + id + "' connects identical nodes, skipping.");
271  continue;
272  }
273 
274  // retrieve the information whether the street is bi-directional
275  std::string dir;
276  int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL");
277  if (index >= 0 && poFeature->IsFieldSet(index)) {
278  dir = poFeature->GetFieldAsString(index);
279  }
280  const std::string origID = saveOrigIDs ? id : "";
281  // add positive direction if wanted
282  if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) {
283  if (myEdgeCont.retrieve(id) == 0) {
284  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
285  NBEdge* edge = new NBEdge(id, from, to, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape, name, origID, spread);
286  myEdgeCont.insert(edge);
287  checkSpread(edge);
288  }
289  }
290  // add negative direction if wanted
291  if (dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) {
292  if (myEdgeCont.retrieve("-" + id) == 0) {
293  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
294  NBEdge* edge = new NBEdge("-" + id, to, from, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), name, origID, spread);
295  myEdgeCont.insert(edge);
296  checkSpread(edge);
297  }
298  }
299  //
300  OGRFeature::DestroyFeature(poFeature);
301  }
302 #if GDAL_VERSION_MAJOR < 2
303  OGRDataSource::DestroyDataSource(poDS);
304 #else
305  GDALClose(poDS);
306 #endif
308 #else
309  WRITE_ERROR("SUMO was compiled without GDAL support.");
310 #endif
311 }
312 
313 #ifdef HAVE_GDAL
314 double
315 NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) {
316  if (myOptions.isSet("shapefile.type-id")) {
317  return myTypeCont.getSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
318  }
319  // try to get definitions as to be found in SUMO-XML-definitions
320  // idea by John Michael Calandrino
321  int index = poFeature.GetDefnRef()->GetFieldIndex("speed");
322  if (index >= 0 && poFeature.IsFieldSet(index)) {
323  return (double) poFeature.GetFieldAsDouble(index);
324  }
325  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED");
326  if (index >= 0 && poFeature.IsFieldSet(index)) {
327  return (double) poFeature.GetFieldAsDouble(index);
328  }
329  // try to get the NavTech-information
330  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT");
331  if (index >= 0 && poFeature.IsFieldSet(index)) {
332  std::string def = poFeature.GetFieldAsString(index);
333  return NINavTeqHelper::getSpeed(edgeid, def);
334  }
335  return -1;
336 }
337 
338 
339 int
340 NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid,
341  double speed) {
342  if (myOptions.isSet("shapefile.type-id")) {
343  return (int) myTypeCont.getNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
344  }
345  // try to get definitions as to be found in SUMO-XML-definitions
346  // idea by John Michael Calandrino
347  int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes");
348  if (index >= 0 && poFeature.IsFieldSet(index)) {
349  return (int) poFeature.GetFieldAsInteger(index);
350  }
351  index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES");
352  if (index >= 0 && poFeature.IsFieldSet(index)) {
353  return (int) poFeature.GetFieldAsInteger(index);
354  }
355  index = poFeature.GetDefnRef()->GetFieldIndex("rnol");
356  if (index >= 0 && poFeature.IsFieldSet(index)) {
357  return (int) poFeature.GetFieldAsInteger(index);
358  }
359  index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT");
360  if (index >= 0 && poFeature.IsFieldSet(index)) {
361  std::string def = poFeature.GetFieldAsString(index);
362  return NINavTeqHelper::getLaneNumber(edgeid, def, speed);
363  }
364  return 0;
365 }
366 
367 
368 int
369 NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) {
370  if (myOptions.isSet("shapefile.type-id")) {
371  return myTypeCont.getPriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
372  }
373  // try to get definitions as to be found in SUMO-XML-definitions
374  // idea by John Michael Calandrino
375  int index = poFeature.GetDefnRef()->GetFieldIndex("priority");
376  if (index >= 0 && poFeature.IsFieldSet(index)) {
377  return poFeature.GetFieldAsInteger(index);
378  }
379  index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY");
380  if (index >= 0 && poFeature.IsFieldSet(index)) {
381  return poFeature.GetFieldAsInteger(index);
382  }
383  // try to determine priority from NavTechs FUNC_CLASS attribute
384  index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS");
385  if (index >= 0 && poFeature.IsFieldSet(index)) {
386  return poFeature.GetFieldAsInteger(index);
387  }
388  return 0;
389 }
390 
391 void
392 NIImporter_ArcView::checkSpread(NBEdge* e) {
393  NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode());
394  if (ret != 0) {
397  }
398 }
399 
400 bool
401 NIImporter_ArcView::getStringEntry(OGRFeature* poFeature, const std::string& optionName, const char* defaultName, bool prune, std::string& into) {
402  std::string v(defaultName);
403  if (myOptions.isSet(optionName)) {
404  v = myOptions.getString(optionName);
405  }
406  if (poFeature->GetFieldIndex(v.c_str()) < 0) {
407  if (myOptions.isSet(optionName)) {
408  into = v;
409  return false;
410  }
411  into = "";
412  return true;
413  }
414  into = poFeature->GetFieldAsString((char*)v.c_str());
415  if (prune) {
416  into = StringUtils::prune(into);
417  }
418  return true;
419 }
420 
421 
422 
423 #endif
424 
425 
426 
427 /****************************************************************************/
428 
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:108
int myNameAddition
A running number to assure unique edge ids.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:75
double getSpeed(const std::string &type) const
Returns the maximal velocity for the given type [m/s].
Definition: NBTypeCont.cpp:180
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:166
~NIImporter_ArcView()
Destructor.
static bool transformCoordinate(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.
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:53
static double getSpeed(const std::string &id, const std::string &speedClassS)
Returns the speed evaluating the given Navteq-description.
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:70
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:186
const OptionsCont & myOptions
The options to use.
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:257
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:174
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:39
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:199
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:64
double getWidth(const std::string &type) const
Returns the lane width for the given type [m].
Definition: NBTypeCont.cpp:216
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition: NBNode.cpp:1744
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:157
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:55
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:45
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:156
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:201
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
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:51
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:161
Instance responsible for building networks.
Definition: NBNetBuilder.h:115
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:250
A storage for options typed value containers)
Definition: OptionsCont.h:98
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&#39;s lateral offset shal...
Represents a single node (junction) during network building.
Definition: NBNode.h:74
static int getLaneNumber(const std::string &id, const std::string &laneNoS, double speed)
Returns the lane number evaluating the given Navteq-description.
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:426
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:66
NBEdgeCont & myEdgeCont
The container to add edges to.
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:202
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition: NBEdge.cpp:784
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:433
bool mySpeedInKMH
Whether the speed is given in km/h.
A storage for available types of edges.
Definition: NBTypeCont.h:61