// Copyright (c) 2013-06 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // Author(s) : Shihao Wu, Cl¨Śment Jamin #ifndef CGAL_RICH_GRID_H #define CGAL_RICH_GRID_H #include #include #include #include #include #include #include #include #include #include //#include //#include namespace CGAL { /// \cond SKIP_IN_MANUAL // ---------------------------------------------------------------------------- // Rich Grid section // ---------------------------------------------------------------------------- //namespace rich_grid_internel{ namespace rich_grid_internel{ /// The Rich_point class represents a 3D point with inedxes of neighbor points; /// - a position, /// - a index. /// - self point set neighbors. /// - other point set neighbors. /// /// @heading Parameters: /// @param Kernel Geometric traits class. template class Rich_point { public: typedef typename Kernel::Point_3 Point; typedef typename Kernel::Vector_3 Vector; typedef typename Kernel::FT FT; public: Rich_point(const Point& p = CGAL::ORIGIN, const int& i = 0, const Vector& v = CGAL::NULL_VECTOR ):pt(p),index(i),normal(v){} public: Point pt; Vector normal; unsigned int index; std::vector neighbors; std::vector original_neighbors;//is not necessary }; template class Rich_box { public: typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; Rich_box(){init();} void init() { FT max_double = (FT)(std::numeric_limits::max)(); min_x = min_y = min_z = max_double; max_x = max_y = max_z = -max_double; } void add_point(const Point& p) { if (p.x() < min_x) min_x = p.x(); if (p.y() < min_y) min_y = p.y(); if (p.z() < min_z) min_z = p.z(); if (p.x() > max_x) max_x = p.x(); if (p.y() > max_y) max_y = p.y(); if (p.z() > max_z) max_z = p.z(); } Point get_min(){return Point(min_x, min_y, min_z);} Point get_max(){return Point(max_x, max_y, max_z);} private: FT min_x, min_y, min_z, max_x, max_y, max_z; }; template class Rich_grid { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; typedef std::vector*> Point_Pointer_vector; typedef typename Point_Pointer_vector::iterator iterator; public: Rich_grid() {} void init(std::vector > &vert, Rich_box& box, const FT _radius); // Travel for the point set itself void travel_itself(void (*self)(iterator starta, iterator enda, FT radius), void (*other)(iterator starta, iterator enda, iterator startb, iterator endb, FT radius)); // Travel other self between two point set(original and samples) void travel_others(Rich_grid &points, void (*travel_others)(iterator starta, iterator enda, iterator startb, iterator endb, FT radius)); void static __cdecl find_original_neighbors(iterator starta, iterator enda, iterator startb, iterator endb, FT radius); void static __cdecl find_self_neighbors(iterator start, iterator end, FT radius); void static __cdecl find_other_neighbors(iterator starta, iterator enda, iterator startb, iterator endb, FT radius); private: std::vector*> rich_points; std::vector index; int xside, yside, zside; FT radius; int cell(int x, int y, int z) { return x + xside*(y + yside*z); } bool isEmpty(int cell) { return index[cell+1] == index[cell]; } iterator startV(int origin) { return rich_points.begin() + index[origin]; } iterator endV(int origin) { return rich_points.begin() + index[origin+1]; } }; template class XSort { public: bool operator()(const Rich_point *a, const Rich_point *b) { return a->pt.x() < b->pt.x(); } }; template class YSort { public: bool operator()(const Rich_point *a, const Rich_point *b) { return a->pt.y() < b->pt.y(); } }; template class ZSort { public: bool operator()(const Rich_point *a, const Rich_point *b) { return a->pt.z() < b->pt.z(); } }; // divide spoints into some grids // and each grid has their points index in the index vector of sample. template void Rich_grid::init(std::vector > &vert, Rich_box& box, const typename Kernel::FT _radius) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; radius = _radius; Point min = box.get_min(); Point max = box.get_max(); rich_points.resize(vert.size()); for(int i = 0; i < rich_points.size(); i++) { Point& pt = vert[i].pt; rich_points[i] = &vert[i]; } xside = (int)ceil((max.x() - min.x())/radius); yside = (int)ceil((max.y() - min.y())/radius); zside = (int)ceil((max.z() - min.z())/radius); xside = (xside > 0) ? xside : 1; yside = (yside > 0) ? yside : 1; zside = (zside > 0) ? zside : 1; index.resize(xside*yside*zside + 1, -1); std::sort(rich_points.begin(), rich_points.end(), ZSort()); unsigned int startz = 0; for(unsigned int z = 0; z < zside; z++) { int endz = startz; FT maxz = min.z() + (z+1)*radius; while(endz < rich_points.size() && rich_points[endz]->pt.z()< maxz) ++endz; sort(rich_points.begin()+startz, rich_points.begin()+endz, YSort()); int starty = startz; for(int y = 0; y < yside; y++) { int endy = starty; FT maxy = min.y() + (y+1)*radius; while(endy < endz && rich_points[endy]->pt.y() < maxy) ++endy; sort(rich_points.begin()+starty, rich_points.begin()+endy, XSort()); int startx = starty; for(int x = 0; x < xside; x++) { int endx = startx; index[x + xside*y + xside*yside*z] = endx; FT maxx = min.x() + (x+1)*radius; while(endx < endy && rich_points[endx]->pt.x() < maxx) ++endx; startx = endx; } starty = endy; } startz = endz; } //compute the last grid's range index[xside*yside*zside] = startz; } /// define how to travel in the same gird template void Rich_grid::travel_itself( void (*self)(iterator starta, iterator enda, const typename Kernel::FT radius), void (*other)(iterator starta, iterator enda, iterator startb, iterator endb, FT radius) ) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; static int corner[8*3] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }; static int diagonals[14*2] = { 0, 0, //remove this to avoid self intesextion 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 2, 3, 1, 3, 1, 2, 1, 4, 2, 5, 3, 6 }; for(int z = 0; z < zside; z++) { for(int y = 0; y < yside; y++) { for(int x = 0; x < xside; x++) { int origin = cell(x, y, z); self(startV(origin), endV(origin), radius); // compute between other girds for(int d = 2; d < 28; d += 2) { // skipping self int *cs = corner + 3*diagonals[d]; int *ce = corner + 3*diagonals[d+1]; if((x + cs[0] < xside) && (y + cs[1] < yside) && (z + cs[2] < zside) && (x + ce[0] < xside) && (y + ce[1] < yside) && (z + ce[2] < zside)) { origin = cell(x+cs[0], y+cs[1], z+cs[2]); int dest = cell(x+ce[0], y+ce[1], z+ce[2]); other(startV(origin), endV(origin), startV(dest), endV(dest), radius); } } } } } } /// define how to travel in other gird template void Rich_grid::travel_others( Rich_grid &points, void (*travel_others)(iterator starta, iterator enda, iterator startb, iterator endb, const typename Kernel::FT radius) ) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; static int corner[8*3] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }; static int diagonals[14*2] = { 0, 0, //remove this to avoid self intesextion 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 2, 3, 1, 3, 1, 2, 1, 4, 2, 5, 3, 6 }; for(int z = 0; z < zside; z++) { for(int y = 0; y < yside; y++) { for(int x = 0; x < xside; x++) { int origin = cell(x, y, z); if(!isEmpty(origin) && !points.isEmpty(origin)) travel_others(startV(origin), endV(origin), points.startV(origin), points.endV(origin), radius); for(int d = 2; d < 28; d += 2) { //skipping self int *cs = corner + 3*diagonals[d]; int *ce = corner + 3*diagonals[d+1]; if((x+cs[0] < xside) && (y+cs[1] < yside) && (z+cs[2] < zside) && (x+ce[0] < xside) && (y+ce[1] < yside) && (z+ce[2] < zside)) { origin = cell(x+cs[0], y+cs[1], z+cs[2]); int dest = cell(x+ce[0], y+ce[1], z+ce[2]); if(!isEmpty(origin) && !points.isEmpty(dest)) // Locally travel_others(startV(origin), endV(origin), points.startV(dest), points.endV(dest), radius); if(!isEmpty(dest) && !points.isEmpty(origin)) travel_others(startV(dest), endV(dest), points.startV(origin), points.endV(origin), radius); } } } } } } /// grid travel function to find the neighbors in the original point set template void Rich_grid::find_original_neighbors( iterator starta, iterator enda, iterator startb, iterator endb, FT radius ) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; FT radius2 = radius*radius; for(Rich_grid::iterator dest = starta; dest != enda; dest++) { Rich_point &v = *(*dest); Point &p = v.pt; for(Rich_grid::iterator origin = startb; origin != endb; origin++) { Rich_point &t = *(*origin); Point &q = t.pt; FT dist2 = CGAL::squared_distance(p, q); if(dist2 < radius2) { v.original_neighbors.push_back((*origin)->index); } } } } /// grid travel function to find the neighbors in the same point set template void Rich_grid::find_self_neighbors( iterator start, iterator end, FT radius) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; FT radius2 = radius*radius; for(iterator dest = start; dest != end; dest++) { Rich_point &v = *(*dest); Point &p = v.pt; for(iterator origin = dest+1; origin != end; origin++) { Rich_point &t = *(*origin); Point &q = t.pt; FT dist2 = CGAL::squared_distance(p, q); if(dist2 < radius2) { v.neighbors.push_back((*origin)->index); t.neighbors.push_back((*dest)->index); } } } } /// grid travel function to find the neighbors in the same point set template void Rich_grid::find_other_neighbors( iterator starta, iterator enda, iterator startb, iterator endb, FT radius) { typedef typename Kernel::Point_3 Point; typedef typename Kernel::FT FT; FT radius2 = radius*radius; for(iterator dest = starta; dest != enda; dest++) { Rich_point &v = *(*dest); Point &p = v.pt; for(iterator origin = startb; origin != endb; origin++) { Rich_point &t = *(*origin); Point &q = t.pt; FT dist2 = CGAL::squared_distance(p, q); if(dist2 < radius2) { v.neighbors.push_back((*origin)->index); t.neighbors.push_back((*dest)->index); } } } } /// Compute ball neighbors for each point in the same point set. /// /// \pre `radius > 0` /// /// @tparam Kernel Geometric traits class. /// /// @return template void compute_ball_neighbors_one_self( std::vector >& points, Rich_box& box, const typename Kernel::FT radius) { typedef typename Kernel::FT FT; CGAL_point_set_processing_precondition(radius > 0); for (unsigned int i = 0; i < points.size(); i++) { points[i].neighbors.clear(); } Rich_grid points_grid; points_grid.init(points, box, radius); points_grid.travel_itself(Rich_grid::find_self_neighbors, Rich_grid::find_other_neighbors); } /// Compute ball neighbors for each (sample)points in the other point set /// /// \pre `radius > 0` /// /// @tparam Kernel Geometric traits class. /// /// @return template void compute_ball_neighbors_one_to_another( std::vector >& samples, ///< sample point set std::vector >& original,///< original point set Rich_box& box, ///< bounding box const typename Kernel::FT radius ///< neighbor radius ) { typedef typename Kernel::FT FT; if (radius < FT(0.0)) { return; } for (unsigned int i = 0; i < samples.size(); i++) { samples[i].original_neighbors.clear(); } Rich_grid samples_grid; samples_grid.init(samples, box, radius); // here can be optimized by initial the original grid just one time. Rich_grid original_grid; original_grid.init(original, box, radius); samples_grid.travel_others(original_grid, Rich_grid::find_original_neighbors); } } //namespace internal } //namespace CGAL #endif // CGAL_RICH_GRID_H