diff --git a/GeoLib/Raster.cpp b/GeoLib/Raster.cpp index 6616360280d01ccea674f0a9d924f1912f60320d..e3bd7d347e4e397549b25e9ff69464c0d52c78e2 100644 --- a/GeoLib/Raster.cpp +++ b/GeoLib/Raster.cpp @@ -101,7 +101,7 @@ Raster* Raster::getRasterFromSurface(Surface const& sfc, double cell_size, doubl return new Raster(n_cols, n_rows, ll[0], ll[1], cell_size, z_vals, z_vals+n_cols*n_rows ,-9999); } -double Raster::getValueAtPoint(const GeoLib::Point &pnt) +double Raster::getValueAtPoint(const GeoLib::Point &pnt) const { if (pnt[0]>=_ll_pnt[0] && pnt[0]<(_ll_pnt[0]+(_cell_size*_n_cols)) && pnt[1]>=_ll_pnt[1] && pnt[1]<(_ll_pnt[1]+(_cell_size*_n_rows))) @@ -119,4 +119,60 @@ double Raster::getValueAtPoint(const GeoLib::Point &pnt) return _no_data_val; } +double Raster::interpolateValueAtPoint(GeoLib::Point const& pnt) const +{ + // position in raster + double const xPos ((pnt[0] - _ll_pnt[0]) / _cell_size); + double const yPos ((pnt[1] - _ll_pnt[1]) / _cell_size); + // raster cell index + std::size_t const xIdx (static_cast<size_t>(floor(xPos))); + std::size_t const yIdx (static_cast<size_t>(floor(yPos))); + + // weights for bilinear interpolation + double const half_delta = 0.5*_cell_size; + double const xShift = fabs(xPos-(xIdx+half_delta)) / _cell_size; + double const yShift = fabs(yPos-(yIdx+half_delta)) / _cell_size; + std::array<double,4> weight = {{ (1-xShift)*(1-xShift), xShift*(1-yShift), xShift*yShift, (1-xShift)*yShift }}; + + // neightbors to include in interpolation + int const xShiftIdx = (xPos-xIdx-half_delta>=0) ? 1 : -1; + int const yShiftIdx = (yPos-yIdx-half_delta>=0) ? 1 : -1; + std::array<int,4> const x_nb = {{ 0, xShiftIdx, xShiftIdx, 0 }}; + std::array<int,4> const y_nb = {{ 0, 0, yShiftIdx, yShiftIdx }}; + + // get pixel values + std::array<double,4> pix_val; + unsigned no_data_count (0); + for (unsigned j=0; j<4; ++j) + { + pix_val[j] = _raster_data[(yIdx + y_nb[j])*_n_cols + (xIdx + x_nb[j])]; + if (fabs(pix_val[j] - _no_data_val) < std::numeric_limits<double>::epsilon()) + { + weight[j] = 0; + no_data_count++; + } + } + + // adjust weights if necessary + if (no_data_count > 0) + { + if (no_data_count == 4) // if there is absolutely no data just use the default value + return _no_data_val; + + const double norm = (double)(4)/(4-no_data_count); + std::for_each(weight.begin(), weight.end(), [&norm](double &val){val*=norm;}); + } + + // new value + return MathLib::scalarProduct<double,4>(weight.data(), pix_val.data()); +} + +bool Raster::isPntOnRaster(GeoLib::Point const& pnt) const +{ + if ((pnt[0]<_ll_pnt[0]) || (pnt[0]>_ll_pnt[0]+(_n_cols*_cell_size)) || + (pnt[1]<_ll_pnt[1]) || (pnt[1]>_ll_pnt[1]+(_n_rows*_cell_size))) + return false; + return true; +} + } // end namespace GeoLib diff --git a/GeoLib/Raster.h b/GeoLib/Raster.h index 78406fedc7be37520d1b57e8acd24990d87e70bf..1f4473ce0ef8754058b2d548c42314eccd73e5c1 100644 --- a/GeoLib/Raster.h +++ b/GeoLib/Raster.h @@ -99,7 +99,13 @@ public: /** * Returns the raster value at the position of the given point. */ - double getValueAtPoint(const GeoLib::Point &pnt); + double getValueAtPoint(const GeoLib::Point &pnt) const; + + /// Interpolates the elevation of the given point based on the 8-neighbourhood of the raster cell it is located on + double interpolateValueAtPoint(const GeoLib::Point &pnt) const; + + /// Checks if the given point is located within the (x,y)-extension of the raster. + bool isPntOnRaster(GeoLib::Point const& node) const; ~Raster(); diff --git a/Gui/DataView/GeoMapper.cpp b/Gui/DataView/GeoMapper.cpp index 658b01cea0e3a9d0253d238563ef4b3aa17e5ded..923838f44259e88549815d5e292c35bfc807e2d7 100644 --- a/Gui/DataView/GeoMapper.cpp +++ b/Gui/DataView/GeoMapper.cpp @@ -106,7 +106,7 @@ void GeoMapper::mapData() { GeoLib::Point* pnt ((*points)[j]); (*pnt)[2] = (_grid) ? this->getMeshElevation((*pnt)[0],(*pnt)[1], min_val, max_val) - : this->getDemElevation((*pnt)[0],(*pnt)[1]); + : this->getDemElevation(*pnt); } } else @@ -115,7 +115,7 @@ void GeoMapper::mapData() { GeoLib::Point* pnt ((*points)[j]); double offset = (_grid) ? (this->getMeshElevation((*pnt)[0],(*pnt)[1], min_val, max_val) - (*pnt)[2]) - : (this->getDemElevation((*pnt)[0],(*pnt)[1]) - (*pnt)[2]); + : this->getDemElevation(*pnt); GeoLib::StationBorehole* borehole = static_cast<GeoLib::StationBorehole*>(pnt); const std::vector<GeoLib::Point*> layers = borehole->getProfile(); @@ -129,21 +129,12 @@ void GeoMapper::mapData() } } -float GeoMapper::getDemElevation(double x, double y) const +float GeoMapper::getDemElevation(GeoLib::Point const& pnt) const { - const double origin_x(_raster->getOrigin()[0]); - const double origin_y(_raster->getOrigin()[1]); - const double cellsize(_raster->getRasterPixelSize()); - const std::size_t width(_raster->getNCols()); - const std::size_t height(_raster->getNRows()); - - if ((x<origin_x) || (x>origin_x+(width*cellsize)) || (y<origin_y) || (y>origin_y+(height*cellsize))) - return 0; - - const unsigned x_index = static_cast<unsigned>((x-origin_x)/cellsize); - const unsigned y_index = static_cast<unsigned>((y-origin_y)/cellsize); - - return static_cast<float>(*(_raster->begin() + (y_index*width+x_index))); + double const elevation (_raster->getValueAtPoint(pnt)); + if (elevation-_raster->getNoDataValue() < std::numeric_limits<double>::epsilon()) + return 0.0; + return static_cast<float>(elevation); } double GeoMapper::getMeshElevation(double x, double y, double min_val, double max_val) const diff --git a/Gui/DataView/GeoMapper.h b/Gui/DataView/GeoMapper.h index 6ae5b11e22def013105409d602458a3920e35319..db3160d1b6dc3739a2f5804c06dae904756d2b50 100644 --- a/Gui/DataView/GeoMapper.h +++ b/Gui/DataView/GeoMapper.h @@ -57,7 +57,7 @@ private: double getMeshElevation(double x, double y, double min_val, double max_val) const; // Returns the elevation at Point (x,y) based on a raster - float getDemElevation(double x, double y) const; + float getDemElevation(GeoLib::Point const& pnt) const; // Calculates the intersection of two lines embedded in the xy-plane GeoLib::Point* calcIntersection(GeoLib::Point const*const p1, GeoLib::Point const*const p2, GeoLib::Point const*const q1, GeoLib::Point const*const q2) const; diff --git a/MeshLib/MeshGenerators/MeshLayerMapper.cpp b/MeshLib/MeshGenerators/MeshLayerMapper.cpp index 649acf81f714a914f0bbb6be03db3663511f4a09..38ea970050241e62ac84d8fc2cb1bd06897bf8c1 100644 --- a/MeshLib/MeshGenerators/MeshLayerMapper.cpp +++ b/MeshLib/MeshGenerators/MeshLayerMapper.cpp @@ -34,7 +34,6 @@ #include "Elements/Prism.h" #include "MeshSurfaceExtraction.h" - #include "MathTools.h" MeshLib::Mesh* MeshLayerMapper::createStaticLayers(MeshLib::Mesh const& mesh, std::vector<float> const& layer_thickness_vector, std::string const& mesh_name) const @@ -132,12 +131,10 @@ bool MeshLayerMapper::layerMapping(MeshLib::Mesh &new_mesh, const GeoLib::Raster const double y0(raster.getOrigin()[1]); const double delta(raster.getRasterPixelSize()); const double no_data(raster.getNoDataValue()); - const std::size_t width(raster.getNCols()); - const std::size_t height(raster.getNRows()); double const*const elevation(raster.begin()); - const std::pair<double, double> xDim(x0, x0 + width * delta); // extension in x-dimension - const std::pair<double, double> yDim(y0, y0 + height * delta); // extension in y-dimension + const std::pair<double, double> xDim(x0, x0 + raster.getNCols() * delta); // extension in x-dimension + const std::pair<double, double> yDim(y0, y0 + raster.getNRows() * delta); // extension in y-dimension const size_t nNodes (new_mesh.getNNodes()); const size_t nNodesPerLayer (nNodes / (nLayers+1)); @@ -149,76 +146,22 @@ bool MeshLayerMapper::layerMapping(MeshLib::Mesh &new_mesh, const GeoLib::Raster const std::vector<MeshLib::Node*> &nodes = new_mesh.getNodes(); for (unsigned i = firstNode; i < lastNode; ++i) { - const double* coords (nodes[i]->getCoords()); - - if (!isNodeOnRaster(*nodes[i], xDim, yDim)) + if (!raster.isPntOnRaster(*nodes[i])) { // use either default value or elevation from layer above - nodes[i]->updateCoordinates(coords[0], coords[1], noDataReplacementValue); + nodes[i]->updateCoordinates((*nodes[i])[0], (*nodes[i])[1], noDataReplacementValue); continue; } - // position in raster - const double xPos ((coords[0] - xDim.first) / delta); - const double yPos ((coords[1] - yDim.first) / delta); - // raster cell index - const size_t xIdx (static_cast<size_t>(floor(xPos))); - const size_t yIdx (static_cast<size_t>(floor(yPos))); - - // weights for bilinear interpolation - const double xShift = fabs(xPos-(xIdx+half_delta))/delta; - const double yShift = fabs(yPos-(yIdx+half_delta))/delta; - std::array<double,4> weight = {{ (1-xShift)*(1-xShift), xShift*(1-yShift), xShift*yShift, (1-xShift)*yShift }}; - - // neightbors to include in interpolation - const int xShiftIdx = (xPos-xIdx-half_delta>=0) ? 1 : -1; - const int yShiftIdx = (yPos-yIdx-half_delta>=0) ? 1 : -1; - const std::array<int,4> x_nb = {{ 0, xShiftIdx, xShiftIdx, 0 }}; - const std::array<int,4> y_nb = {{ 0, 0, yShiftIdx, yShiftIdx }}; - - // get pixel values - std::array<double,4> pix_val; - unsigned no_data_count (0); - for (unsigned j=0; j<4; ++j) - { - pix_val[j] = elevation[(yIdx + y_nb[j])*width + (xIdx + x_nb[j])]; - if (fabs(pix_val[j] - no_data) < std::numeric_limits<double>::epsilon()) - { - weight[j] = 0; - no_data_count++; - } - } - - // adjust weights if necessary - if (no_data_count > 0) - { - if (no_data_count == 4) // if there is absolutely no data just use the default value - { - nodes[i]->updateCoordinates(coords[0], coords[1], noDataReplacementValue); - continue; - } - const double norm = (double)(4)/(4-no_data_count); - std::for_each(weight.begin(), weight.end(), [&norm](double &val){val*=norm;}); - } - - // new value - double z = MathLib::scalarProduct<double,4>(weight.data(), pix_val.data()); - nodes[i]->updateCoordinates(coords[0], coords[1], z); + double elevation (raster.interpolateValueAtPoint(*nodes[i])); + if (elevation - no_data < std::numeric_limits<double>::epsilon()) + elevation = noDataReplacementValue; + nodes[i]->updateCoordinates((*nodes[i])[0], (*nodes[i])[1], elevation); } return true; } -bool MeshLayerMapper::isNodeOnRaster(const MeshLib::Node &node, - const std::pair<double, double> &xDim, - const std::pair<double, double> &yDim) const -{ - if (node[0] < xDim.first || node[0] > xDim.second || node[1] < yDim.first || node[1] > yDim.second) - return false; - - return true; -} - MeshLib::Mesh* MeshLayerMapper::blendLayersWithSurface(MeshLib::Mesh &mesh, const unsigned nLayers, const std::string &dem_raster) const { // construct surface mesh from DEM diff --git a/MeshLib/MeshGenerators/MeshLayerMapper.h b/MeshLib/MeshGenerators/MeshLayerMapper.h index 543896d0650edcc192407493acb25b5adcd93c72..aab59cb115cc497e47a99f010a4806e933d242ec 100644 --- a/MeshLib/MeshGenerators/MeshLayerMapper.h +++ b/MeshLib/MeshGenerators/MeshLayerMapper.h @@ -67,9 +67,7 @@ public: MeshLib::Mesh* blendLayersWithSurface(MeshLib::Mesh &mesh, const unsigned nLayers, const std::string &dem_raster) const; private: - /// Checks if the given mesh is within the dimensions given by xDim and yDim. - bool isNodeOnRaster(const MeshLib::Node &node, - const std::pair<double, double> &xDim, const std::pair<double, double> &yDim) const; + }; #endif //MESHLAYERMAPPER_H