SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBHeightMapper.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Set z-values for all network positions based on data from a height map
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
12 // Copyright (C) 2011-2014 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <string>
35 #include <utils/common/ToString.h>
38 #include <utils/geom/GeomHelper.h>
39 #include "NBHeightMapper.h"
41 #include <utils/common/RGBColor.h>
43 
44 #ifdef HAVE_GDAL
45 #include <ogrsf_frmts.h>
46 #include <ogr_api.h>
47 #endif
48 
49 #ifdef CHECK_MEMORY_LEAKS
50 #include <foreign/nvwa/debug_new.h>
51 #endif // CHECK_MEMORY_LEAKS
52 
53 // ===========================================================================
54 // static members
55 // ===========================================================================
57 
58 // ===========================================================================
59 // method definitions
60 // ===========================================================================
61 
62 
64  myRTree(&Triangle::addSelf)
65 { }
66 
67 
69  clearData();
70 }
71 
72 
73 const NBHeightMapper&
75  return Singleton;
76 }
77 
78 
79 bool
81  return myTriangles.size() > 0;
82 }
83 
84 
85 
87 NBHeightMapper::getZ(const Position& geo) const {
88  if (!ready()) {
89  WRITE_WARNING("Cannot supply height since no height data was loaded");
90  return 0;
91  }
92  // coordinates in degress hence a small search window
93  float minB[2];
94  float maxB[2];
95  minB[0] = (float)geo.x() - 0.00001f;
96  minB[1] = (float)geo.y() - 0.00001f;
97  maxB[0] = (float)geo.x() + 0.00001f;
98  maxB[1] = (float)geo.y() + 0.00001f;
99  QueryResult queryResult;
100  int hits = myRTree.Search(minB, maxB, queryResult);
101  Triangles result = queryResult.triangles;
102  assert(hits == (int)result.size());
103  UNUSED_PARAMETER(hits); // only used for assertion
104 
105  for (Triangles::iterator it = result.begin(); it != result.end(); it++) {
106  const Triangle* triangle = *it;
107  if (triangle->contains(geo)) {
108  return triangle->getZ(geo);
109  }
110  }
111  WRITE_WARNING("Could not get height data for coordinate " + toString(geo));
112  return 0;
113 }
114 
115 
116 void
118  Triangle* triangle = new Triangle(corners);
119  myTriangles.push_back(triangle);
120  Boundary b = corners.getBoxBoundary();
121  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
122  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
123  myRTree.Insert(cmin, cmax, triangle);
124 }
125 
126 
127 void
129  if (oc.isSet("heightmap.shapefiles")) {
130  // parse file(s)
131  std::vector<std::string> files = oc.getStringVector("heightmap.shapefiles");
132  for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
133  PROGRESS_BEGIN_MESSAGE("Parsing from shape-file '" + *file + "'");
134  int numFeatures = Singleton.loadShapeFile(*file);
136  " done (parsed " + toString(numFeatures) +
137  " features, Boundary: " + toString(Singleton.getBoundary()) + ").");
138  }
139  }
140 }
141 
142 
143 int
144 NBHeightMapper::loadShapeFile(const std::string& file) {
145  int numFeatures = 0;
146 #ifndef HAVE_GDAL
147  WRITE_ERROR("Cannot load shape file since SUMO was compiled without GDAL support.");
148  return numFeatures;
149 #else
150  OGRRegisterAll();
151  OGRDataSource* ds = OGRSFDriverRegistrar::Open(file.c_str(), FALSE);
152  if (ds == NULL) {
153  throw ProcessError("Could not open shape file '" + file + "'.");
154  }
155 
156  // begin file parsing
157  OGRLayer* layer = ds->GetLayer(0);
158  layer->ResetReading();
159 
160  // triangle coordinates are stored in WGS84 and later matched with network coordinates in WGS84
161  // build coordinate transformation
162  OGRSpatialReference* sr_src = layer->GetSpatialRef();
163  OGRSpatialReference sr_dest;
164  sr_dest.SetWellKnownGeogCS("WGS84");
165  OGRCoordinateTransformation* toWGS84 = OGRCreateCoordinateTransformation(sr_src, &sr_dest);
166  if (toWGS84 == 0) {
167  WRITE_WARNING("Could not create geocoordinates converter; check whether proj.4 is installed.");
168  }
169 
170  OGRFeature* feature;
171  layer->ResetReading();
172  while ((feature = layer->GetNextFeature()) != NULL) {
173  OGRGeometry* geom = feature->GetGeometryRef();
174  assert(geom != 0);
175 
176  // @todo gracefull handling of shapefiles with unexpected contents or any error handling for that matter
177  assert(std::string(geom->getGeometryName()) == std::string("POLYGON"));
178  // try transform to wgs84
179  geom->transform(toWGS84);
180  OGRLinearRing* cgeom = ((OGRPolygon*) geom)->getExteriorRing();
181  // assume TIN with with 4 points and point0 == point3
182  assert(cgeom->getNumPoints() == 4);
183  PositionVector corners;
184  for (int j = 0; j < 3; j++) {
185  Position pos((SUMOReal) cgeom->getX(j), (SUMOReal) cgeom->getY(j), (SUMOReal) cgeom->getZ(j));
186  corners.push_back(pos);
187  myBoundary.add(pos);
188  }
189  addTriangle(corners);
190  numFeatures++;
191 
192  /*
193  OGRwkbGeometryType gtype = geom->getGeometryType();
194  switch (gtype) {
195  case wkbPolygon: {
196  break;
197  }
198  case wkbPoint: {
199  WRITE_WARNING("got wkbPoint");
200  break;
201  }
202  case wkbLineString: {
203  WRITE_WARNING("got wkbLineString");
204  break;
205  }
206  case wkbMultiPoint: {
207  WRITE_WARNING("got wkbMultiPoint");
208  break;
209  }
210  case wkbMultiLineString: {
211  WRITE_WARNING("got wkbMultiLineString");
212  break;
213  }
214  case wkbMultiPolygon: {
215  WRITE_WARNING("got wkbMultiPolygon");
216  break;
217  }
218  default:
219  WRITE_WARNING("Unsupported shape type occured");
220  break;
221  }
222  */
223  OGRFeature::DestroyFeature(feature);
224  }
225  OGRDataSource::DestroyDataSource(ds);
226  OCTDestroyCoordinateTransformation(toWGS84);
227  OGRCleanupAll();
228  return numFeatures;
229 #endif
230 }
231 
232 
233 void
235  for (Triangles::iterator it = myTriangles.begin(); it != myTriangles.end(); it++) {
236  delete *it;
237  }
238  myTriangles.clear();
239  myBoundary.reset();
240 }
241 
242 
243 // ===========================================================================
244 // Triangle member methods
245 // ===========================================================================
247  myCorners(corners) {
248  assert(myCorners.size() == 3);
249  // @todo assert non-colinearity
250 }
251 
252 
253 void
255  queryResult.triangles.push_back(this);
256 }
257 
258 
259 bool
261  return myCorners.around(pos);
262 }
263 
264 
265 SUMOReal
267  // en.wikipedia.org/wiki/Line-plane_intersection
268  Position p0 = myCorners.front();
269  Position line(0, 0, 1);
270  p0.sub(geo); // p0 - l0
271  Position normal = normalVector();
272  return p0.dotProduct(normal) / line.dotProduct(normal);
273 }
274 
275 
276 Position
278  // @todo maybe cache result to avoid multiple computations?
279  Position side1 = myCorners[1] - myCorners[0];
280  Position side2 = myCorners[2] - myCorners[0];
281  return side1.crossProduct(side2);
282 }
283 
284 
285 /****************************************************************************/
286 
void sub(SUMOReal dx, SUMOReal dy)
Substracts the given position from this one.
Definition: Position.h:139
std::vector< std::string > getStringVector(const std::string &name) const
Returns the list of string-vector-value of the named option (only for Option_String) ...
SUMOReal getZ(const Position &geo) const
returns the projection of the give geoCoordinate (WGS84) onto triangle plane
Triangles myTriangles
bool ready() const
returns whether the NBHeightMapper has data
Position normalVector() const
returns the normal vector for this triangles plane
int loadShapeFile(const std::string &file)
load height data from Arcgis-shape file and returns the number of
SUMOReal getZ(const Position &geo) const
returns height for the given geo coordinate (WGS84)
SUMOReal ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:124
SUMOReal xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:112
Triangle(const PositionVector &corners)
void addTriangle(PositionVector corners)
adds one triangles worth of height data
void clearData()
clears loaded data
static NBHeightMapper Singleton
the singleton instance
NBHeightMapper()
private constructor and destructor (Singleton)
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:39
SUMOReal xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:118
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static const NBHeightMapper & get()
return the singleton instance (maybe 0)
class for cirumventing the const-restriction of RTree::Search-context
static void loadIfSet(OptionsCont &oc)
loads heigh map data if any loading options are set
TRIANGLE_RTREE_QUAL myRTree
The RTree for spatial queries.
Position crossProduct(const Position &pos)
returns the cross product between this point and the second one
Definition: Position.h:250
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
A list of positions.
std::vector< const Triangle * > Triangles
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:202
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
Definition: MsgHandler.cpp:62
bool contains(const Position &pos) const
checks whether pos lies within triangle (only checks x,y)
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:53
Boundary myBoundary
convex boundary of all known triangles;
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
void add(SUMOReal x, SUMOReal y)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:76
void reset()
Resets the boundary.
Definition: Boundary.cpp:66
SUMOReal dotProduct(const Position &pos)
returns the dot product (scalar product) between this point and the second one
Definition: Position.h:258
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
PositionVector myCorners
the corners of the triangle
A storage for options typed value containers)
Definition: OptionsCont.h:108
void addSelf(const QueryResult &queryResult) const
callback for RTree search
#define SUMOReal
Definition: config.h:218
SUMOReal ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:130
const Boundary & getBoundary()
returns the convex boundary of all known triangles
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
Set z-values for all network positions based on data from a height map.
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
void endProcessMsg(std::string msg)
Ends a process information.
Definition: MsgHandler.cpp:131