Added Rich_grid.h file

Modified regularize_and_simplify_point_set_using_balltree for Rich_grid

Used CGAL::Timer instead
This commit is contained in:
Shihao Wu 2013-07-08 16:02:15 +08:00
parent 6bb238d5cb
commit 273eb39cd2
5 changed files with 588 additions and 610 deletions

View File

@ -3,6 +3,7 @@
#include <CGAL/regularize_and_simplify_point_set_using_balltree.h>
#include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/write_xyz_points.h>
#include <CGAL/Timer.h>
#include <vector>
#include <fstream>
@ -38,8 +39,9 @@ int main(void)
std::vector<Point> points_sampled;
points_sampled.resize(points.size() * (retain_percentage / 100.));
int starttime, stoptime, timeused;
starttime = clock();
CGAL::Timer task_timer;
task_timer.start();
std::cout << "Run algorithm example: " << std::endl;
// Run algorithm and copy results to sample points using kdtree
//std::copy(CGAL::regularize_and_simplify_point_set(
@ -52,7 +54,7 @@ int main(void)
// points.end(),
// points_sampled.begin());
// Run algorithm
// Run algorithm using balltree
std::vector<Point>::const_iterator sample_points_begin =
CGAL::regularize_and_simplify_point_set_using_balltree(
points.begin(),
@ -61,15 +63,16 @@ int main(void)
neighbor_radius,
iter_number,
need_compute_density);
// Copy results to sample points using balltree
// Copy results to sample points
std::copy(sample_points_begin,
static_cast<std::vector<Point>::const_iterator>(points.end()),
points_sampled.begin());
stoptime = clock();
timeused = stoptime - starttime;
std::cout << "##" << " time used: " << timeused / double(CLOCKS_PER_SEC) << " seconds." << std::endl;
long memory = CGAL::Memory_sizer().virtual_size();
std::cout << "done: " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated" << std::endl;
task_timer.stop();
// Saves point set.
// Note: write_xyz_points_and_normals() requires an output iterator
@ -91,40 +94,3 @@ int main(void)
template <typename Kernel, typename IteratorType>
void find_original_neighbors(
typename IteratorType::iterator starta,
typename IteratorType::iterator enda,
typename IteratorType::iterator startb,
typename IteratorType::iterator endb,
const typename Kernel::FT radius)
{
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
FT radius2 = radius*radius;
FT iradius16 = -4/radius2;
const FT PI = 3.1415926;
for(CGrid::iterator dest = starta; dest != enda; dest++)
{
RichPoint<Kernel> &v = *(*dest);
Point &p = v.pt;
for(CGrid::iterator origin = startb; origin != endb; origin++)
{
RichPoint<Kernel> &t = *(*origin);
Point &q = t.pt;
double dist2 = CGAL::squared_distance(p, q);
if(dist2 < radius2)
{
v.neighbors.push_back((*origin)->index);
}
}
}
}

View File

