diff --git a/GeoLib/Grid.h b/GeoLib/Grid.h index a834d65859fa64962b9cd8c3697271e56b2661a1..ddaf7c525e5b29951ad319e1b7a253b18682d65c 100644 --- a/GeoLib/Grid.h +++ b/GeoLib/Grid.h @@ -13,6 +13,7 @@ #ifndef GRID_H_ #define GRID_H_ +#include <type_traits> #include <vector> // GeoLib @@ -43,8 +44,224 @@ public: * * @param pnts (input) the points that are managed with the Grid * @param max_num_per_grid_cell (input) max number per grid cell in the average (default 512) + * + * @note the somewhat wired template syntax chooses this constructor for non-pointer types + * at compile time */ - Grid(std::vector<POINT> const& pnts, size_t max_num_per_grid_cell = 512); + template <typename T, typename = typename std::enable_if<std::is_same<T, POINT>::value && !std::is_pointer<T>::value>::type> + Grid(std::vector<T> const& pnts, size_t max_num_per_grid_cell = 512) : + GeoLib::AABB(), _grid_cell_nodes_map(NULL) + { + // compute axis aligned bounding box + const size_t n_pnts(pnts.size()); + for (size_t k(0); k < n_pnts; k++) { + this->update(pnts[k].getCoords()); + } + + double delta[3] = { 0.0, 0.0, 0.0 }; + for (size_t k(0); k < 3; k++) { + // make the bounding box a little bit bigger, + // such that the node with maximal coordinates fits into the grid + _max_pnt[k] *= (1.0 + 1e-6); + if (fabs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { + _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); + } + delta[k] = _max_pnt[k] - _min_pnt[k]; + } + + // *** condition: n_pnts / (_n_steps[0] * _n_steps[1] * _n_steps[2]) < max_num_per_grid_cell + // *** with _n_steps[1] = _n_steps[0] * delta[1]/delta[0], _n_steps[2] = _n_steps[0] * delta[2]/delta[0] + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() || + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + // 1d case y = z = 0 + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() && + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + _n_steps[1] = 1; + _n_steps[2] = 1; + } else { + // 1d case x = z = 0 + if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = 1; + _n_steps[1] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + _n_steps[2] = 1; + } else { + // 1d case x = y = 0 + if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && fabs(delta[1]) + < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = 1; + _n_steps[1] = 1; + _n_steps[2] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + } else { + // 2d case + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[2])))); + _n_steps[1] = 1; + _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); + } else { + _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[1])))); + _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); + _n_steps[2] = 1; + } + } + } + } + } else { + // 3d case + _n_steps[0] = static_cast<size_t> (ceil(pow(n_pnts * delta[0] * delta[0] + / (max_num_per_grid_cell * delta[1] * delta[2]), 1. / 3.))); + _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); + _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); + } + + const size_t n_plane(_n_steps[0] * _n_steps[1]); + _grid_cell_nodes_map = new std::vector<POINT*>[n_plane * _n_steps[2]]; + + // some frequently used expressions to fill the grid vectors + for (size_t k(0); k < 3; k++) { + _step_sizes[k] = delta[k] / _n_steps[k]; + _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; + } + + // fill the grid vectors + for (size_t l(0); l < n_pnts; l++) { + double const* const pnt(pnts[l].getCoords()); + const size_t i(static_cast<size_t> ((pnt[0] - _min_pnt[0]) * _inverse_step_sizes[0])); + const size_t j(static_cast<size_t> ((pnt[1] - _min_pnt[1]) * _inverse_step_sizes[1])); + const size_t k(static_cast<size_t> ((pnt[2] - _min_pnt[2]) * _inverse_step_sizes[2])); + + if (i >= _n_steps[0] || j >= _n_steps[1] || k >= _n_steps[2]) { + std::cout << "error computing indices " << std::endl; + } + + _grid_cell_nodes_map[i + j * _n_steps[0] + k * n_plane].push_back(&pnts[l]); + } + +#ifndef NDEBUG + size_t pnts_cnt(0); + for (size_t k(0); k < n_plane * _n_steps[2]; k++) + pnts_cnt += _grid_cell_nodes_map[k].size(); + + assert(n_pnts==pnts_cnt); +#endif + } + + /** + * @brief The constructor of the grid object takes a vector of pointers to points or nodes. This is + * the main difference to the previous constructor. Furthermore the + * user can specify the *average* maximum number of points per grid cell. + * + * The number of grid cells are computed with the following formula + * \f$\frac{n_{points}}{n_{cells}} \le n_{max\_per\_cell}\f$ + * + * In order to limit the memory wasting the maximum number of points per grid cell + * (in the average) should be a power of two (since std::vector objects resize itself + * with this step size). + * + * @param pnts (input) a vector holding pointers to the points that are managed with the Grid + * @param max_num_per_grid_cell (input) max number per grid cell in the average (default 512) + * + * @note the somewhat wired template syntax chooses this constructor for pointer types at compile time + */ + template <typename T, bool dummy = true, typename std::enable_if<std::is_same<T, POINT>::value && std::is_pointer<T>::value, int>::type = 0> + Grid(std::vector<T> const& pnts, size_t max_num_per_grid_cell = 512) : + GeoLib::AABB(), _grid_cell_nodes_map(NULL) + { + // compute axis aligned bounding box + const size_t n_pnts(pnts.size()); + for (size_t k(0); k < n_pnts; k++) { + this->update(pnts[k]->getCoords()); + } + + double delta[3] = { 0.0, 0.0, 0.0 }; + for (size_t k(0); k < 3; k++) { + // make the bounding box a little bit bigger, + // such that the node with maximal coordinates fits into the grid + _max_pnt[k] *= (1.0 + 1e-6); + if (fabs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { + _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); + } + delta[k] = _max_pnt[k] - _min_pnt[k]; + } + + // *** condition: n_pnts / (_n_steps[0] * _n_steps[1] * _n_steps[2]) < max_num_per_grid_cell + // *** with _n_steps[1] = _n_steps[0] * delta[1]/delta[0], _n_steps[2] = _n_steps[0] * delta[2]/delta[0] + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() || + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + // 1d case y = z = 0 + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() && + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + _n_steps[1] = 1; + _n_steps[2] = 1; + } else { + // 1d case x = z = 0 + if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && + fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = 1; + _n_steps[1] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + _n_steps[2] = 1; + } else { + // 1d case x = y = 0 + if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && fabs(delta[1]) + < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = 1; + _n_steps[1] = 1; + _n_steps[2] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); + } else { + // 2d case + if (fabs(delta[1]) < std::numeric_limits<double>::epsilon()) { + _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[2])))); + _n_steps[1] = 1; + _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); + } else { + _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[1])))); + _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); + _n_steps[2] = 1; + } + } + } + } + } else { + // 3d case + _n_steps[0] = static_cast<size_t> (ceil(pow(n_pnts * delta[0] * delta[0] + / (max_num_per_grid_cell * delta[1] * delta[2]), 1. / 3.))); + _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); + _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); + } + + const size_t n_plane(_n_steps[0] * _n_steps[1]); + _grid_cell_nodes_map = new std::vector<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type>[n_plane * _n_steps[2]]; + + // some frequently used expressions to fill the grid vectors + for (size_t k(0); k < 3; k++) { + _step_sizes[k] = delta[k] / _n_steps[k]; + _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; + } + + // fill the grid vectors + for (size_t l(0); l < n_pnts; l++) { + double const* const pnt(pnts[l]->getCoords()); + const size_t i(static_cast<size_t> ((pnt[0] - _min_pnt[0]) * _inverse_step_sizes[0])); + const size_t j(static_cast<size_t> ((pnt[1] - _min_pnt[1]) * _inverse_step_sizes[1])); + const size_t k(static_cast<size_t> ((pnt[2] - _min_pnt[2]) * _inverse_step_sizes[2])); + + if (i >= _n_steps[0] || j >= _n_steps[1] || k >= _n_steps[2]) { + std::cout << "error computing indices " << std::endl; + } + + _grid_cell_nodes_map[i + j * _n_steps[0] + k * n_plane].push_back(pnts[l]); + } + +#ifndef NDEBUG + size_t pnts_cnt(0); + for (size_t k(0); k < n_plane * _n_steps[2]; k++) + pnts_cnt += _grid_cell_nodes_map[k].size(); + + assert(n_pnts==pnts_cnt); +#endif + } /** * This is the destructor of the class. It deletes the internal data structures *not* @@ -52,7 +269,7 @@ public: */ virtual ~Grid() { - delete [] _grid_quad_to_node_map; + delete [] _grid_cell_nodes_map; } /** @@ -102,18 +319,20 @@ private: /** * * point numbering of the grid cell is as follow + * @code * 7 -------- 6 * /: /| * / : / | * / : / | * / : / | - * 4 -------- 5 | + * 4 -------- 5 | * | 3 ....|... 2 * | . | / * | . | / * | . | / * |. |/ * 0 -------- 1 + * @endcode * the face numbering is as follow: * face nodes * 0 0,3,2,1 bottom @@ -134,108 +353,14 @@ private: double _step_sizes[3]; double _inverse_step_sizes[3]; size_t _n_steps[3]; - std::vector<POINT*>* _grid_quad_to_node_map; + /** + * This is an array that stores pointers to POINT objects. If POINT is a pointer type, + * std::remove_pointer returns the "base" type, else the POINT type is returned. Then, + * the base type is converted to a pointer type emploing std::add_pointer. + */ + std::vector<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type>* _grid_cell_nodes_map; }; -template <typename POINT> -Grid<POINT>::Grid(std::vector<POINT> const& pnts, size_t max_num_per_grid_cell) : - GeoLib::AABB(), _grid_quad_to_node_map(NULL) -{ - // compute axis aligned bounding box - const size_t n_pnts(pnts.size()); - for (size_t k(0); k < n_pnts; k++) { - this->update(pnts[k].getCoords()); - } - - double delta[3] = { 0.0, 0.0, 0.0 }; - for (size_t k(0); k < 3; k++) { - // make the bounding box a little bit bigger, - // such that the node with maximal coordinates fits into the grid - _max_pnt[k] *= (1.0 + 1e-6); - if (fabs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { - _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); - } - delta[k] = _max_pnt[k] - _min_pnt[k]; - } - - // *** condition: n_pnts / (_n_steps[0] * _n_steps[1] * _n_steps[2]) < max_num_per_grid_cell - // *** with _n_steps[1] = _n_steps[0] * delta[1]/delta[0], _n_steps[2] = _n_steps[0] * delta[2]/delta[0] - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() || - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - // 1d case y = z = 0 - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() && - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - _n_steps[1] = 1; - _n_steps[2] = 1; - } else { - // 1d case x = z = 0 - if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = 1; - _n_steps[1] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - _n_steps[2] = 1; - } else { - // 1d case x = y = 0 - if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && fabs(delta[1]) - < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = 1; - _n_steps[1] = 1; - _n_steps[2] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - } else { - // 2d case - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[2])))); - _n_steps[1] = 1; - _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); - } else { - _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[1])))); - _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); - _n_steps[2] = 1; - } - } - } - } - } else { - // 3d case - _n_steps[0] = static_cast<size_t> (ceil(pow(n_pnts * delta[0] * delta[0] - / (max_num_per_grid_cell * delta[1] * delta[2]), 1. / 3.))); - _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); - _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); - } - - const size_t n_plane(_n_steps[0] * _n_steps[1]); - _grid_quad_to_node_map = new std::vector<POINT*>[n_plane * _n_steps[2]]; - - // some frequently used expressions to fill the grid vectors - for (size_t k(0); k < 3; k++) { - _step_sizes[k] = delta[k] / _n_steps[k]; - _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; - } - - // fill the grid vectors - for (size_t l(0); l < n_pnts; l++) { - double const* const pnt(pnts[l].getCoords()); - const size_t i(static_cast<size_t> ((pnt[0] - _min_pnt[0]) * _inverse_step_sizes[0])); - const size_t j(static_cast<size_t> ((pnt[1] - _min_pnt[1]) * _inverse_step_sizes[1])); - const size_t k(static_cast<size_t> ((pnt[2] - _min_pnt[2]) * _inverse_step_sizes[2])); - - if (i >= _n_steps[0] || j >= _n_steps[1] || k >= _n_steps[2]) { - std::cout << "error computing indices " << std::endl; - } - - _grid_quad_to_node_map[i + j * _n_steps[0] + k * n_plane].push_back(&pnts[l]); - } - -#ifndef NDEBUG - size_t pnts_cnt(0); - for (size_t k(0); k < n_plane * _n_steps[2]; k++) - pnts_cnt += _grid_quad_to_node_map[k].size(); - - assert(n_pnts==pnts_cnt); -#endif -} - template <typename POINT> POINT const* Grid<POINT>::getNearestPoint(double const*const pnt) const { @@ -309,6 +434,7 @@ POINT const* Grid<POINT>::getNearestPoint(double const*const pnt) const return nearest_pnt; } + template<typename POINT> void Grid<POINT>::getVecsOfGridCellsIntersectingCube(double const* const pnt, double half_len, std::vector<std::vector<POINT> const*>& pnts) const @@ -328,7 +454,7 @@ void Grid<POINT>::getVecsOfGridCellsIntersectingCube(double const* const pnt, do for (coords[1] = min_coords[1]; coords[1] < max_coords[1] + 1; coords[1]++) { const size_t coords0_p_coords1_x_steps0(coords[0] + coords[1] * _n_steps[0]); for (coords[2] = min_coords[2]; coords[2] < max_coords[2] + 1; coords[2]++) { - pnts.push_back(&(_grid_quad_to_node_map[coords0_p_coords1_x_steps0 + coords[2] + pnts.push_back(&(_grid_cell_nodes_map[coords0_p_coords1_x_steps0 + coords[2] * steps0_x_steps1])); } } @@ -438,7 +564,7 @@ bool Grid<POINT>::calcNearestPointInGridCell(double const* const pnt, size_t con double &sqr_min_dist, POINT*& nearest_pnt) const { const size_t grid_idx (coords[0] + coords[1] * _n_steps[0] + coords[2] * _n_steps[0] * _n_steps[1]); - std::vector<POINT*> const& pnts(_grid_quad_to_node_map[grid_idx]); + std::vector<POINT*> const& pnts(_grid_cell_nodes_map[grid_idx]); if (pnts.empty()) return false; const size_t n_pnts(pnts.size()); @@ -468,335 +594,6 @@ void Grid<POINT>::getPointCellBorderDistances(double const*const pnt, double dis dists[2] = (_step_sizes[0] - dists[4]); // right } -/** - * this is a specialization of class template Grid for pointer types - */ -template <typename POINT> -class Grid<POINT*> : public GeoLib::AABB -{ -public: - Grid(std::vector<POINT*> const& pnts, size_t max_num_per_grid_cell = 512) : - GeoLib::AABB(), _grid_quad_to_node_map(NULL) - { - // compute axis aligned bounding box - const size_t n_pnts(pnts.size()); - for (size_t k(0); k < n_pnts; k++) { - this->update(pnts[k]->getCoords()); - } - - double delta[3] = { 0.0, 0.0, 0.0 }; - for (size_t k(0); k < 3; k++) { - // make the bounding box a little bit bigger, - // such that the node with maximal coordinates fits into the grid - _max_pnt[k] *= (1.0 + 1e-6); - if (fabs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { - _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); - } - delta[k] = _max_pnt[k] - _min_pnt[k]; - } - - // *** condition: n_pnts / (_n_steps[0] * _n_steps[1] * _n_steps[2]) < max_num_per_grid_cell - // *** with _n_steps[1] = _n_steps[0] * delta[1]/delta[0], _n_steps[2] = _n_steps[0] * delta[2]/delta[0] - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() || - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - // 1d case y = z = 0 - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon() && - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - _n_steps[1] = 1; - _n_steps[2] = 1; - } else { - // 1d case x = z = 0 - if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && - fabs(delta[2]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = 1; - _n_steps[1] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - _n_steps[2] = 1; - } else { - // 1d case x = y = 0 - if (fabs(delta[0]) < std::numeric_limits<double>::epsilon() && fabs(delta[1]) - < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = 1; - _n_steps[1] = 1; - _n_steps[2] = static_cast<size_t> (ceil(n_pnts / (double) max_num_per_grid_cell)); - } else { - // 2d case - if (fabs(delta[1]) < std::numeric_limits<double>::epsilon()) { - _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[2])))); - _n_steps[1] = 1; - _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); - } else { - _n_steps[0] = static_cast<size_t> (ceil(sqrt(n_pnts * delta[0] / (max_num_per_grid_cell * delta[1])))); - _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); - _n_steps[2] = 1; - } - } - } - } - } else { - // 3d case - _n_steps[0] = static_cast<size_t> (ceil(pow(n_pnts * delta[0] * delta[0] - / (max_num_per_grid_cell * delta[1] * delta[2]), 1. / 3.))); - _n_steps[1] = static_cast<size_t> (ceil(_n_steps[0] * delta[1] / delta[0])); - _n_steps[2] = static_cast<size_t> (ceil(_n_steps[0] * delta[2] / delta[0])); - } - - const size_t n_plane(_n_steps[0] * _n_steps[1]); - _grid_quad_to_node_map = new std::vector<POINT*>[n_plane * _n_steps[2]]; - - // some frequently used expressions to fill the grid vectors - for (size_t k(0); k < 3; k++) { - _step_sizes[k] = delta[k] / _n_steps[k]; - _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; - } - - // fill the grid vectors - for (size_t l(0); l < n_pnts; l++) { - double const* const pnt(pnts[l]->getCoords()); - const size_t i(static_cast<size_t> ((pnt[0] - _min_pnt[0]) * _inverse_step_sizes[0])); - const size_t j(static_cast<size_t> ((pnt[1] - _min_pnt[1]) * _inverse_step_sizes[1])); - const size_t k(static_cast<size_t> ((pnt[2] - _min_pnt[2]) * _inverse_step_sizes[2])); - - if (i >= _n_steps[0] || j >= _n_steps[1] || k >= _n_steps[2]) { - std::cout << "error computing indices " << std::endl; - } - - _grid_quad_to_node_map[i + j * _n_steps[0] + k * n_plane].push_back(pnts[l]); - } - -#ifndef NDEBUG - size_t pnts_cnt(0); - for (size_t k(0); k < n_plane * _n_steps[2]; k++) - pnts_cnt += _grid_quad_to_node_map[k].size(); - - assert(n_pnts==pnts_cnt); -#endif - } - - /** - * This is the destructor of the class. It deletes the internal data structures *not* - * including the pointers to the points. - */ - virtual ~Grid() - { - delete [] _grid_quad_to_node_map; - } - - /** - * The method calculates the grid cell the given point is belonging to, i.e., - * the (internal) coordinates of the grid cell are computed. The method searches the actual - * grid cell and all its neighbors for the POINT object which has the smallest - * distance. A pointer to this object is returned. - * - * If there is not such a point, i.e., all the searched grid cells do not contain any - * POINT object a NULL pointer is returned. - * - * @param pnt a field that holds the coordinates of the point - * @return a point with the smallest distance within the grid cells that are outlined above or NULL - */ - POINT const* getNearestPoint(double const*const pnt) const - { - size_t coords[3]; - getGridCoords(pnt, coords); - - double sqr_min_dist (MathLib::sqrDist(&_min_pnt, &_max_pnt)); - POINT* nearest_pnt(NULL); - - double dists[6]; - getPointCellBorderDistances(pnt, dists, coords); - - if (calcNearestPointInGridCell(pnt, coords, sqr_min_dist, nearest_pnt)) { - double min_dist(sqrt(sqr_min_dist)); - if (dists[0] >= min_dist - && dists[1] >= min_dist - && dists[2] >= min_dist - && dists[3] >= min_dist - && dists[4] >= min_dist - && dists[5] >= min_dist) { - return nearest_pnt; - } - } else { - // search in all border cells for at least one neighbor - double sqr_min_dist_tmp; - POINT* nearest_pnt_tmp(NULL); - size_t offset(1); - - while (nearest_pnt == NULL) { - size_t tmp_coords[3]; - for (tmp_coords[0] = coords[0]-offset; tmp_coords[0]<coords[0]+offset; tmp_coords[0]++) { - for (tmp_coords[1] = coords[1]-offset; tmp_coords[1]<coords[1]+offset; tmp_coords[1]++) { - for (tmp_coords[2] = coords[2]-offset; tmp_coords[2]<coords[2]+offset; tmp_coords[2]++) { - // do not check the origin grid cell twice - if (!(tmp_coords[0] == coords[0] && tmp_coords[1] == coords[1] && tmp_coords[2] == coords[2])) { - // check if temporary grid cell coordinates are valid - if (tmp_coords[0] < _n_steps[0] && tmp_coords[1] < _n_steps[1] && tmp_coords[2] < _n_steps[2]) { - if (calcNearestPointInGridCell(pnt, tmp_coords, sqr_min_dist_tmp, nearest_pnt_tmp)) { - if (sqr_min_dist_tmp < sqr_min_dist) { - sqr_min_dist = sqr_min_dist_tmp; - nearest_pnt = nearest_pnt_tmp; - } - } - } // valid grid cell coordinates - } // same element - } // end k - } // end j - } // end i - offset++; - } // end while - } // end else - - double len (sqrt(MathLib::sqrDist(pnt, nearest_pnt->getCoords()))); - // search all other grid cells within the cube with the edge nodes - std::vector<std::vector<POINT*> const*> vecs_of_pnts; - getVecsOfGridCellsIntersectingCube(pnt, len, vecs_of_pnts); - - const size_t n_vecs(vecs_of_pnts.size()); - for (size_t j(0); j<n_vecs; j++) { - std::vector<POINT*> const& pnts(vecs_of_pnts[j]); - const size_t n_pnts(pnts.size()); - for (size_t k(0); k<n_pnts; k++) { - const double sqr_dist (MathLib::sqrDist(pnt, pnts[k]->getCoords())); - if (sqr_dist < sqr_min_dist) { - sqr_min_dist = sqr_dist; - nearest_pnt = pnts[k]; - } - } - } - - return nearest_pnt; - } - - /** - * Method fetches the vectors of all grid cells intersecting the axis aligned cube - * defined by its center and half edge length. - * - * @param pnt (input) the center point of the axis aligned cube - * @param half_len (input) half of the edge length of the axis aligned cube - * @param pnts (output) vector of vectors of points within grid cells that intersects - * the axis aligned cube - */ - void getVecsOfGridCellsIntersectingCube(double const*const pnt, double half_len, std::vector<std::vector<POINT*> const*>& pnts) const - { - double tmp_pnt[3] = {pnt[0]-half_len, pnt[1]-half_len, pnt[2]-half_len}; // min - size_t min_coords[3]; - getGridCoords(tmp_pnt, min_coords); - - tmp_pnt[0] = pnt[0]+half_len; - tmp_pnt[1] = pnt[1]+half_len; - tmp_pnt[2] = pnt[2]+half_len; - size_t max_coords[3]; - getGridCoords(tmp_pnt, max_coords); - - size_t coords[3], steps0_x_steps1(_n_steps[0] * _n_steps[1]); - for (coords[0] = min_coords[0]; coords[0] < max_coords[0]+1; coords[0]++) { - for (coords[1] = min_coords[1]; coords[1] < max_coords[1]+1; coords[1]++) { - const size_t coords0_p_coords1_x_steps0 (coords[0] + coords[1] * _n_steps[0]); - for (coords[2] = min_coords[2]; coords[2] < max_coords[2]+1; coords[2]++) { - pnts.push_back (&(_grid_quad_to_node_map[coords0_p_coords1_x_steps0 + coords[2] * steps0_x_steps1])); - } - } - } - } - -#ifndef NDEBUG - /** - * Method creates a geometry for every mesh grid box. Additionally it - * creates one geometry containing all the box geometries. - * @param geo_obj - */ - void createGridGeometry(GeoLib::GEOObjects* geo_obj) const; -#endif - -private: - /** - * Method calculates the grid cell coordinates for the given point pnt. If - * the point is located outside of the bounding box the coordinates of the - * grid cell on the border that is nearest to given point will be returned. - * @param pnt (input) the coordinates of the point - * @param coords (output) the coordinates of the grid cell - */ - inline void getGridCoords(double const*const pnt, size_t* coords) const - { - for (size_t k(0); k<3; k++) { - if (pnt[k] < _min_pnt[k]) { - coords[k] = 0; - } else { - if (pnt[k] > _max_pnt[k]) { - coords[k] = _n_steps[k]-1; - } else { - coords[k] = static_cast<size_t>((pnt[k]-_min_pnt[k]) * _inverse_step_sizes[k]); - } - } - } - } - - - /** - * - * point numbering of the grid cell is as follow - * 7 -------- 6 - * /: /| - * / : / | - * / : / | - * / : / | - * 4 -------- 5 | - * | 3 ....|... 2 - * | . | / - * | . | / - * | . | / - * |. |/ - * 0 -------- 1 - * the face numbering is as follow: - * face nodes - * 0 0,3,2,1 bottom - * 1 0,1,5,4 front - * 2 1,2,6,5 right - * 3 2,3,7,6 back - * 4 3,0,4,7 left - * 5 4,5,6,7 top - * @param pnt (input) coordinates of the point - * @param dists (output) squared distances of the point to the faces - * ordered in the same sequence as above described - * @param coords coordinates of the grid cell - */ - void getPointCellBorderDistances(double const*const pnt, double dists[6], size_t const* const coords) const - { - dists[0] = (pnt[2] - _min_pnt[2] + coords[2]*_step_sizes[2]); // bottom - dists[5] = (_step_sizes[2] - dists[0]); // top - - dists[1] = (pnt[1] - _min_pnt[1] + coords[1]*_step_sizes[1]); // front - dists[3] = (_step_sizes[1] - dists[1]); // back - - dists[4] = (pnt[0] - _min_pnt[0] + coords[0]*_step_sizes[0]); // left - dists[2] = (_step_sizes[0] - dists[4]); // right - } - - bool calcNearestPointInGridCell(double const* const pnt, size_t const* const coords, - double &sqr_min_dist, POINT* &nearest_pnt) const - { - const size_t grid_idx (coords[0] + coords[1] * _n_steps[0] + coords[2] * _n_steps[0] * _n_steps[1]); - std::vector<POINT*> const& pnts(_grid_quad_to_node_map[grid_idx]); - if (pnts.empty()) return false; - - const size_t n_pnts(pnts.size()); - sqr_min_dist = MathLib::sqrDist(pnts[0]->getCoords(), pnt); - nearest_pnt = pnts[0]; - for (size_t i(1); i < n_pnts; i++) { - const double sqr_dist(MathLib::sqrDist(pnts[i]->getCoords(), pnt)); - if (sqr_dist < sqr_min_dist) { - sqr_min_dist = sqr_dist; - nearest_pnt = pnts[i]; - } - } - return true; - }; - - double _step_sizes[3]; - double _inverse_step_sizes[3]; - size_t _n_steps[3]; - std::vector<POINT*>* _grid_quad_to_node_map; -}; - } // end namespace GeoLib #endif /* MESHGRID_H_ */