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.sourceforge.net/
14 // Copyright (C) 2001-2012 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  OGRLineString* cgeom = (OGRLineString*) poGeometry;
214  if (poCT != 0) {
215  // try transform to wgs84
216  cgeom->transform(poCT);
217  }
218 
219  PositionVector shape;
220  for (int j = 0; j < cgeom->getNumPoints(); j++) {
221  Position pos((SUMOReal) cgeom->getX(j), (SUMOReal) cgeom->getY(j));
222  if (!NILoader::transformCoordinates(pos)) {
223  WRITE_WARNING("Unable to project coordinates for edge '" + id + "'.");
224  }
225  shape.push_back_noDoublePos(pos);
226  }
227 
228  // build from-node
229  NBNode* from = myNodeCont.retrieve(from_node);
230  if (from == 0) {
231  Position from_pos = shape[0];
232  from = myNodeCont.retrieve(from_pos);
233  if (from == 0) {
234  from = new NBNode(from_node, from_pos);
235  if (!myNodeCont.insert(from)) {
236  WRITE_ERROR("Node '" + from_node + "' could not be added");
237  delete from;
238  continue;
239  }
240  }
241  }
242  // build to-node
243  NBNode* to = myNodeCont.retrieve(to_node);
244  if (to == 0) {
245  Position to_pos = shape[-1];
246  to = myNodeCont.retrieve(to_pos);
247  if (to == 0) {
248  to = new NBNode(to_node, to_pos);
249  if (!myNodeCont.insert(to)) {
250  WRITE_ERROR("Node '" + to_node + "' could not be added");
251  delete to;
252  continue;
253  }
254  }
255  }
256 
257  if (from == to) {
258  WRITE_WARNING("Edge '" + id + "' connects identical nodes, skipping.");
259  continue;
260  }
261 
262  // retrieve the information whether the street is bi-directional
263  std::string dir;
264  int index = poFeature->GetDefnRef()->GetFieldIndex("DIR_TRAVEL");
265  if (index >= 0 && poFeature->IsFieldSet(index)) {
266  dir = poFeature->GetFieldAsString(index);
267  }
268  // add positive direction if wanted
269  if (dir == "B" || dir == "F" || dir == "" || myOptions.getBool("shapefile.all-bidirectional")) {
270  if (myEdgeCont.retrieve(id) == 0) {
271  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
272  NBEdge* edge = new NBEdge(id, from, to, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape, "", spread);
273  myEdgeCont.insert(edge);
274  checkSpread(edge);
275  }
276  }
277  // add negative direction if wanted
278  if (dir == "B" || dir == "T" || myOptions.getBool("shapefile.all-bidirectional")) {
279  id = "-" + id;
280  if (myEdgeCont.retrieve(id) == 0) {
281  LaneSpreadFunction spread = dir == "B" || dir == "FALSE" ? LANESPREAD_RIGHT : LANESPREAD_CENTER;
282  NBEdge* edge = new NBEdge(id, to, from, type, speed, nolanes, priority, width, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), "", spread);
283  myEdgeCont.insert(edge);
284  checkSpread(edge);
285  }
286  }
287  //
288  OGRFeature::DestroyFeature(poFeature);
289  }
291 #else
292  WRITE_ERROR("SUMO was compiled without GDAL support.");
293 #endif
294 }
295 
296 #ifdef HAVE_GDAL
297 SUMOReal
298 NIImporter_ArcView::getSpeed(OGRFeature& poFeature, const std::string& edgeid) {
299  if (myOptions.isSet("shapefile.type-id")) {
300  return myTypeCont.getSpeed(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
301  }
302  // try to get definitions as to be found in SUMO-XML-definitions
303  // idea by John Michael Calandrino
304  int index = poFeature.GetDefnRef()->GetFieldIndex("speed");
305  if (index >= 0 && poFeature.IsFieldSet(index)) {
306  return (SUMOReal) poFeature.GetFieldAsDouble(index);
307  }
308  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED");
309  if (index >= 0 && poFeature.IsFieldSet(index)) {
310  return (SUMOReal) poFeature.GetFieldAsDouble(index);
311  }
312  // try to get the NavTech-information
313  index = poFeature.GetDefnRef()->GetFieldIndex("SPEED_CAT");
314  if (index >= 0 && poFeature.IsFieldSet(index)) {
315  std::string def = poFeature.GetFieldAsString(index);
316  return NINavTeqHelper::getSpeed(edgeid, def);
317  }
318  return -1;
319 }
320 
321 
322 unsigned int
323 NIImporter_ArcView::getLaneNo(OGRFeature& poFeature, const std::string& edgeid,
324  SUMOReal speed) {
325  if (myOptions.isSet("shapefile.type-id")) {
326  return (unsigned int) myTypeCont.getNumLanes(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
327  }
328  // try to get definitions as to be found in SUMO-XML-definitions
329  // idea by John Michael Calandrino
330  int index = poFeature.GetDefnRef()->GetFieldIndex("nolanes");
331  if (index >= 0 && poFeature.IsFieldSet(index)) {
332  return (unsigned int) poFeature.GetFieldAsInteger(index);
333  }
334  index = poFeature.GetDefnRef()->GetFieldIndex("NOLANES");
335  if (index >= 0 && poFeature.IsFieldSet(index)) {
336  return (unsigned int) poFeature.GetFieldAsInteger(index);
337  }
338  index = poFeature.GetDefnRef()->GetFieldIndex("rnol");
339  if (index >= 0 && poFeature.IsFieldSet(index)) {
340  return (unsigned int) poFeature.GetFieldAsInteger(index);
341  }
342  index = poFeature.GetDefnRef()->GetFieldIndex("LANE_CAT");
343  if (index >= 0 && poFeature.IsFieldSet(index)) {
344  std::string def = poFeature.GetFieldAsString(index);
345  return NINavTeqHelper::getLaneNumber(edgeid, def, speed);
346  }
347  return 0;
348 }
349 
350 
351 int
352 NIImporter_ArcView::getPriority(OGRFeature& poFeature, const std::string& /*edgeid*/) {
353  if (myOptions.isSet("shapefile.type-id")) {
354  return myTypeCont.getPriority(poFeature.GetFieldAsString((char*)(myOptions.getString("shapefile.type-id").c_str())));
355  }
356  // try to get definitions as to be found in SUMO-XML-definitions
357  // idea by John Michael Calandrino
358  int index = poFeature.GetDefnRef()->GetFieldIndex("priority");
359  if (index >= 0 && poFeature.IsFieldSet(index)) {
360  return poFeature.GetFieldAsInteger(index);
361  }
362  index = poFeature.GetDefnRef()->GetFieldIndex("PRIORITY");
363  if (index >= 0 && poFeature.IsFieldSet(index)) {
364  return poFeature.GetFieldAsInteger(index);
365  }
366  // try to determine priority from NavTechs FUNC_CLASS attribute
367  index = poFeature.GetDefnRef()->GetFieldIndex("FUNC_CLASS");
368  if (index >= 0 && poFeature.IsFieldSet(index)) {
369  return poFeature.GetFieldAsInteger(index);
370  }
371  return 0;
372 }
373 
374 void
375 NIImporter_ArcView::checkSpread(NBEdge* e) {
376  NBEdge* ret = e->getToNode()->getConnectionTo(e->getFromNode());
377  if (ret != 0) {
380  }
381 }
382 
383 bool
384 NIImporter_ArcView::getStringEntry(OGRFeature* poFeature, const std::string& optionName, const char* defaultName, bool prune, std::string& into) {
385  std::string v(defaultName);
386  if (myOptions.isSet(optionName)) {
387  v = myOptions.getString(optionName);
388  }
389  if (poFeature->GetFieldIndex(v.c_str()) < 0) {
390  if (myOptions.isSet(optionName)) {
391  into = v;
392  return false;
393  }
394  into = "";
395  return true;
396  }
397  into = poFeature->GetFieldAsString((char*)v.c_str());
398  if (prune) {
399  into = StringUtils::prune(into);
400  }
401  return true;
402 }
403 
404 
405 
406 #endif
407 
408 
409 
410 /****************************************************************************/
411