diff --git a/GeoLib/Grid.h b/GeoLib/Grid.h index 53d62e3e7d6c41955941181d800f6f2357b42fae..a66283e540b4eb75c78f8a058d67829e2a8276ab 100644 --- a/GeoLib/Grid.h +++ b/GeoLib/Grid.h @@ -45,17 +45,17 @@ 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 */ - 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) : + template <typename InputIterator> + Grid(InputIterator first, InputIterator last, 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()); + InputIterator it(first); + size_t n_pnts(0); + while (it != last) { + n_pnts++; + this->update(copyOrAddress(*it)->getCoords()); } double delta[3] = { 0.0, 0.0, 0.0 }; @@ -125,8 +125,9 @@ public: } // fill the grid vectors - for (size_t l(0); l < n_pnts; l++) { - double const* const pnt(pnts[l].getCoords()); + it = first; + while (it != last) { + double const* const pnt(copyOrAddress(*it)->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])); @@ -135,123 +136,7 @@ public: 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]); + _grid_cell_nodes_map[i + j * _n_steps[0] + k * n_plane].push_back(copyOrAddress(*it)); } #ifndef NDEBUG @@ -285,14 +170,13 @@ public: * @return a pointer to the point with the smallest distance within the grid cells that are * outlined above or NULL */ - const typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type - getNearestPoint(double const*const pnt) const + POINT* getNearestPoint(double const*const pnt) const { size_t coords[3]; getGridCoords(pnt, coords); double sqr_min_dist (MathLib::sqrDist(&_min_pnt, &_max_pnt)); - typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type nearest_pnt(NULL); + POINT* nearest_pnt(NULL); double dists[6]; getPointCellBorderDistances(pnt, dists, coords); @@ -310,7 +194,7 @@ public: } else { // search in all border cells for at least one neighbor double sqr_min_dist_tmp; - typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type nearest_pnt_tmp(NULL); + POINT* nearest_pnt_tmp(NULL); size_t offset(1); while (nearest_pnt == NULL) { @@ -339,12 +223,12 @@ public: 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<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type> const*> vecs_of_pnts; + 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<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type> const& pnts(*(vecs_of_pnts[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())); @@ -367,7 +251,7 @@ public: * @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; + void getVecsOfGridCellsIntersectingCube(double const*const pnt, double half_len, std::vector<std::vector<POINT*> const*>& pnts) const; #ifndef NDEBUG /** @@ -422,7 +306,7 @@ private: bool calcNearestPointInGridCell(double const* const pnt, size_t const* const coords, double &sqr_min_dist, - typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type &nearest_pnt) const + 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<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type> const& pnts(_grid_cell_nodes_map[grid_idx]); @@ -440,20 +324,22 @@ private: } return true; } + + static POINT* copyOrAddress(POINT& p) { return &p; } + static POINT* copyOrAddress(POINT* p) { return p; } + double _step_sizes[3]; double _inverse_step_sizes[3]; size_t _n_steps[3]; /** - * 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. + * This is an array that stores pointers to POINT objects. */ - std::vector<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type>* _grid_cell_nodes_map; + std::vector<POINT*>* _grid_cell_nodes_map; }; template<typename POINT> void Grid<POINT>::getVecsOfGridCellsIntersectingCube(double const* const pnt, double half_len, - std::vector<std::vector<POINT> const*>& pnts) const + 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];