@ -0,0 +1,516 @@
// 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 <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
#include <iterator>
#include <algorithm>
#include <cmath>
#include <ctime>
//#include <tbb/parallel_for.h>
//#include <tbb/blocked_range.h>
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 <typename Kernel>
class Rich_point
{
public:
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
public:
Rich_point(){}
Rich_point(const Point& p, const int& i):pt(p),index(i){}
Point pt;
unsigned int index;
std::vector<unsigned int> neighbors;
std::vector<unsigned int> original_neighbors;
};
template <typename Kernel>
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<double>::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 <typename Kernel>
class Rich_grid
{
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
typedef std::vector<Rich_point<Kernel>*> Point_Pointer_vector;
typedef typename Point_Pointer_vector::iterator iterator;
public:
Rich_grid() {}
void init(std::vector<Rich_point<Kernel> > &vert,
Rich_box<Kernel>& 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_point<Kernel>*> rich_points;
std::vector<int> 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 <typename Kernel>
class XSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *b) {
return a->pt.x() < b->pt.x();
}
};
template <typename Kernel>
class YSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *b) {
return a->pt.y() < b->pt.y();
}
};
template <typename Kernel>
class ZSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *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 <typename Kernel>
void Rich_grid<Kernel>::init(std::vector<Rich_point<Kernel> > &vert,
Rich_box<Kernel>& 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<Kernel>());
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<Kernel>());
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<Kernel>());
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 <typename Kernel>
void Rich_grid<Kernel>::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 <typename Kernel>
void Rich_grid<Kernel>::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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(Rich_grid::iterator origin = startb; origin != endb; origin++)
{
Rich_point<Kernel> &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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(iterator origin = dest+1; origin != end; origin++)
{
Rich_point<Kernel> &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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(iterator origin = startb; origin != endb; origin++)
{
Rich_point<Kernel> &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 <typename Kernel>
void compute_ball_neighbors_one_self(
std::vector<Rich_point<Kernel> >& points,
Rich_box<Kernel>& 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<Kernel> points_grid;
points_grid.init(points, box, radius);
points_grid.travel_itself(Rich_grid<Kernel>::find_self_neighbors,
Rich_grid<Kernel>::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 <typename Kernel>
void compute_ball_neighbors_one_to_another(
std::vector<Rich_point<Kernel> >& samples, ///< sample point set
std::vector<Rich_point<Kernel> >& original,///< original point set
Rich_box<Kernel>& 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<Kernel> samples_grid;
samples_grid.init(samples, box, radius);
// here can be optimized by initial the original grid just one time.
Rich_grid<Kernel> original_grid;
original_grid.init(original, box, radius);
samples_grid.travel_others(original_grid,
Rich_grid<Kernel>::find_original_neighbors);
}
} //namespace internal
} //namespace CGAL
#endif // CGAL_RICH_GRID_H

View File

@ -15,7 +15,7 @@
// $URL$
// $Id$
//
// Author(s) : Shihao Wu, Clement Jamin
// Author(s) : Shihao Wu, Cl¨¦ment Jamin
#ifndef CGAL_DENOSISE_POINTS_WITH_NORMALS_H
#define CGAL_DENOSISE_POINTS_WITH_NORMALS_H

View File

@ -24,6 +24,8 @@
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Timer.h>
#include <CGAL/Memory_sizer.h>
#include <iterator>
#include <set>
@ -36,35 +38,6 @@
namespace CGAL {
/// \cond SKIP_IN_MANUAL
class Timer
{
public:
void start(const std::string& str)
{
std::cout << std::endl;
starttime = clock();
mid_start = clock();
// std::cout << "@@@@@ Time Count Strat For: " << str << std::endl;
_str = str;
}
void end()
{
stoptime = clock();
timeused = stoptime - starttime;
std::cout << /*endl <<*/ "@@@@ finish " << _str << " time used: " << timeused / double(CLOCKS_PER_SEC) << " seconds." << std::endl;
std::cout << std::endl;
}
private:
int starttime, mid_start, mid_end, stoptime, timeused;
std::string _str;
};
// ----------------------------------------------------------------------------
// Private section
@ -571,7 +544,7 @@ regularize_and_simplify_point_set(
)
{
CGAL_point_set_processing_precondition(k > 1);
Timer time;
Timer task_timer;
// basic geometric types
typedef typename Kernel::Point_3 Point;
@ -612,7 +585,9 @@ regularize_and_simplify_point_set(
sample_points[i] = get(point_pmap, it);
// Initiate a KD-tree search for original points
time.start("Build Original Neighbor Tree");
task_timer.start();
std::cout << "Initialization / Compute Density For Original" << endl;
std::vector<KdTreeElement> original_treeElements;
for (it = first_original_point, i=0 ; it != beyond ; ++it, ++i)
{
@ -620,10 +595,8 @@ regularize_and_simplify_point_set(
original_treeElements.push_back(KdTreeElement(p0,i));
}
Tree original_tree(original_treeElements.begin(), original_treeElements.end());
time.end();
// Guess spacing
time.start("Guess Neighborhood Radiuse");
FT guess_neighbor_radius = (FT)(std::numeric_limits<double>::max)(); // Or a better max number: (numeric_limits<double>::max)()?
for(it = first_original_point; it != beyond ; ++it)
{
@ -631,11 +604,10 @@ regularize_and_simplify_point_set(
guess_neighbor_radius = max_spacing < guess_neighbor_radius ? max_spacing : guess_neighbor_radius;
}
guess_neighbor_radius *= 0.95;
time.end();
std::cout << "Guess Neighborhood Radius:" << guess_neighbor_radius << std::endl;
// Compute original density weight for original points if user needed
time.start("Compute Density For Original");
task_timer.start("Compute Density For Original");
std::vector<FT> original_density_weight_set;
if (need_compute_density)
{
@ -645,10 +617,8 @@ regularize_and_simplify_point_set(
original_density_weight_set.push_back(density);
}
}
time.end();
// Compute guess KNN set
time.start("Compute guess KNN set");
std::vector<unsigned int> guess_KNN_set;
for (i=0 ; i < sample_points.size(); i++)
{
@ -656,14 +626,19 @@ regularize_and_simplify_point_set(
unsigned int guess_knn = regularize_and_simplify_internal::guess_KNN_number_for_original_set<Kernel, Tree>(p0, original_tree, k, guess_neighbor_radius);
guess_KNN_set.push_back(guess_knn);
}
time.end();
long memory = CGAL::Memory_sizer().virtual_size();
std::cout << "done: " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated" << std::endl << std::endl;
task_timer.stop();
for (unsigned int iter_n = 0; iter_n < iter_number; iter_n++)
{
task_timer.start();
std::cout << "Compute average term and repulsion term " << endl;
// Initiate a KD-tree search for sample points
time.start("Build Sample Neighbor Tree");
std::vector<KdTreeElement> sample_treeElements;
unsigned int k_for_sample = 30; // Or it can be conducted by the "guess_neighbor_radius"
for (i=0 ; i < sample_points.size(); i++)
@ -672,11 +647,10 @@ regularize_and_simplify_point_set(
sample_treeElements.push_back(KdTreeElement(p0,i));
}
Tree sample_tree(sample_treeElements.begin(), sample_treeElements.end());
time.end();
// Compute sample density weight for sample points if user needed
std::vector<FT> sample_density_weight_set;
time.start("Compute Density For Sample");
// task_timer.start("Compute Density For Sample");
if (need_compute_density)
{
for (i=0 ; i < sample_points.size(); i++)
@ -685,29 +659,24 @@ regularize_and_simplify_point_set(
sample_density_weight_set.push_back(density);
}
}
time.end();
// Compute average term and repulsion term for each sample points separately,
// then update each sample points
std::vector<Vector> average_set(nb_points_sample);
std::vector<Vector> repulsion_set(nb_points_sample);
time.start("Compute Average Term");
//task_timer.start("Compute Average Term");
for (i = 0; i < sample_points.size(); i++)
{
Point& p = sample_points[i];
average_set[i] = regularize_and_simplify_internal::compute_average_term<Kernel>(p, original_tree, k, guess_neighbor_radius, original_density_weight_set); // Before speed up
//average_set[i] = regularize_and_simplify_internal::compute_average_term<Kernel>(p, original_tree, guess_KNN_set[i], guess_neighbor_radius, original_density_weight_set);
average_set[i] = regularize_and_simplify_internal::compute_average_term<Kernel>(p, original_tree, guess_KNN_set[i], guess_neighbor_radius, original_density_weight_set);
}
time.end();
time.start("Compute Repulsion Term");
//task_timer.start("Compute Repulsion Term");
for (i = 0; i < sample_points.size(); i++)
{
Point& p = sample_points[i];
repulsion_set[i] = regularize_and_simplify_internal::compute_repulsion_term<Kernel>(p, sample_tree, k_for_sample, guess_neighbor_radius, sample_density_weight_set);
}
time.end();
for (i = 0; i < sample_points.size(); i++)
{
@ -715,7 +684,12 @@ regularize_and_simplify_point_set(
p = CGAL::ORIGIN + average_set[i] + (FT)0.5 * repulsion_set[i];
}
std::cout << "iterate: " << iter_n + 1 << " "<< std::endl;
long memory = CGAL::Memory_sizer().virtual_size();
std::cout << "done: " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated" << std::endl;
task_timer.stop();
std::cout << "iterate: " << iter_n + 1 << " "<< std::endl << std::endl;;
}
//Copy back modified sample points to original points for output

View File

@ -22,12 +22,13 @@
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
#include <CGAL/Rich_grid.h>
#include <CGAL/Timer.h>
#include <CGAL/Memory_sizer.h>
#include <iterator>
#include <set>
#include <algorithm>
#include <cmath>
#include <ctime>
//#include <tbb/parallel_for.h>
@ -36,498 +37,13 @@
namespace CGAL {
/// \cond SKIP_IN_MANUAL
// ----------------------------------------------------------------------------
// Testing code section
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Rich Grid section
// ----------------------------------------------------------------------------
//namespace rich_grid_internel
//{
//}
// ----------------------------------------------------------------------------
// Private section
// ----------------------------------------------------------------------------
namespace regularize_and_simplify_internal{
class Timer
{
public:
void start(const std::string& str)
{
std::cout << std::endl;
starttime = clock();
//std::cout << "@@@@@ Time Count Strat For: " << str << std::endl;
_str = str;
}
void end()
{
stoptime = clock();
timeused = stoptime - starttime;
std::cout << /*endl <<*/ "@@@@ finish " << _str << " time used: " << timeused / double(CLOCKS_PER_SEC) << " seconds." << std::endl;
std::cout << std::endl;
}
private:
int starttime, mid_start, mid_end, stoptime, timeused;
std::string _str;
};
// ----------------------------------------------------------------------------
// Ball Tree section
// ----------------------------------------------------------------------------
template <typename Kernel>
class Rich_point
{
public:
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
public:
Rich_point(){}
Rich_point(const Point& p, const int& i):pt(p),index(i){}
Point pt;
unsigned int index;
std::vector<unsigned int> neighbors;
std::vector<unsigned int> original_neighbors;//need more memory, but make the code a littel easier to read.
};
template <typename Kernel>
class Rich_box
{
public:
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
Rich_box(){init();}
void init()
{
FT max_double = std::numeric_limits<FT>::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 <typename Kernel>
class Rich_grid
{
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
typedef std::vector<Rich_point<Kernel>*> Point_Pointer_vector;
typedef typename Point_Pointer_vector::iterator iterator;
public:
Rich_grid() {}
void init(std::vector<Rich_point<Kernel> > &vert, Rich_box<Kernel>& 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_point<Kernel>*> rich_points;
std::vector<int> index; // the start index of each grid in the sample points which is order by Zsort
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 <typename Kernel>
class XSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *b) {
return a->pt.x() < b->pt.x();
}
};
template <typename Kernel>
class YSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *b) {
return a->pt.y() < b->pt.y();
}
};
template <typename Kernel>
class ZSort {
public:
bool operator()(const Rich_point<Kernel> *a, const Rich_point<Kernel> *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 <typename Kernel>
void Rich_grid<Kernel>::init(std::vector<Rich_point<Kernel> > &vert, Rich_box<Kernel>& 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<Kernel>()); //this would be very slow
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<Kernel>());
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<Kernel>());
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;
}
index[xside*yside*zside] = startz; // in order to compute the last grid's range
}
/// define how to travel in the same gird
template <typename Kernel>
void Rich_grid<Kernel>::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 line 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 <typename Kernel>
void Rich_grid<Kernel>::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 line 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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(Rich_grid::iterator origin = startb; origin != endb; origin++)
{
Rich_point<Kernel> &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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(iterator origin = dest+1; origin != end; origin++)
{
Rich_point<Kernel> &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 <typename Kernel>
void Rich_grid<Kernel>::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<Kernel> &v = *(*dest);
Point &p = v.pt;
for(iterator origin = startb; origin != endb; origin++)
{
Rich_point<Kernel> &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(sample or original points)
///
/// \pre `radius > 0`
///
/// @tparam Kernel Geometric traits class.
///
/// @return
template <typename Kernel>
void compute_ball_neighbors_one_self(
std::vector<Rich_point<Kernel> >& points,
Rich_box<Kernel>& 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<Kernel> points_grid;
points_grid.init(points, box, radius);
points_grid.travel_itself(Rich_grid<Kernel>::find_self_neighbors, Rich_grid<Kernel>::find_other_neighbors);
}
/// Compute ball neighbors for each point(sample points) in the other point set(original points)
///
/// \pre `radius > 0`
///
/// @tparam Kernel Geometric traits class.
///
/// @return
template <typename Kernel>
void compute_ball_neighbors_one_to_another(
std::vector<Rich_point<Kernel> >& samples, ///< sample point set
std::vector<Rich_point<Kernel> >& original,///< original point set
Rich_box<Kernel>& 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<Kernel> samples_grid;
samples_grid.init(samples, box, radius);
// can be speed up by initial the original grid just one time(as paramter of this function)
Rich_grid<Kernel> original_grid;
original_grid.init(original, box, radius);
samples_grid.travel_others(original_grid, Rich_grid<Kernel>::find_original_neighbors);
}
// ----------------------------------------------------------------------------
// WLOP algorithm section
@ -544,9 +60,9 @@ template <typename Kernel>
typename Kernel::Vector_3
compute_average_term(
const typename Kernel::Point_3& query, ///< 3D point to project
const std::vector<Rich_point<Kernel> > neighbor_original_points, ///< neighbor original points
const std::vector<rich_grid_internel::Rich_point<Kernel> > neighbor_original_points,
const typename Kernel::FT radius, ///<accept neighborhood radius
const std::vector<typename Kernel::FT>& density_weight_set ///<if user need density
const std::vector<typename Kernel::FT>& density_weight_set ///<
)
{
CGAL_point_set_processing_precondition(radius > 0);
@ -597,7 +113,7 @@ template <typename Kernel>
typename Kernel::Vector_3
compute_repulsion_term(
const typename Kernel::Point_3& query, ///< 3D point to project
const std::vector<Rich_point<Kernel> > neighbor_sample_points, ///< neighbor sample points
const std::vector<rich_grid_internel::Rich_point<Kernel> > neighbor_sample_points, ///< neighbor sample points
const typename Kernel::FT radius, ///<accept neighborhood radius
const std::vector<typename Kernel::FT>& density_weight_set ///< if user need density
)
@ -763,13 +279,13 @@ regularize_and_simplify_point_set_using_balltree(
)
{
CGAL_point_set_processing_precondition(neighbor_radius > 0);
regularize_and_simplify_internal::Timer time;
Timer task_timer;
// basic geometric types
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::FT FT;
typedef typename regularize_and_simplify_internal::Rich_point<Kernel> Rich_point;
typedef typename rich_grid_internel::Rich_point<Kernel> Rich_point;
// precondition: at least one element in the container.
// to fix: should have at least three distinct points
@ -807,7 +323,7 @@ regularize_and_simplify_point_set_using_balltree(
std::vector<Rich_point> original_rich_point_set(nb_points_original);
std::vector<Rich_point> sample_rich_point_set(nb_points_sample);
regularize_and_simplify_internal::Rich_box<Kernel> box;
rich_grid_internel::Rich_box<Kernel> box;
for (it = first_original_point, i = 0; it != beyond ; ++it, i++)
{
Point& p0 = get(point_pmap,it);
@ -820,11 +336,11 @@ regularize_and_simplify_point_set_using_balltree(
std::vector<FT> original_density_weight_set;
if (need_compute_density)
{
time.start("Buile Ball Tree For Original");
regularize_and_simplify_internal::compute_ball_neighbors_one_self(original_rich_point_set, box, neighbor_radius);
time.end();
time.start("Compute Density For Original");
task_timer.start();
std::cout << "Initialization / Compute Density For Original" << std::endl;
rich_grid_internel::compute_ball_neighbors_one_self(original_rich_point_set, box, neighbor_radius);
for (it = first_original_point, i = 0; it != beyond ; ++it, i++)
{
std::vector<Point> original_neighbors;
@ -840,26 +356,30 @@ regularize_and_simplify_point_set_using_balltree(
original_density_weight_set.push_back(density);
original_rich_point_set[i].neighbors.clear();
}
time.end();
long memory = CGAL::Memory_sizer().virtual_size();
std::cout << "done: " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated" << std::endl << std::endl;
task_timer.stop();
}
for (unsigned int iter_n = 0; iter_n < iter_number; iter_n++)
{
task_timer.start();
std::cout << "Compute average term and repulsion term " << std::endl;
// Build Ball Tree For Sample Neighbor
time.start("Build Ball Tree For Sample Neighbor");
for (i=0 ; i < sample_points.size(); i++)
{
Point& p0 = sample_points[i];
Rich_point rp(p0, i);
sample_rich_point_set[i] = rp;
}
regularize_and_simplify_internal::compute_ball_neighbors_one_self(sample_rich_point_set, box, neighbor_radius);
time.end();
rich_grid_internel::compute_ball_neighbors_one_self(sample_rich_point_set, box, neighbor_radius);
// Compute sample density weight for sample points if user needed
std::vector<FT> sample_density_weight_set;
time.start("Compute Density For Sample");
if (need_compute_density)
{
for (i=0 ; i < sample_points.size(); i++)
@ -876,19 +396,17 @@ regularize_and_simplify_point_set_using_balltree(
sample_density_weight_set.push_back(density);
}
}
time.end();
// Build Ball Tree For Sample-Original Neighbor
time.start("Build Ball Tree For Sample-Original Neighbor");
regularize_and_simplify_internal::compute_ball_neighbors_one_to_another(sample_rich_point_set,
rich_grid_internel::compute_ball_neighbors_one_to_another(sample_rich_point_set,
original_rich_point_set, box, neighbor_radius);
time.end();
// Compute average term and repulsion term for each sample points separately,
// then update each sample points
std::vector<Vector> average_set(nb_points_sample);
std::vector<Vector> repulsion_set(nb_points_sample);
time.start("Compute Average Term");
// average term
for (i = 0; i < sample_points.size(); i++)
{
Point& p = sample_points[i];
@ -910,9 +428,8 @@ regularize_and_simplify_point_set_using_balltree(
average_set[i] = regularize_and_simplify_internal::compute_average_term<Kernel>(p, rich_original_neighbors, neighbor_radius, original_density_weight_set);
}
time.end();
time.start("Compute Repulsion Term");
//repulsion term
for (i = 0; i < sample_points.size(); i++)
{
std::vector<Rich_point> rich_sample_neighbors;
@ -934,15 +451,20 @@ regularize_and_simplify_point_set_using_balltree(
Point& p = sample_points[i];
repulsion_set[i] = regularize_and_simplify_internal::compute_repulsion_term<Kernel>(p, rich_sample_neighbors, neighbor_radius, sample_density_weight_set);
}
time.end();
// update points positions according to average and repulsion term
for (i = 0; i < sample_points.size(); i++)
{
Point& p = sample_points[i];
p = CGAL::ORIGIN + average_set[i] + (FT)0.5 * repulsion_set[i];
}
std::cout << "iterate: " << iter_n + 1 << " "<< std::endl;
long memory = CGAL::Memory_sizer().virtual_size();
std::cout << "done: " << task_timer.time() << " seconds, "
<< (memory>>20) << " Mb allocated" << std::endl;
task_timer.stop();
std::cout << "iterate: " << iter_n + 1 << " "<< std::endl << std::endl;;
}
//Copy back modified sample points to original points for output