37#pragma warning(disable: 4435 5219 5220)
40#pragma GCC diagnostic push
41#pragma GCC diagnostic ignored "-Wpedantic"
43#include <gdal_version.h>
44#include <ogrsf_frmts.h>
48#pragma GCC diagnostic pop
89 WRITE_WARNING(
TL(
"Cannot supply height since no height data was loaded"));
93 const Boundary& boundary = item.boundary;
94 float* raster = item.raster;
103 if (item.transform !=
nullptr) {
110 item.transform->Transform(1, &x, &y);
115 const int xSize = item.xSize;
119 corners.push_back(
Position(floor(normX) + 0.5, floor(normY) + 0.5, raster[(int)normY * xSize + (
int)normX]));
120 if (normX - floor(normX) > 0.5) {
121 corners.push_back(
Position(floor(normX) + 1.5, floor(normY) + 0.5, raster[(int)normY * xSize + (
int)normX + 1]));
123 corners.push_back(
Position(floor(normX) - 0.5, floor(normY) + 0.5, raster[(int)normY * xSize + (
int)normX - 1]));
125 if (normY - floor(normY) > 0.5 && ((int)normY + 1) < item.ySize) {
126 corners.push_back(
Position(floor(normX) + 0.5, floor(normY) + 1.5, raster[((int)normY + 1) * xSize + (int)normX]));
128 corners.push_back(
Position(floor(normX) + 0.5, floor(normY) - 0.5, raster[((int)normY - 1) * xSize + (int)normX]));
132 if (result > -1e5 && result < 1e5) {
139 minB[0] = (float)geo.
x() - 0.00001f;
140 minB[1] = (float)geo.
y() - 0.00001f;
141 maxB[0] = (float)geo.
x() + 0.00001f;
142 maxB[1] = (float)geo.
y() + 0.00001f;
144 int hits =
myRTree.Search(minB, maxB, queryResult);
146 assert(hits == (
int)result.size());
149 for (Triangles::iterator it = result.begin(); it != result.end(); it++) {
152 return triangle->
getZ(geo);
165 const float cmin[2] = {(float) b.
xmin(), (float) b.
ymin()};
166 const float cmax[2] = {(float) b.
xmax(), (float) b.
ymax()};
167 myRTree.Insert(cmin, cmax, triangle);
173 if (oc.
isSet(
"heightmap.geotiff")) {
175 std::vector<std::string> files = oc.
getStringVector(
"heightmap.geotiff");
176 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
180 " done (parsed " +
toString(numFeatures) +
184 if (oc.
isSet(
"heightmap.shapefiles")) {
186 std::vector<std::string> files = oc.
getStringVector(
"heightmap.shapefiles");
187 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
191 " done (parsed " +
toString(numFeatures) +
201#if GDAL_VERSION_MAJOR < 2
203 OGRDataSource* ds = OGRSFDriverRegistrar::Open(file.c_str(), FALSE);
206 GDALDataset* ds = (GDALDataset*)GDALOpenEx(file.c_str(), GDAL_OF_VECTOR | GA_ReadOnly,
nullptr,
nullptr,
nullptr);
213 OGRLayer* layer = ds->GetLayer(0);
214 layer->ResetReading();
218#if GDAL_VERSION_MAJOR < 3
219 OGRSpatialReference* sr_src = layer->GetSpatialRef();
221 const OGRSpatialReference* sr_src = layer->GetSpatialRef();
223 OGRSpatialReference sr_dest;
224 sr_dest.SetWellKnownGeogCS(
"WGS84");
225 OGRCoordinateTransformation* toWGS84 = OGRCreateCoordinateTransformation(sr_src, &sr_dest);
226 if (toWGS84 ==
nullptr) {
227 WRITE_WARNING(
TL(
"Could not create geocoordinates converter; check whether proj.4 is installed."));
232 layer->ResetReading();
233 while ((feature = layer->GetNextFeature()) !=
nullptr) {
234 OGRGeometry* geom = feature->GetGeometryRef();
237 OGRwkbGeometryType gtype = geom->getGeometryType();
238 if (gtype == wkbPolygon) {
239 assert(std::string(geom->getGeometryName()) == std::string(
"POLYGON"));
241 geom->transform(toWGS84);
242 OGRLinearRing* cgeom = ((OGRPolygon*) geom)->getExteriorRing();
244 assert(cgeom->getNumPoints() == 4);
246 for (
int j = 0; j < 3; j++) {
247 Position pos((
double) cgeom->getX(j), (
double) cgeom->getY(j), (
double) cgeom->getZ(j));
248 corners.push_back(pos);
254 WRITE_WARNINGF(
TL(
"Ignored heightmap feature type %"), geom->getGeometryName());
287 OGRFeature::DestroyFeature(feature);
289#if GDAL_VERSION_MAJOR < 2
290 OGRDataSource::DestroyDataSource(ds);
294 OCTDestroyCoordinateTransformation(
reinterpret_cast<OGRCoordinateTransformationH
>(toWGS84));
299 WRITE_ERROR(
TL(
"Cannot load shape file since SUMO was compiled without GDAL support."));
309 GDALDataset* poDataset = (GDALDataset*)GDALOpen(file.c_str(), GA_ReadOnly);
310 if (poDataset == 0) {
315 const int xSize = poDataset->GetRasterXSize();
316 const int ySize = poDataset->GetRasterYSize();
317 double adfGeoTransform[6];
318 if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
319 Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
323 boundary.
add(topLeft);
324 boundary.
add(topLeft.
x() + horizontalSize, topLeft.
y() + verticalSize);
326 WRITE_ERRORF(
TL(
"Could not parse geo information from %."), file);
329 const int picSize = xSize * ySize;
330 float* raster = (
float*)CPLMalloc(
sizeof(
float) * picSize);
332 for (
int i = 1; i <= poDataset->GetRasterCount(); i++) {
333 GDALRasterBand* poBand = poDataset->GetRasterBand(i);
334 if (poBand->GetColorInterpretation() != GCI_GrayIndex) {
340 assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
341 if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, raster, xSize, ySize, GDT_Float32, 0, 0) == CE_Failure) {
348 double min = std::numeric_limits<double>::max();
349 double max = -std::numeric_limits<double>::max();
350 for (
int i = 0; i < picSize; i++) {
351 min =
MIN2(min, (
double)raster[i]);
352 max =
MAX2(max, (
double)raster[i]);
356#if GDAL_VERSION_MAJOR < 3
357 OGRSpatialReference spatialRef;
358 char* wkt =
const_cast<char*
>(poDataset->GetProjectionRef());
359 spatialRef.importFromWkt(&wkt);
361 OGRSpatialReference spatialRef(*poDataset->GetSpatialRef());
363 GDALClose(poDataset);
366 +
" for geo boundary [" +
toString(boundary)
368 OGRSpatialReference wgs;
369 wgs.SetWellKnownGeogCS(
"WGS84");
370 myRasters.push_back(
RasterData{raster, boundary, xSize, ySize, OGRCreateCoordinateTransformation(&wgs, &spatialRef)});
376 WRITE_ERROR(
TL(
"Cannot load GeoTIFF file since SUMO was compiled without GDAL support."));
390 CPLFree(item.raster);
391 if (item.transform !=
nullptr) {
392 delete item.transform;
419 return myCorners.around(pos);
437 Position side1 = myCorners[1] - myCorners[0];
438 Position side2 = myCorners[2] - myCorners[0];
#define WRITE_WARNINGF(...)
#define WRITE_ERRORF(...)
#define WRITE_MESSAGE(msg)
#define WRITE_WARNING(msg)
#define PROGRESS_BEGIN_MESSAGE(msg)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A class that stores a 2D geometrical boundary.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
double ymin() const
Returns minimum y-coordinate.
void reset()
Resets the boundary.
double xmin() const
Returns minimum x-coordinate.
bool around2D(const Position &p, double offset=0) const
Returns whether the boundary contains the given 2D coordinate (position)
double ymax() const
Returns maximum y-coordinate.
double xmax() const
Returns maximum x-coordinate.
virtual void endProcessMsg(std::string msg)
Ends a process information.
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
class for cirumventing the const-restriction of RTree::Search-context
Position normalVector() const
returns the normal vector for this triangles plane
double getZ(const Position &geo) const
returns the projection of the give geoCoordinate (WGS84) onto triangle plane
PositionVector myCorners
the corners of the triangle
Triangle(const PositionVector &corners)
void addSelf(const QueryResult &queryResult) const
callback for RTree search
bool contains(const Position &pos) const
checks whether pos lies within triangle (only checks x,y)
Set z-values for all network positions based on data from a height map.
std::vector< const Triangle * > Triangles
double getZ(const Position &geo) const
returns height for the given geo coordinate (WGS84)
static const NBHeightMapper & get()
return the singleton instance (maybe 0)
int loadShapeFile(const std::string &file)
load height data from Arcgis-shape file and returns the number of parsed features
static NBHeightMapper myInstance
the singleton instance
bool ready() const
returns whether the NBHeightMapper has data
std::vector< RasterData > myRasters
raster height information in m for all loaded files
NBHeightMapper()
private constructor and destructor (Singleton)
const Boundary & getBoundary()
returns the convex boundary of all known triangles
static void loadIfSet(OptionsCont &oc)
loads height map data if any loading options are set
void clearData()
clears loaded data
Position mySizeOfPixel
dimensions of one pixel in raster data
void addTriangle(PositionVector corners)
adds one triangles worth of height data
Boundary myBoundary
convex boundary of all known triangles;
TRIANGLE_RTREE_QUAL myRTree
The RTree for spatial queries.
int loadTiff(const std::string &file)
load height data from GeoTIFF file and returns the number of non void pixels
A storage for options typed value containers)
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
A point in 2D or 3D with translation and scaling methods.
double dotProduct(const Position &pos) const
returns the dot product (scalar product) between this point and the second one
void set(double x, double y)
set positions x and y
void sub(double dx, double dy)
Subtracts the given position from this one.
double x() const
Returns the x-position.
Position crossProduct(const Position &pos)
returns the cross product between this point and the second one
double y() const
Returns the y-position.
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
#define UNUSED_PARAMETER(x)
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects