mirror of https://github.com/CGAL/cgal
Merge pull request #3129 from sgiraudot/Point_set_processing-Callbacks-GF
Point Set Processing: Callbacks
This commit is contained in:
commit
c68cf8fc4c
|
|
@ -86,6 +86,7 @@ CGAL_add_named_parameter(query_point_t, query_point_map, query_point_map)
|
||||||
CGAL_add_named_parameter(normal_t, normal_map, normal_map)
|
CGAL_add_named_parameter(normal_t, normal_map, normal_map)
|
||||||
CGAL_add_named_parameter(diagonalize_traits_t, diagonalize_traits, diagonalize_traits)
|
CGAL_add_named_parameter(diagonalize_traits_t, diagonalize_traits, diagonalize_traits)
|
||||||
CGAL_add_named_parameter(svd_traits_t, svd_traits, svd_traits)
|
CGAL_add_named_parameter(svd_traits_t, svd_traits, svd_traits)
|
||||||
|
CGAL_add_named_parameter(callback_t, callback, callback)
|
||||||
CGAL_add_named_parameter(sharpness_angle_t, sharpness_angle, sharpness_angle)
|
CGAL_add_named_parameter(sharpness_angle_t, sharpness_angle, sharpness_angle)
|
||||||
CGAL_add_named_parameter(edge_sensitivity_t, edge_sensitivity, edge_sensitivity)
|
CGAL_add_named_parameter(edge_sensitivity_t, edge_sensitivity, edge_sensitivity)
|
||||||
CGAL_add_named_parameter(neighbor_radius_t, neighbor_radius, neighbor_radius)
|
CGAL_add_named_parameter(neighbor_radius_t, neighbor_radius, neighbor_radius)
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,18 @@ Release date: September 2018
|
||||||
to reflect the real needs of the code (some types and operators were used
|
to reflect the real needs of the code (some types and operators were used
|
||||||
in the code but did not appear in the concepts).
|
in the code but did not appear in the concepts).
|
||||||
|
|
||||||
|
### Point Set Processing
|
||||||
|
|
||||||
|
- Added a callback mechanism for functions
|
||||||
|
`CGAL::bilateral_smooth_point_set()`,
|
||||||
|
`CGAL::compute_average_spacing()`,
|
||||||
|
`CGAL::grid_simplify_point_set()`,
|
||||||
|
`CGAL::hierarchy_simplify_point_set()`,
|
||||||
|
`CGAL::jet_estimate_normals()`, `CGAL::jet_smooth_point_set()`,
|
||||||
|
`CGAL::pca_estimate_normals()`, `CGAL::remove_outliers()` and
|
||||||
|
`CGAL::wlop_simplify_and_regularize_point_set()`.
|
||||||
|
|
||||||
|
|
||||||
### Polygon Mesh Processing
|
### Polygon Mesh Processing
|
||||||
|
|
||||||
- Added a new named parameter for stitching that allows to perform
|
- Added a new named parameter for stitching that allows to perform
|
||||||
|
|
|
||||||
|
|
@ -195,9 +195,14 @@
|
||||||
#if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \
|
#if defined(BOOST_NO_0X_HDR_UNORDERED_SET) || \
|
||||||
defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \
|
defined(BOOST_NO_0X_HDR_UNORDERED_MAP) || \
|
||||||
defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) || \
|
defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) || \
|
||||||
defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP)
|
defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) || \
|
||||||
|
(defined(_MSC_VER) && (_MSC_VER == 1800)) // std::unordered_set is very bad in MSVC2013
|
||||||
#define CGAL_CFG_NO_CPP0X_UNORDERED 1
|
#define CGAL_CFG_NO_CPP0X_UNORDERED 1
|
||||||
#endif
|
#endif
|
||||||
|
#if defined( BOOST_NO_0X_HDR_THREAD) || \
|
||||||
|
defined( BOOST_NO_CXX11_HDR_THREAD)
|
||||||
|
#define CGAL_CFG_NO_STD_THREAD 1
|
||||||
|
#endif
|
||||||
#if defined(BOOST_NO_DECLTYPE) || \
|
#if defined(BOOST_NO_DECLTYPE) || \
|
||||||
defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600)
|
defined(BOOST_NO_CXX11_DECLTYPE) || (BOOST_VERSION < 103600)
|
||||||
#define CGAL_CFG_NO_CPP0X_DECLTYPE 1
|
#define CGAL_CFG_NO_CPP0X_DECLTYPE 1
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
# include <tbb/parallel_do.h>
|
# include <tbb/parallel_do.h>
|
||||||
|
# include <tbb/mutex.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
# if TBB_IMPLEMENT_CPP0X
|
# include <tbb/task_scheduler_init.h>
|
||||||
# include <tbb/compat/thread>
|
|
||||||
# else
|
|
||||||
# include <thread>
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
# include <tbb/task.h>
|
# include <tbb/task.h>
|
||||||
# include <tbb/tbb.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,9 @@
|
||||||
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
||||||
#include <CGAL/Meshes/Triangulation_mesher_level_traits_3.h>
|
#include <CGAL/Meshes/Triangulation_mesher_level_traits_3.h>
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
#include <tbb/tbb.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
|
#include <tbb/blocked_range.h>
|
||||||
|
#include <tbb/parallel_for.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <CGAL/Meshes/Filtered_deque_container.h>
|
#include <CGAL/Meshes/Filtered_deque_container.h>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@
|
||||||
#include <CGAL/Mesh_3/Mesher_level.h>
|
#include <CGAL/Mesh_3/Mesher_level.h>
|
||||||
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
#include <CGAL/Mesh_3/Mesher_level_default_implementations.h>
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
#include <tbb/tbb.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
|
#include <tbb/parallel_do.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <CGAL/Meshes/Filtered_deque_container.h>
|
#include <CGAL/Meshes/Filtered_deque_container.h>
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,14 @@ No default value.
|
||||||
\b Default: if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, then `CGAL::Eigen_svd` is used.\n
|
\b Default: if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined, then `CGAL::Eigen_svd` is used.\n
|
||||||
\cgalNPEnd
|
\cgalNPEnd
|
||||||
|
|
||||||
|
\cgalNPBegin{callback} \anchor PSP_callback
|
||||||
|
is a mechanism to get feedback on the advancement of the algorithm while it's running and to interrupt it if needed. It is called regularly when the algorithm is running: the current advancement (between 0. and 1.) is passed as parameter. If it returns `true`, then the algorithm continues its execution normally; if it returns `false`, the algorithm is stopped.\n
|
||||||
|
The callback will be copied and therefore needs to be lightweight.\n
|
||||||
|
Note that when a callback is run on a parallelized algorithm with `CGAL::Parallel_tag`, it is called asynchronously on a separate thread and shouldn't access or modify the variables that are parameters of the algorithm.\n
|
||||||
|
\b Type: `CGAL::cpp11::function<bool(double)>`.\n
|
||||||
|
\b Default: empty function.\n
|
||||||
|
\cgalNPEnd
|
||||||
|
|
||||||
\cgalNPBegin{query_point_map} \anchor PSP_query_point_map
|
\cgalNPBegin{query_point_map} \anchor PSP_query_point_map
|
||||||
is the property map containing the points associated to the iterators of the point range `queries`.\n
|
is the property map containing the points associated to the iterators of the point range `queries`.\n
|
||||||
\b Type: a class model of `ReadablePropertyMap` with
|
\b Type: a class model of `ReadablePropertyMap` with
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,26 @@ point set:
|
||||||
\cgalExample{Point_set_processing_3/structuring_example.cpp}
|
\cgalExample{Point_set_processing_3/structuring_example.cpp}
|
||||||
|
|
||||||
|
|
||||||
|
\section Point_set_processing_3Callbacks Callbacks
|
||||||
|
|
||||||
|
Several functions of this package provide a callback mechanism that enables the user to track the progress of the algorithms and to interrupt them if needed. A callback, in this package, is an instance of `CGAL::cpp11::function<bool(double)>` that takes the advancement as a parameter (between 0. when the algorithm begins to 1. when the algorithm is completed) and that returns `true` if the algorithm should carry on, `false` otherwise. It is passed as a named parameter with an empty function as default.
|
||||||
|
|
||||||
|
Algorithms that support this mechanism are detailed in the [Reference Manual](@ref PkgPointSetProcessing), along with the effect that an early interruption has on the output.
|
||||||
|
|
||||||
|
\subsection Point_set_processing_3Example_callbacks Example
|
||||||
|
|
||||||
|
The following example defines a callback that displays the name of the current algorithm along with the progress (as a percentage) updated every \f$1/10th\f$ of a second. While the algorithm is running, the console output will typically look like this:
|
||||||
|
|
||||||
|
\code{.sh}
|
||||||
|
Computing average spacing: 100%
|
||||||
|
Grid simplification: 100%
|
||||||
|
Jet smoothing: 54%
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Thanks to the carriage return character `\r`, the lines are overwritten and the user sees the percentage increasing on each line.
|
||||||
|
|
||||||
|
\cgalExample{Point_set_processing_3/callback_example.cpp}
|
||||||
|
|
||||||
|
|
||||||
\section Point_set_processing_3ImplementationHistory Implementation History
|
\section Point_set_processing_3ImplementationHistory Implementation History
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,5 @@
|
||||||
\example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp
|
\example Point_set_processing_3/edge_aware_upsample_point_set_example.cpp
|
||||||
\example Point_set_processing_3/edges_example.cpp
|
\example Point_set_processing_3/edges_example.cpp
|
||||||
\example Point_set_processing_3/structuring_example.cpp
|
\example Point_set_processing_3/structuring_example.cpp
|
||||||
|
\example Point_set_processing_3/callback_example.cpp
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ if ( CGAL_FOUND )
|
||||||
create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" )
|
create_single_source_cgal_program( "wlop_simplify_and_regularize_point_set_example.cpp" )
|
||||||
create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" )
|
create_single_source_cgal_program( "edge_aware_upsample_point_set_example.cpp" )
|
||||||
create_single_source_cgal_program( "structuring_example.cpp" )
|
create_single_source_cgal_program( "structuring_example.cpp" )
|
||||||
|
create_single_source_cgal_program( "callback_example.cpp" )
|
||||||
|
|
||||||
set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates)
|
set(needed_cxx_features cxx_rvalue_references cxx_variadic_templates)
|
||||||
create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} )
|
create_single_source_cgal_program( "read_ply_points_with_colors_example.cpp" CXX_FEATURES ${needed_cxx_features} )
|
||||||
|
|
@ -103,7 +104,8 @@ if ( CGAL_FOUND )
|
||||||
average_spacing_example
|
average_spacing_example
|
||||||
normals_example
|
normals_example
|
||||||
jet_smoothing_example
|
jet_smoothing_example
|
||||||
normal_estimation)
|
normal_estimation
|
||||||
|
callback_example)
|
||||||
if(TBB_FOUND AND TARGET ${target})
|
if(TBB_FOUND AND TARGET ${target})
|
||||||
CGAL_target_use_TBB(${target})
|
CGAL_target_use_TBB(${target})
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/point_generators_3.h>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
#include <CGAL/compute_average_spacing.h>
|
||||||
|
#include <CGAL/grid_simplify_point_set.h>
|
||||||
|
#include <CGAL/jet_smooth_point_set.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// Types
|
||||||
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
|
typedef Kernel::FT FT;
|
||||||
|
typedef Kernel::Point_3 Point;
|
||||||
|
typedef CGAL::Random_points_on_sphere_3<Point> Generator;
|
||||||
|
|
||||||
|
// Concurrency
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
#else
|
||||||
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// instance of CGAL::cpp11::function<bool(double)>
|
||||||
|
struct Progress_to_std_cerr_callback
|
||||||
|
{
|
||||||
|
mutable std::size_t nb;
|
||||||
|
CGAL::Real_timer timer;
|
||||||
|
double t_start;
|
||||||
|
mutable double t_latest;
|
||||||
|
const std::string name;
|
||||||
|
|
||||||
|
Progress_to_std_cerr_callback (const char* name)
|
||||||
|
: name (name)
|
||||||
|
{
|
||||||
|
timer.start();
|
||||||
|
t_start = timer.time();
|
||||||
|
t_latest = t_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(double advancement) const
|
||||||
|
{
|
||||||
|
// Avoid calling time() at every single iteration, which could
|
||||||
|
// impact performances very badly
|
||||||
|
++ nb;
|
||||||
|
if (advancement != 1 && nb % 10000 != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
double t = timer.time();
|
||||||
|
if (advancement == 1 || (t - t_latest) > 0.1) // Update every 1/10th of second
|
||||||
|
{
|
||||||
|
std::cerr << "\r" // Return at the beginning of same line and overwrite
|
||||||
|
<< name << ": " << int(advancement * 100) << "%";
|
||||||
|
|
||||||
|
if (advancement == 1)
|
||||||
|
std::cerr << std::endl;
|
||||||
|
t_latest = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
// Generate 1000000 points on a sphere of radius 100.
|
||||||
|
std::vector<Point> points;
|
||||||
|
points.reserve (1000000);
|
||||||
|
Generator generator(100.);
|
||||||
|
CGAL::cpp11::copy_n (generator, 1000000, std::back_inserter(points));
|
||||||
|
|
||||||
|
// Compute average spacing
|
||||||
|
FT average_spacing = CGAL::compute_average_spacing<Concurrency_tag>
|
||||||
|
(points, 6,
|
||||||
|
CGAL::parameters::callback
|
||||||
|
(Progress_to_std_cerr_callback("Computing average spacing")));
|
||||||
|
|
||||||
|
// Simplify on a grid with a size of twice the average spacing
|
||||||
|
points.erase(CGAL::grid_simplify_point_set
|
||||||
|
(points, 2. * average_spacing,
|
||||||
|
CGAL::parameters::callback
|
||||||
|
(Progress_to_std_cerr_callback("Grid simplification"))),
|
||||||
|
points.end());
|
||||||
|
|
||||||
|
// Smooth simplified point set
|
||||||
|
CGAL::jet_smooth_point_set<Concurrency_tag>
|
||||||
|
(points, 6,
|
||||||
|
CGAL::parameters::callback
|
||||||
|
(Progress_to_std_cerr_callback("Jet smoothing")));
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
#include <CGAL/Point_with_normal_3.h>
|
#include <CGAL/Point_with_normal_3.h>
|
||||||
#include <CGAL/squared_distance_3.h>
|
#include <CGAL/squared_distance_3.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -45,9 +46,11 @@
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/scalable_allocator.h>
|
#include <tbb/scalable_allocator.h>
|
||||||
|
#include <tbb/atomic.h>
|
||||||
#endif // CGAL_LINKED_WITH_TBB
|
#endif // CGAL_LINKED_WITH_TBB
|
||||||
|
|
||||||
// Default allocator: use TBB allocators if available
|
// Default allocator: use TBB allocators if available
|
||||||
|
|
@ -300,18 +303,27 @@ class Compute_pwns_neighbors
|
||||||
const Tree & m_tree;
|
const Tree & m_tree;
|
||||||
const Pwns & m_pwns;
|
const Pwns & m_pwns;
|
||||||
Pwns_neighbors & m_pwns_neighbors;
|
Pwns_neighbors & m_pwns_neighbors;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Compute_pwns_neighbors(unsigned int k, const Tree &tree,
|
Compute_pwns_neighbors(unsigned int k, const Tree &tree,
|
||||||
const Pwns &pwns, Pwns_neighbors &neighbors)
|
const Pwns &pwns, Pwns_neighbors &neighbors,
|
||||||
: m_k(k), m_tree(tree), m_pwns(pwns), m_pwns_neighbors(neighbors) {}
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted)
|
||||||
|
: m_k(k), m_tree(tree), m_pwns(pwns), m_pwns_neighbors(neighbors)
|
||||||
|
, advancement (advancement), interrupted (interrupted) {}
|
||||||
|
|
||||||
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
||||||
{
|
{
|
||||||
for (size_t i = r.begin(); i!=r.end(); i++)
|
for (size_t i = r.begin(); i!=r.end(); i++)
|
||||||
{
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
|
|
||||||
m_pwns_neighbors[i] = bilateral_smooth_point_set_internal::
|
m_pwns_neighbors[i] = bilateral_smooth_point_set_internal::
|
||||||
compute_kdtree_neighbors<Kernel, Tree>(m_pwns[i], m_tree, m_k);
|
compute_kdtree_neighbors<Kernel, Tree>(m_pwns[i], m_tree, m_k);
|
||||||
|
++ advancement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -331,30 +343,37 @@ class Pwn_updater
|
||||||
Pwns* pwns;
|
Pwns* pwns;
|
||||||
Pwns* update_pwns;
|
Pwns* update_pwns;
|
||||||
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors;
|
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Pwn_updater(FT sharpness,
|
Pwn_updater(FT sharpness,
|
||||||
FT r,
|
FT r,
|
||||||
Pwns *in,
|
Pwns *in,
|
||||||
Pwns *out,
|
Pwns *out,
|
||||||
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* neighbors):
|
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* neighbors,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted):
|
||||||
sharpness_angle(sharpness),
|
sharpness_angle(sharpness),
|
||||||
radius(r),
|
radius(r),
|
||||||
pwns(in),
|
pwns(in),
|
||||||
update_pwns(out),
|
update_pwns(out),
|
||||||
pwns_neighbors(neighbors){}
|
pwns_neighbors(neighbors),
|
||||||
|
advancement (advancement),
|
||||||
|
interrupted (interrupted) {}
|
||||||
|
|
||||||
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
||||||
{
|
{
|
||||||
for (size_t i = r.begin(); i != r.end(); ++i)
|
for (size_t i = r.begin(); i != r.end(); ++i)
|
||||||
{
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
(*update_pwns)[i] = bilateral_smooth_point_set_internal::
|
(*update_pwns)[i] = bilateral_smooth_point_set_internal::
|
||||||
compute_denoise_projection<Kernel>((*pwns)[i],
|
compute_denoise_projection<Kernel>((*pwns)[i],
|
||||||
(*pwns_neighbors)[i],
|
(*pwns_neighbors)[i],
|
||||||
radius,
|
radius,
|
||||||
sharpness_angle);
|
sharpness_angle);
|
||||||
|
++ advancement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -402,6 +421,13 @@ public:
|
||||||
\cgalParamBegin{normal_map} a model of `ReadWritePropertyMap` with value type
|
\cgalParamBegin{normal_map} a model of `ReadWritePropertyMap` with value type
|
||||||
`geom_traits::Vector_3`.\cgalParamEnd
|
`geom_traits::Vector_3`.\cgalParamEnd
|
||||||
\cgalParamBegin{sharpness_angle} controls the sharpness of the result.\cgalParamEnd
|
\cgalParamBegin{sharpness_angle} controls the sharpness of the result.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped, all points are left unchanged
|
||||||
|
and the function return `NaN`.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -434,6 +460,8 @@ bilateral_smooth_point_set(
|
||||||
typedef typename Kernel::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
|
|
||||||
double sharpness_angle = choose_param(get_param(np, internal_np::sharpness_angle), 30.);
|
double sharpness_angle = choose_param(get_param(np, internal_np::sharpness_angle), 30.);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
CGAL_point_set_processing_precondition(points.begin() != points.end());
|
CGAL_point_set_processing_precondition(points.begin() != points.end());
|
||||||
CGAL_point_set_processing_precondition(k > 1);
|
CGAL_point_set_processing_precondition(k > 1);
|
||||||
|
|
@ -513,8 +541,23 @@ bilateral_smooth_point_set(
|
||||||
#else
|
#else
|
||||||
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
Compute_pwns_neighbors<Kernel, Tree> f(k, tree, pwns, pwns_neighbors);
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, 2 * nb_points);
|
||||||
|
|
||||||
|
Compute_pwns_neighbors<Kernel, Tree> f(k, tree, pwns, pwns_neighbors,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f);
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f);
|
||||||
|
|
||||||
|
bool interrupted = parallel_callback.interrupted();
|
||||||
|
|
||||||
|
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||||
|
parallel_callback.interrupted() = true;
|
||||||
|
parallel_callback.join();
|
||||||
|
|
||||||
|
// If interrupted during this step, nothing is computed, we return NaN
|
||||||
|
if (interrupted)
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -522,10 +565,13 @@ bilateral_smooth_point_set(
|
||||||
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
||||||
pwns_iter = pwns_neighbors.begin();
|
pwns_iter = pwns_neighbors.begin();
|
||||||
|
|
||||||
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter, ++pwns_iter)
|
std::size_t nb = 0;
|
||||||
|
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter, ++pwns_iter, ++ nb)
|
||||||
{
|
{
|
||||||
*pwns_iter = bilateral_smooth_point_set_internal::
|
*pwns_iter = bilateral_smooth_point_set_internal::
|
||||||
compute_kdtree_neighbors<Kernel, Tree>(*pwn_iter, tree, k);
|
compute_kdtree_neighbors<Kernel, Tree>(*pwn_iter, tree, k);
|
||||||
|
if (callback && !callback ((nb+1) / double(2. * nb_points)))
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -545,24 +591,37 @@ bilateral_smooth_point_set(
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
|
if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, 2 * nb_points, nb_points);
|
||||||
|
|
||||||
//tbb::task_scheduler_init init(4);
|
//tbb::task_scheduler_init init(4);
|
||||||
tbb::blocked_range<size_t> block(0, nb_points);
|
tbb::blocked_range<size_t> block(0, nb_points);
|
||||||
Pwn_updater<Kernel> pwn_updater(sharpness_angle,
|
Pwn_updater<Kernel> pwn_updater(sharpness_angle,
|
||||||
guess_neighbor_radius,
|
guess_neighbor_radius,
|
||||||
&pwns,
|
&pwns,
|
||||||
&update_pwns,
|
&update_pwns,
|
||||||
&pwns_neighbors);
|
&pwns_neighbors,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(block, pwn_updater);
|
tbb::parallel_for(block, pwn_updater);
|
||||||
|
|
||||||
|
parallel_callback.join();
|
||||||
|
|
||||||
|
// If interrupted during this step, nothing is computed, we return NaN
|
||||||
|
if (parallel_callback.interrupted())
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif // CGAL_LINKED_WITH_TBB
|
#endif // CGAL_LINKED_WITH_TBB
|
||||||
{
|
{
|
||||||
|
std::size_t nb = nb_points;
|
||||||
|
|
||||||
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
|
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
|
||||||
update_iter = update_pwns.begin();
|
update_iter = update_pwns.begin();
|
||||||
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
|
||||||
neighbor_iter = pwns_neighbors.begin();
|
neighbor_iter = pwns_neighbors.begin();
|
||||||
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end();
|
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end();
|
||||||
++pwn_iter, ++update_iter, ++neighbor_iter)
|
++pwn_iter, ++update_iter, ++neighbor_iter, ++ nb)
|
||||||
{
|
{
|
||||||
*update_iter = bilateral_smooth_point_set_internal::
|
*update_iter = bilateral_smooth_point_set_internal::
|
||||||
compute_denoise_projection<Kernel>
|
compute_denoise_projection<Kernel>
|
||||||
|
|
@ -570,6 +629,8 @@ bilateral_smooth_point_set(
|
||||||
*neighbor_iter,
|
*neighbor_iter,
|
||||||
guess_neighbor_radius,
|
guess_neighbor_radius,
|
||||||
sharpness_angle);
|
sharpness_angle);
|
||||||
|
if (callback && !callback ((nb+1) / double(2. * nb_points)))
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef CGAL_PSP3_VERBOSE
|
#ifdef CGAL_PSP3_VERBOSE
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
#include <CGAL/assertions.h>
|
#include <CGAL/assertions.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -39,9 +40,10 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/scalable_allocator.h>
|
#include <tbb/scalable_allocator.h>
|
||||||
#endif // CGAL_LINKED_WITH_TBB
|
#endif // CGAL_LINKED_WITH_TBB
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
@ -109,17 +111,29 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who
|
||||||
const unsigned int k;
|
const unsigned int k;
|
||||||
const std::vector<Point>& input;
|
const std::vector<Point>& input;
|
||||||
std::vector<FT>& output;
|
std::vector<FT>& output;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Compute_average_spacings(Tree& tree, unsigned int k, std::vector<Point>& points,
|
Compute_average_spacings(Tree& tree, unsigned int k, std::vector<Point>& points,
|
||||||
std::vector<FT>& output)
|
std::vector<FT>& output,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted)
|
||||||
: tree(tree), k (k), input (points), output (output)
|
: tree(tree), k (k), input (points), output (output)
|
||||||
|
, advancement (advancement)
|
||||||
|
, interrupted (interrupted)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||||
{
|
{
|
||||||
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
||||||
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
|
|
||||||
output[i] = CGAL::internal::compute_average_spacing<Kernel,Tree>(input[i], tree, k);
|
output[i] = CGAL::internal::compute_average_spacing<Kernel,Tree>(input[i], tree, k);
|
||||||
|
++ advancement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -153,6 +167,13 @@ compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point who
|
||||||
\cgalNamedParamsBegin
|
\cgalNamedParamsBegin
|
||||||
\cgalParamBegin{point_map} a model of `ReadablePropertyMap` with value type `geom_traits::Point_3`.
|
\cgalParamBegin{point_map} a model of `ReadablePropertyMap` with value type `geom_traits::Point_3`.
|
||||||
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and the average spacing value
|
||||||
|
estimated on the processed subset is returned.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -184,6 +205,8 @@ compute_average_spacing(
|
||||||
typedef typename Kernel::Point_3 Point;
|
typedef typename Kernel::Point_3 Point;
|
||||||
|
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
// types for K nearest neighbors search structure
|
// types for K nearest neighbors search structure
|
||||||
typedef typename Kernel::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
|
|
@ -209,6 +232,7 @@ compute_average_spacing(
|
||||||
// iterate over input points, compute and output normal
|
// iterate over input points, compute and output normal
|
||||||
// vectors (already normalized)
|
// vectors (already normalized)
|
||||||
FT sum_spacings = (FT)0.0;
|
FT sum_spacings = (FT)0.0;
|
||||||
|
std::size_t nb = 0;
|
||||||
|
|
||||||
#ifndef CGAL_LINKED_WITH_TBB
|
#ifndef CGAL_LINKED_WITH_TBB
|
||||||
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
||||||
|
|
@ -216,26 +240,43 @@ compute_average_spacing(
|
||||||
#else
|
#else
|
||||||
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
std::vector<FT> spacings (kd_tree_points.size ());
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, kd_tree_points.size());
|
||||||
|
|
||||||
|
std::vector<FT> spacings (kd_tree_points.size (), -1);
|
||||||
CGAL::internal::Compute_average_spacings<Kernel, Tree>
|
CGAL::internal::Compute_average_spacings<Kernel, Tree>
|
||||||
f (tree, k, kd_tree_points, spacings);
|
f (tree, k, kd_tree_points, spacings,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < spacings.size (); ++ i)
|
for (unsigned int i = 0; i < spacings.size (); ++ i)
|
||||||
sum_spacings += spacings[i];
|
if (spacings[i] >= 0.)
|
||||||
|
{
|
||||||
|
sum_spacings += spacings[i];
|
||||||
|
++ nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
parallel_callback.join();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++)
|
for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++, nb++)
|
||||||
{
|
{
|
||||||
sum_spacings += internal::compute_average_spacing<Kernel,Tree>(
|
sum_spacings += internal::compute_average_spacing<Kernel,Tree>(
|
||||||
get(point_map,*it),
|
get(point_map,*it),
|
||||||
tree,k);
|
tree,k);
|
||||||
}
|
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||||
|
{
|
||||||
|
++ nb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return average spacing
|
// return average spacing
|
||||||
return sum_spacings / (FT)(kd_tree_points.size ());
|
return sum_spacings / (FT)(nb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
#include <CGAL/unordered.h>
|
#include <CGAL/unordered.h>
|
||||||
#include <CGAL/Iterator_range.h>
|
#include <CGAL/Iterator_range.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
|
|
@ -188,6 +189,13 @@ public:
|
||||||
\cgalNamedParamsBegin
|
\cgalNamedParamsBegin
|
||||||
\cgalParamBegin{point_map} a model of `ReadWritePropertyMap` with value type `geom_traits::Point_3`.
|
\cgalParamBegin{point_map} a model of `ReadWritePropertyMap` with value type `geom_traits::Point_3`.
|
||||||
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and simplification stops with
|
||||||
|
no guarantee on the output.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -204,6 +212,8 @@ grid_simplify_point_set(
|
||||||
|
|
||||||
typedef typename Point_set_processing_3::GetPointMap<PointRange, NamedParameters>::const_type PointMap;
|
typedef typename Point_set_processing_3::GetPointMap<PointRange, NamedParameters>::const_type PointMap;
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
// actual type of input points
|
// actual type of input points
|
||||||
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Enriched_point;
|
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Enriched_point;
|
||||||
|
|
@ -214,12 +224,15 @@ grid_simplify_point_set(
|
||||||
// points_to_keep[] will contain 1 point per cell; the others will be in points_to_remove[].
|
// points_to_keep[] will contain 1 point per cell; the others will be in points_to_remove[].
|
||||||
Epsilon_point_set_3<Enriched_point, PointMap> points_to_keep(epsilon, point_map);
|
Epsilon_point_set_3<Enriched_point, PointMap> points_to_keep(epsilon, point_map);
|
||||||
std::deque<Enriched_point> points_to_remove;
|
std::deque<Enriched_point> points_to_remove;
|
||||||
for (typename PointRange::iterator it = points.begin(); it != points.end(); it++)
|
std::size_t nb = 0, nb_points = points.size();
|
||||||
|
for (typename PointRange::iterator it = points.begin(); it != points.end(); it++, ++ nb)
|
||||||
{
|
{
|
||||||
std::pair<typename Epsilon_point_set_3<Enriched_point, PointMap>::iterator,bool> result;
|
std::pair<typename Epsilon_point_set_3<Enriched_point, PointMap>::iterator,bool> result;
|
||||||
result = points_to_keep.insert(*it);
|
result = points_to_keep.insert(*it);
|
||||||
if (!result.second) // if not inserted
|
if (!result.second) // if not inserted
|
||||||
points_to_remove.push_back(*it);
|
points_to_remove.push_back(*it);
|
||||||
|
if (callback && !callback ((nb+1) / double(nb_points)))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces `[first, beyond)` range by the content of points_to_keep, then points_to_remove.
|
// Replaces `[first, beyond)` range by the content of points_to_keep, then points_to_remove.
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include <CGAL/PCA_util.h>
|
#include <CGAL/PCA_util.h>
|
||||||
#include <CGAL/squared_distance_3.h>
|
#include <CGAL/squared_distance_3.h>
|
||||||
#include <CGAL/Iterator_range.h>
|
#include <CGAL/Iterator_range.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -142,6 +143,13 @@ namespace CGAL {
|
||||||
if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined then an overload
|
if Eigen 3 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined then an overload
|
||||||
using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation
|
using `Eigen_diagonalize_traits` is provided. Otherwise, the internal implementation
|
||||||
`CGAL::Diagonalize_traits` is used.\cgalParamEnd
|
`CGAL::Diagonalize_traits` is used.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and simplification stops with
|
||||||
|
no guarantee on the output.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -167,6 +175,8 @@ namespace CGAL {
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
unsigned int size = choose_param(get_param(np, internal_np::size), 10);
|
unsigned int size = choose_param(get_param(np, internal_np::size), 10);
|
||||||
double var_max = choose_param(get_param(np, internal_np::maximum_variation), 1./3.);
|
double var_max = choose_param(get_param(np, internal_np::maximum_variation), 1./3.);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Input_type;
|
typedef typename std::iterator_traits<typename PointRange::iterator>::value_type Input_type;
|
||||||
|
|
||||||
|
|
@ -191,6 +201,8 @@ namespace CGAL {
|
||||||
|
|
||||||
std::list<Input_type> points_to_keep;
|
std::list<Input_type> points_to_keep;
|
||||||
std::list<Input_type> points_to_remove;
|
std::list<Input_type> points_to_remove;
|
||||||
|
|
||||||
|
std::size_t nb_done = 0;
|
||||||
|
|
||||||
while (!(clusters_stack.empty ()))
|
while (!(clusters_stack.empty ()))
|
||||||
{
|
{
|
||||||
|
|
@ -203,6 +215,7 @@ namespace CGAL {
|
||||||
points_to_keep.splice (points_to_keep.end (), current_cluster->first,
|
points_to_keep.splice (points_to_keep.end (), current_cluster->first,
|
||||||
current_cluster->first.begin ());
|
current_cluster->first.begin ());
|
||||||
clusters_stack.pop_front ();
|
clusters_stack.pop_front ();
|
||||||
|
++ nb_done;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,6 +281,7 @@ namespace CGAL {
|
||||||
cluster_iterator nonempty = (current_cluster->first.empty ()
|
cluster_iterator nonempty = (current_cluster->first.empty ()
|
||||||
? negative_side : current_cluster);
|
? negative_side : current_cluster);
|
||||||
|
|
||||||
|
nb_done += nonempty->first.size();
|
||||||
// Compute the centroid
|
// Compute the centroid
|
||||||
nonempty->second = internal::hsps_centroid (nonempty->first.begin (),
|
nonempty->second = internal::hsps_centroid (nonempty->first.begin (),
|
||||||
nonempty->first.end (),
|
nonempty->first.end (),
|
||||||
|
|
@ -279,6 +293,7 @@ namespace CGAL {
|
||||||
point_map,
|
point_map,
|
||||||
nonempty->second,
|
nonempty->second,
|
||||||
Kernel ());
|
Kernel ());
|
||||||
|
|
||||||
clusters_stack.pop_front ();
|
clusters_stack.pop_front ();
|
||||||
clusters_stack.pop_front ();
|
clusters_stack.pop_front ();
|
||||||
}
|
}
|
||||||
|
|
@ -311,6 +326,7 @@ namespace CGAL {
|
||||||
// and output point
|
// and output point
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
nb_done += current_cluster->first.size();
|
||||||
internal::hsc_terminate_cluster (current_cluster->first,
|
internal::hsc_terminate_cluster (current_cluster->first,
|
||||||
points_to_keep,
|
points_to_keep,
|
||||||
points_to_remove,
|
points_to_remove,
|
||||||
|
|
@ -319,7 +335,14 @@ namespace CGAL {
|
||||||
Kernel ());
|
Kernel ());
|
||||||
clusters_stack.pop_front ();
|
clusters_stack.pop_front ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callback && !callback (nb_done / double (points.size())))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
callback (1.);
|
||||||
|
|
||||||
typename PointRange::iterator first_point_to_remove =
|
typename PointRange::iterator first_point_to_remove =
|
||||||
std::copy (points_to_keep.begin(), points_to_keep.end(), points.begin());
|
std::copy (points_to_keep.begin(), points_to_keep.end(), points.begin());
|
||||||
std::copy (points_to_remove.begin(), points_to_remove.end(), first_point_to_remove);
|
std::copy (points_to_remove.begin(), points_to_remove.end(), first_point_to_remove);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright (c) 2018 GeometryFactory (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$
|
||||||
|
// SPDX-License-Identifier: GPL-3.0+
|
||||||
|
//
|
||||||
|
// Author(s) : Simon Giraudot
|
||||||
|
|
||||||
|
#ifndef CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H
|
||||||
|
#define CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H
|
||||||
|
|
||||||
|
#include <CGAL/license/Point_set_processing_3.h>
|
||||||
|
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
|
#include <CGAL/thread.h>
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
namespace internal {
|
||||||
|
namespace Point_set_processing_3 {
|
||||||
|
|
||||||
|
class Parallel_callback
|
||||||
|
{
|
||||||
|
const cpp11::function<bool(double)>& m_callback;
|
||||||
|
cpp11::atomic<std::size_t>* m_advancement;
|
||||||
|
cpp11::atomic<bool>* m_interrupted;
|
||||||
|
std::size_t m_size;
|
||||||
|
bool m_creator;
|
||||||
|
cpp11::thread* m_thread;
|
||||||
|
|
||||||
|
// assignment operator shouldn't be used (m_callback is const ref)
|
||||||
|
Parallel_callback& operator= (const Parallel_callback&)
|
||||||
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Parallel_callback (const cpp11::function<bool(double)>& callback,
|
||||||
|
std::size_t size,
|
||||||
|
std::size_t advancement = 0,
|
||||||
|
bool interrupted = false)
|
||||||
|
: m_callback (callback)
|
||||||
|
, m_advancement (new cpp11::atomic<std::size_t>())
|
||||||
|
, m_interrupted (new cpp11::atomic<bool>())
|
||||||
|
, m_size (size)
|
||||||
|
, m_creator (true)
|
||||||
|
, m_thread (NULL)
|
||||||
|
{
|
||||||
|
// cpp11::atomic only has default constructor, initialization done in two steps
|
||||||
|
*m_advancement = advancement;
|
||||||
|
*m_interrupted = interrupted;
|
||||||
|
if (m_callback)
|
||||||
|
m_thread = new cpp11::thread (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parallel_callback (const Parallel_callback& other)
|
||||||
|
: m_callback (other.m_callback)
|
||||||
|
, m_advancement (other.m_advancement)
|
||||||
|
, m_interrupted (other.m_interrupted)
|
||||||
|
, m_size (other.m_size)
|
||||||
|
, m_creator (false)
|
||||||
|
, m_thread (NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~Parallel_callback ()
|
||||||
|
{
|
||||||
|
if (m_creator)
|
||||||
|
{
|
||||||
|
delete m_advancement;
|
||||||
|
delete m_interrupted;
|
||||||
|
}
|
||||||
|
if (m_thread != NULL)
|
||||||
|
delete m_thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpp11::atomic<std::size_t>& advancement() { return *m_advancement; }
|
||||||
|
cpp11::atomic<bool>& interrupted() { return *m_interrupted; }
|
||||||
|
void join()
|
||||||
|
{
|
||||||
|
if (m_thread != NULL)
|
||||||
|
m_thread->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
while (*m_advancement != m_size)
|
||||||
|
{
|
||||||
|
if (!m_callback (*m_advancement / double(m_size)))
|
||||||
|
*m_interrupted = true;
|
||||||
|
if (*m_interrupted)
|
||||||
|
return;
|
||||||
|
cpp11::sleep_for (0.00001);
|
||||||
|
}
|
||||||
|
m_callback (1.);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Point_set_processing_3
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace CGAL
|
||||||
|
|
||||||
|
#endif // CGAL_INTERNAL_PSP_PARALLEL_CALLBACK_H
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
#include <CGAL/Memory_sizer.h>
|
#include <CGAL/Memory_sizer.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -40,6 +41,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/scalable_allocator.h>
|
#include <tbb/scalable_allocator.h>
|
||||||
|
|
@ -125,17 +127,28 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
|
||||||
const unsigned int degree_fitting;
|
const unsigned int degree_fitting;
|
||||||
const std::vector<Point>& input;
|
const std::vector<Point>& input;
|
||||||
std::vector<Vector>& output;
|
std::vector<Vector>& output;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Jet_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
|
Jet_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
|
||||||
unsigned int degree_fitting, std::vector<Vector>& output)
|
unsigned int degree_fitting, std::vector<Vector>& output,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted)
|
||||||
: tree(tree), k (k), degree_fitting (degree_fitting), input (points), output (output)
|
: tree(tree), k (k), degree_fitting (degree_fitting), input (points), output (output)
|
||||||
|
, advancement (advancement)
|
||||||
|
, interrupted (interrupted)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||||
{
|
{
|
||||||
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
||||||
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
output[i] = CGAL::internal::jet_estimate_normal<Kernel,SvdTraits>(input[i], tree, k, degree_fitting);
|
output[i] = CGAL::internal::jet_estimate_normal<Kernel,SvdTraits>(input[i], tree, k, degree_fitting);
|
||||||
|
++ advancement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -179,6 +192,13 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
|
||||||
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
|
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
|
||||||
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
|
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
|
||||||
then `CGAL::Eigen_svd` is used.\cgalParamEnd
|
then `CGAL::Eigen_svd` is used.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and the remaining normals are
|
||||||
|
left unchanged.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
*/
|
*/
|
||||||
|
|
@ -212,6 +232,8 @@ jet_estimate_normals(
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
|
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
|
||||||
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
|
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename Kernel::Point_3 Point;
|
typedef typename Kernel::Point_3 Point;
|
||||||
|
|
||||||
|
|
@ -254,28 +276,37 @@ jet_estimate_normals(
|
||||||
#else
|
#else
|
||||||
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
std::vector<Vector> normals (kd_tree_points.size ());
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, kd_tree_points.size());
|
||||||
|
|
||||||
|
std::vector<Vector> normals (kd_tree_points.size (),
|
||||||
|
CGAL::NULL_VECTOR);
|
||||||
CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree>
|
CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree>
|
||||||
f (tree, k, kd_tree_points, degree_fitting, normals);
|
f (tree, k, kd_tree_points, degree_fitting, normals,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
||||||
unsigned int i = 0;
|
std::size_t i = 0;
|
||||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||||
{
|
if (normals[i] != CGAL::NULL_VECTOR)
|
||||||
put (normal_map, *it, normals[i]);
|
put (normal_map, *it, normals[i]);
|
||||||
}
|
|
||||||
|
parallel_callback.join();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
for(it = points.begin(); it != points.end(); it++)
|
std::size_t nb = 0;
|
||||||
|
for(it = points.begin(); it != points.end(); it++, ++ nb)
|
||||||
{
|
{
|
||||||
Vector normal = internal::jet_estimate_normal<Kernel,SvdTraits,Tree>(
|
Vector normal = internal::jet_estimate_normal<Kernel,SvdTraits,Tree>(
|
||||||
get(point_map,*it),
|
get(point_map,*it),
|
||||||
tree, k, degree_fitting);
|
tree, k, degree_fitting);
|
||||||
|
|
||||||
put(normal_map, *it, normal); // normal_map[it] = normal
|
put(normal_map, *it, normal); // normal_map[it] = normal
|
||||||
|
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <CGAL/Monge_via_jet_fitting.h>
|
#include <CGAL/Monge_via_jet_fitting.h>
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -39,6 +40,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/scalable_allocator.h>
|
#include <tbb/scalable_allocator.h>
|
||||||
|
|
@ -125,20 +127,31 @@ jet_smooth_point(
|
||||||
unsigned int degree_monge;
|
unsigned int degree_monge;
|
||||||
const std::vector<Point>& input;
|
const std::vector<Point>& input;
|
||||||
std::vector<Point>& output;
|
std::vector<Point>& output;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Jet_smooth_pwns (Tree& tree, unsigned int k, std::vector<Point>& points,
|
Jet_smooth_pwns (Tree& tree, unsigned int k, std::vector<Point>& points,
|
||||||
unsigned int degree_fitting, unsigned int degree_monge, std::vector<Point>& output)
|
unsigned int degree_fitting, unsigned int degree_monge, std::vector<Point>& output,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted)
|
||||||
: tree(tree), k (k), degree_fitting (degree_fitting),
|
: tree(tree), k (k), degree_fitting (degree_fitting),
|
||||||
degree_monge (degree_monge), input (points), output (output)
|
degree_monge (degree_monge), input (points), output (output)
|
||||||
|
, advancement (advancement)
|
||||||
|
, interrupted (interrupted)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||||
{
|
{
|
||||||
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
||||||
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
output[i] = CGAL::internal::jet_smooth_point<Kernel, SvdTraits>(input[i], tree, k,
|
output[i] = CGAL::internal::jet_smooth_point<Kernel, SvdTraits>(input[i], tree, k,
|
||||||
degree_fitting,
|
degree_fitting,
|
||||||
degree_monge);
|
degree_monge);
|
||||||
|
++ advancement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -182,6 +195,13 @@ jet_smooth_point(
|
||||||
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
|
\cgalParamBegin{svd_traits} template parameter for the class `Monge_via_jet_fitting`. If
|
||||||
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
|
\ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and `CGAL_EIGEN3_ENABLED` is defined,
|
||||||
then `CGAL::Eigen_svd` is used.\cgalParamEnd
|
then `CGAL::Eigen_svd` is used.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and the remaining points are
|
||||||
|
left unchanged.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -210,6 +230,8 @@ jet_smooth_point_set(
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
|
unsigned int degree_fitting = choose_param(get_param(np, internal_np::degree_fitting), 2);
|
||||||
unsigned int degree_monge = choose_param(get_param(np, internal_np::degree_monge), 2);
|
unsigned int degree_monge = choose_param(get_param(np, internal_np::degree_monge), 2);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename Kernel::Point_3 Point;
|
typedef typename Kernel::Point_3 Point;
|
||||||
|
|
||||||
|
|
@ -244,27 +266,36 @@ jet_smooth_point_set(
|
||||||
#else
|
#else
|
||||||
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
std::vector<Point> mutated_points (kd_tree_points.size ());
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, kd_tree_points.size());
|
||||||
|
|
||||||
|
std::vector<Point> mutated_points (kd_tree_points.size (), CGAL::ORIGIN);
|
||||||
CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree>
|
CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree>
|
||||||
f (tree, k, kd_tree_points, degree_fitting, degree_monge,
|
f (tree, k, kd_tree_points, degree_fitting, degree_monge,
|
||||||
mutated_points);
|
mutated_points,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||||
{
|
if (mutated_points[i] != CGAL::ORIGIN)
|
||||||
put(point_map, *it, mutated_points[i]);
|
put(point_map, *it, mutated_points[i]);
|
||||||
|
|
||||||
|
parallel_callback.join();
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
for(it = points.begin(); it != points.end(); it++)
|
std::size_t nb = 0;
|
||||||
|
for(it = points.begin(); it != points.end(); it++, ++ nb)
|
||||||
{
|
{
|
||||||
const typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
|
const typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
|
||||||
put(point_map, *it ,
|
put(point_map, *it ,
|
||||||
internal::jet_smooth_point<Kernel, SvdTraits>(
|
internal::jet_smooth_point<Kernel, SvdTraits>(
|
||||||
p,tree,k,degree_fitting,degree_monge) );
|
p,tree,k,degree_fitting,degree_monge) );
|
||||||
|
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
#include <CGAL/Memory_sizer.h>
|
#include <CGAL/Memory_sizer.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -41,6 +42,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
#include <tbb/scalable_allocator.h>
|
#include <tbb/scalable_allocator.h>
|
||||||
|
|
@ -117,17 +119,28 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
|
||||||
const unsigned int k;
|
const unsigned int k;
|
||||||
const std::vector<Point>& input;
|
const std::vector<Point>& input;
|
||||||
std::vector<Vector>& output;
|
std::vector<Vector>& output;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PCA_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
|
PCA_estimate_normals(Tree& tree, unsigned int k, std::vector<Point>& points,
|
||||||
std::vector<Vector>& output)
|
std::vector<Vector>& output,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted)
|
||||||
: tree(tree), k (k), input (points), output (output)
|
: tree(tree), k (k), input (points), output (output)
|
||||||
|
, advancement (advancement)
|
||||||
|
, interrupted (interrupted)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
void operator()(const tbb::blocked_range<std::size_t>& r) const
|
||||||
{
|
{
|
||||||
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
for( std::size_t i = r.begin(); i != r.end(); ++i)
|
||||||
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
output[i] = CGAL::internal::pca_estimate_normal<Kernel,Tree>(input[i], tree, k);
|
output[i] = CGAL::internal::pca_estimate_normal<Kernel,Tree>(input[i], tree, k);
|
||||||
|
++ advancement;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -166,6 +179,13 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
|
||||||
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
If this parameter is omitted, `CGAL::Identity_property_map<geom_traits::Point_3>` is used.\cgalParamEnd
|
||||||
\cgalParamBegin{normal_map} a model of `WritablePropertyMap` with value type
|
\cgalParamBegin{normal_map} a model of `WritablePropertyMap` with value type
|
||||||
`geom_traits::Vector_3`.\cgalParamEnd
|
`geom_traits::Vector_3`.\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped and the remaining normals are
|
||||||
|
left unchanged.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
*/
|
*/
|
||||||
|
|
@ -193,6 +213,8 @@ pca_estimate_normals(
|
||||||
|
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
|
NormalMap normal_map = choose_param(get_param(np, internal_np::normal_map), NormalMap());
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename Kernel::Point_3 Point;
|
typedef typename Kernel::Point_3 Point;
|
||||||
|
|
||||||
|
|
@ -235,20 +257,28 @@ pca_estimate_normals(
|
||||||
#else
|
#else
|
||||||
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
std::vector<Vector> normals (kd_tree_points.size ());
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, kd_tree_points.size());
|
||||||
|
|
||||||
|
std::vector<Vector> normals (kd_tree_points.size (),
|
||||||
|
CGAL::NULL_VECTOR);
|
||||||
CGAL::internal::PCA_estimate_normals<Kernel, Tree>
|
CGAL::internal::PCA_estimate_normals<Kernel, Tree>
|
||||||
f (tree, k, kd_tree_points, normals);
|
f (tree, k, kd_tree_points, normals,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
for(it = points.begin(); it != points.end(); ++ it, ++ i)
|
||||||
{
|
if (normals[i] != CGAL::NULL_VECTOR)
|
||||||
put (normal_map, *it, normals[i]);
|
put (normal_map, *it, normals[i]);
|
||||||
}
|
|
||||||
|
parallel_callback.join();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
for(it = points.begin(); it != points.end(); it++)
|
std::size_t nb = 0;
|
||||||
|
for(it = points.begin(); it != points.end(); it++, ++ nb)
|
||||||
{
|
{
|
||||||
Vector normal = internal::pca_estimate_normal<Kernel,Tree>(
|
Vector normal = internal::pca_estimate_normal<Kernel,Tree>(
|
||||||
get(point_map,*it),
|
get(point_map,*it),
|
||||||
|
|
@ -256,6 +286,8 @@ pca_estimate_normals(
|
||||||
k);
|
k);
|
||||||
|
|
||||||
put(normal_map, *it, normal); // normal_map[it] = normal
|
put(normal_map, *it, normal); // normal_map[it] = normal
|
||||||
|
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
#include <CGAL/Orthogonal_k_neighbor_search.h>
|
||||||
#include <CGAL/property_map.h>
|
#include <CGAL/property_map.h>
|
||||||
#include <CGAL/point_set_processing_assertions.h>
|
#include <CGAL/point_set_processing_assertions.h>
|
||||||
|
#include <CGAL/function.h>
|
||||||
|
|
||||||
#include <CGAL/boost/graph/named_function_params.h>
|
#include <CGAL/boost/graph/named_function_params.h>
|
||||||
#include <CGAL/boost/graph/named_params_helper.h>
|
#include <CGAL/boost/graph/named_params_helper.h>
|
||||||
|
|
@ -132,6 +133,13 @@ compute_avg_knn_sq_distance_3(
|
||||||
\cgalParamBegin{threshold_percent} maximum percentage of points to remove.\cgalParamEnd
|
\cgalParamBegin{threshold_percent} maximum percentage of points to remove.\cgalParamEnd
|
||||||
\cgalParamBegin{threshold_distance} minimum distance for a point to be considered as outlier
|
\cgalParamBegin{threshold_distance} minimum distance for a point to be considered as outlier
|
||||||
(distance here is the square root of the average squared distance to K nearest neighbors).\cgalParamEnd
|
(distance here is the square root of the average squared distance to K nearest neighbors).\cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped, all points are left unchanged
|
||||||
|
and the function return `points.end()`.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -163,6 +171,8 @@ remove_outliers(
|
||||||
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
PointMap point_map = choose_param(get_param(np, internal_np::point_map), PointMap());
|
||||||
double threshold_percent = choose_param(get_param(np, internal_np::threshold_percent), 10.);
|
double threshold_percent = choose_param(get_param(np, internal_np::threshold_percent), 10.);
|
||||||
double threshold_distance = choose_param(get_param(np, internal_np::threshold_distance), 0.);
|
double threshold_distance = choose_param(get_param(np, internal_np::threshold_distance), 0.);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename Kernel::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
|
|
||||||
|
|
@ -198,12 +208,15 @@ remove_outliers(
|
||||||
|
|
||||||
// iterate over input points and add them to multimap sorted by distance to k
|
// iterate over input points and add them to multimap sorted by distance to k
|
||||||
std::multimap<FT,Enriched_point> sorted_points;
|
std::multimap<FT,Enriched_point> sorted_points;
|
||||||
for(it = points.begin(); it != points.end(); it++)
|
std::size_t nb = 0;
|
||||||
|
for(it = points.begin(); it != points.end(); it++, ++ nb)
|
||||||
{
|
{
|
||||||
FT sq_distance = internal::compute_avg_knn_sq_distance_3<Kernel>(
|
FT sq_distance = internal::compute_avg_knn_sq_distance_3<Kernel>(
|
||||||
get(point_map,*it),
|
get(point_map,*it),
|
||||||
tree, k);
|
tree, k);
|
||||||
sorted_points.insert( std::make_pair(sq_distance, *it) );
|
sorted_points.insert( std::make_pair(sq_distance, *it) );
|
||||||
|
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
|
||||||
|
return points.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces [points.begin(), points.end()) range by the multimap content.
|
// Replaces [points.begin(), points.end()) range by the multimap content.
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,10 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
#include <CGAL/internal/Parallel_callback.h>
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
#include <tbb/blocked_range.h>
|
#include <tbb/blocked_range.h>
|
||||||
|
#include <tbb/scalable_allocator.h>
|
||||||
#endif // CGAL_LINKED_WITH_TBB
|
#endif // CGAL_LINKED_WITH_TBB
|
||||||
|
|
||||||
#include <CGAL/Simple_cartesian.h>
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
|
@ -354,6 +356,8 @@ class Sample_point_updater
|
||||||
const typename Kernel::FT radius;
|
const typename Kernel::FT radius;
|
||||||
const std::vector<typename Kernel::FT> &original_densities;
|
const std::vector<typename Kernel::FT> &original_densities;
|
||||||
const std::vector<typename Kernel::FT> &sample_densities;
|
const std::vector<typename Kernel::FT> &sample_densities;
|
||||||
|
cpp11::atomic<std::size_t>& advancement;
|
||||||
|
cpp11::atomic<bool>& interrupted;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Sample_point_updater(
|
Sample_point_updater(
|
||||||
|
|
@ -363,20 +367,25 @@ public:
|
||||||
const Tree &_sample_kd_tree,
|
const Tree &_sample_kd_tree,
|
||||||
const typename Kernel::FT _radius,
|
const typename Kernel::FT _radius,
|
||||||
const std::vector<typename Kernel::FT> &_original_densities,
|
const std::vector<typename Kernel::FT> &_original_densities,
|
||||||
const std::vector<typename Kernel::FT> &_sample_densities):
|
const std::vector<typename Kernel::FT> &_sample_densities,
|
||||||
|
cpp11::atomic<std::size_t>& advancement,
|
||||||
|
cpp11::atomic<bool>& interrupted):
|
||||||
update_sample_points(out),
|
update_sample_points(out),
|
||||||
sample_points(in),
|
sample_points(in),
|
||||||
original_kd_tree(_original_kd_tree),
|
original_kd_tree(_original_kd_tree),
|
||||||
sample_kd_tree(_sample_kd_tree),
|
sample_kd_tree(_sample_kd_tree),
|
||||||
radius(_radius),
|
radius(_radius),
|
||||||
original_densities(_original_densities),
|
original_densities(_original_densities),
|
||||||
sample_densities(_sample_densities){}
|
sample_densities(_sample_densities),
|
||||||
|
advancement (advancement),
|
||||||
|
interrupted (interrupted) {}
|
||||||
|
|
||||||
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
void operator() ( const tbb::blocked_range<size_t>& r ) const
|
||||||
{
|
{
|
||||||
for (size_t i = r.begin(); i != r.end(); ++i)
|
for (size_t i = r.begin(); i != r.end(); ++i)
|
||||||
{
|
{
|
||||||
|
if (interrupted)
|
||||||
|
break;
|
||||||
update_sample_points[i] = simplify_and_regularize_internal::
|
update_sample_points[i] = simplify_and_regularize_internal::
|
||||||
compute_update_sample_point<Kernel, Tree, RandomAccessIterator>(
|
compute_update_sample_point<Kernel, Tree, RandomAccessIterator>(
|
||||||
sample_points[i],
|
sample_points[i],
|
||||||
|
|
@ -385,6 +394,7 @@ public:
|
||||||
radius,
|
radius,
|
||||||
original_densities,
|
original_densities,
|
||||||
sample_densities);
|
sample_densities);
|
||||||
|
++ advancement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -440,6 +450,13 @@ public:
|
||||||
value is 35. More iterations give a more regular result but increase the runtime.\cgalParamEnd
|
value is 35. More iterations give a more regular result but increase the runtime.\cgalParamEnd
|
||||||
\cgalParamBegin{require_uniform_sampling} an optional preprocessing, which will give better result if the
|
\cgalParamBegin{require_uniform_sampling} an optional preprocessing, which will give better result if the
|
||||||
distribution of the input points is highly non-uniform. The default value is `false`. \cgalParamEnd
|
distribution of the input points is highly non-uniform. The default value is `false`. \cgalParamEnd
|
||||||
|
\cgalParamBegin{callback} an instance of
|
||||||
|
`cpp11::function<bool(double)>`. It is called regularly when the
|
||||||
|
algorithm is running: the current advancement (between 0. and
|
||||||
|
1.) is passed as parameter. If it returns `true`, then the
|
||||||
|
algorithm continues its execution normally; if it returns
|
||||||
|
`false`, the algorithm is stopped, no output points are
|
||||||
|
generated.\cgalParamEnd
|
||||||
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
\cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `Kernel`\cgalParamEnd
|
||||||
\cgalNamedParamsEnd
|
\cgalNamedParamsEnd
|
||||||
|
|
||||||
|
|
@ -466,6 +483,8 @@ wlop_simplify_and_regularize_point_set(
|
||||||
double radius = choose_param(get_param(np, internal_np::neighbor_radius), -1);
|
double radius = choose_param(get_param(np, internal_np::neighbor_radius), -1);
|
||||||
unsigned int iter_number = choose_param(get_param(np, internal_np::number_of_iterations), 35);
|
unsigned int iter_number = choose_param(get_param(np, internal_np::number_of_iterations), 35);
|
||||||
bool require_uniform_sampling = choose_param(get_param(np, internal_np::require_uniform_sampling), false);
|
bool require_uniform_sampling = choose_param(get_param(np, internal_np::require_uniform_sampling), false);
|
||||||
|
const cpp11::function<bool(double)>& callback = choose_param(get_param(np, internal_np::callback),
|
||||||
|
cpp11::function<bool(double)>());
|
||||||
|
|
||||||
typedef typename Kernel::Point_3 Point;
|
typedef typename Kernel::Point_3 Point;
|
||||||
typedef typename Kernel::FT FT;
|
typedef typename Kernel::FT FT;
|
||||||
|
|
@ -589,6 +608,9 @@ wlop_simplify_and_regularize_point_set(
|
||||||
//parallel
|
//parallel
|
||||||
if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
|
if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
|
||||||
{
|
{
|
||||||
|
internal::Point_set_processing_3::Parallel_callback
|
||||||
|
parallel_callback (callback, iter_number * number_of_sample, iter_n * number_of_sample);
|
||||||
|
|
||||||
tbb::blocked_range<size_t> block(0, number_of_sample);
|
tbb::blocked_range<size_t> block(0, number_of_sample);
|
||||||
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater(
|
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater(
|
||||||
update_sample_points,
|
update_sample_points,
|
||||||
|
|
@ -597,15 +619,28 @@ wlop_simplify_and_regularize_point_set(
|
||||||
sample_kd_tree,
|
sample_kd_tree,
|
||||||
radius2,
|
radius2,
|
||||||
original_density_weights,
|
original_density_weights,
|
||||||
sample_density_weights);
|
sample_density_weights,
|
||||||
|
parallel_callback.advancement(),
|
||||||
|
parallel_callback.interrupted());
|
||||||
|
|
||||||
tbb::parallel_for(block, sample_updater);
|
tbb::parallel_for(block, sample_updater);
|
||||||
|
|
||||||
|
bool interrupted = parallel_callback.interrupted();
|
||||||
|
|
||||||
|
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||||
|
parallel_callback.interrupted() = true;
|
||||||
|
parallel_callback.join();
|
||||||
|
|
||||||
|
// If interrupted during this step, nothing is computed, we return NaN
|
||||||
|
if (interrupted)
|
||||||
|
return output;
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
//sequential
|
//sequential
|
||||||
|
std::size_t nb = iter_n * number_of_sample;
|
||||||
for (sample_iter = sample_points.begin();
|
for (sample_iter = sample_points.begin();
|
||||||
sample_iter != sample_points.end(); ++sample_iter, ++update_iter)
|
sample_iter != sample_points.end(); ++sample_iter, ++update_iter, ++ nb)
|
||||||
{
|
{
|
||||||
*update_iter = simplify_and_regularize_internal::
|
*update_iter = simplify_and_regularize_internal::
|
||||||
compute_update_sample_point<Kernel,
|
compute_update_sample_point<Kernel,
|
||||||
|
|
@ -617,6 +652,8 @@ wlop_simplify_and_regularize_point_set(
|
||||||
radius2,
|
radius2,
|
||||||
original_density_weights,
|
original_density_weights,
|
||||||
sample_density_weights);
|
sample_density_weights);
|
||||||
|
if (callback && !callback ((nb+1) / double(iter_number * number_of_sample)))
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
|
||||||
add_library(scene_color_ramp SHARED Color_ramp.cpp)
|
add_library(scene_color_ramp SHARED Color_ramp.cpp)
|
||||||
target_link_libraries(scene_color_ramp PRIVATE Qt5::Core)
|
target_link_libraries(scene_color_ramp PRIVATE Qt5::Core)
|
||||||
|
|
||||||
|
add_library(scene_callback_signaler SHARED Callback_signaler.cpp)
|
||||||
|
target_link_libraries(scene_callback_signaler PRIVATE Qt5::Core)
|
||||||
|
|
||||||
add_library(point_dialog SHARED Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES})
|
add_library(point_dialog SHARED Show_point_dialog.cpp Show_point_dialog.ui ${Show_point_dialogUI_FILES})
|
||||||
target_link_libraries(point_dialog
|
target_link_libraries(point_dialog
|
||||||
PUBLIC Qt5::OpenGL Qt5::Gui Qt5::Script Qt5::Widgets)
|
PUBLIC Qt5::OpenGL Qt5::Gui Qt5::Script Qt5::Widgets)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "Callback_signaler.h"
|
||||||
|
|
||||||
|
Callback_signaler::Callback_signaler()
|
||||||
|
: is_canceled(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Callback_signaler::emit_signal (int value) const
|
||||||
|
{
|
||||||
|
Q_EMIT progressChanged(value);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef CALLBACK_SIGNALER_H
|
||||||
|
#define CALLBACK_SIGNALER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
#ifdef scene_callback_signaler_EXPORTS
|
||||||
|
# define SCENE_CALLBACK_SIGNALER_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
# define SCENE_CALLBACK_SIGNALER_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SCENE_CALLBACK_SIGNALER_EXPORT Callback_signaler
|
||||||
|
: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool is_canceled;
|
||||||
|
|
||||||
|
Callback_signaler();
|
||||||
|
|
||||||
|
void emit_signal (int value) const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
|
||||||
|
void cancel()
|
||||||
|
{
|
||||||
|
is_canceled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
void progressChanged(int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CALLBACK_SIGNALER_H
|
||||||
|
|
@ -6,17 +6,17 @@ if(EIGEN3_FOUND)
|
||||||
|
|
||||||
qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui)
|
qt5_wrap_ui( point_set_normal_estimationUI_FILES Point_set_normal_estimation_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES})
|
polyhedron_demo_plugin(point_set_normal_estimation_plugin Point_set_normal_estimation_plugin ${point_set_normal_estimationUI_FILES})
|
||||||
target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_normal_estimation_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui)
|
qt5_wrap_ui( features_detection_pluginUI_FILES Features_detection_plugin.ui)
|
||||||
polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES})
|
polyhedron_demo_plugin(features_detection_plugin Features_detection_plugin ${features_detection_pluginUI_FILES})
|
||||||
target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(features_detection_plugin PUBLIC scene_points_with_normal_item)
|
||||||
|
|
||||||
polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin)
|
polyhedron_demo_plugin(point_set_smoothing_plugin Point_set_smoothing_plugin)
|
||||||
target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin)
|
polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin)
|
||||||
target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
else(EIGEN3_FOUND)
|
else(EIGEN3_FOUND)
|
||||||
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.")
|
message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.")
|
||||||
|
|
@ -29,11 +29,11 @@ endif()
|
||||||
|
|
||||||
qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui)
|
qt5_wrap_ui(point_set_bilateral_smoothingUI_FILES Point_set_bilateral_smoothing_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_bilateral_smoothing_plugin Point_set_bilateral_smoothing_plugin ${point_set_bilateral_smoothingUI_FILES})
|
polyhedron_demo_plugin(point_set_bilateral_smoothing_plugin Point_set_bilateral_smoothing_plugin ${point_set_bilateral_smoothingUI_FILES})
|
||||||
target_link_libraries(point_set_bilateral_smoothing_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_bilateral_smoothing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
qt5_wrap_ui( ps_outliers_removal_UI_FILES Point_set_outliers_removal_plugin.ui)
|
qt5_wrap_ui( ps_outliers_removal_UI_FILES Point_set_outliers_removal_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_outliers_removal_plugin Point_set_outliers_removal_plugin ${ps_outliers_removal_UI_FILES})
|
polyhedron_demo_plugin(point_set_outliers_removal_plugin Point_set_outliers_removal_plugin ${ps_outliers_removal_UI_FILES})
|
||||||
target_link_libraries(point_set_outliers_removal_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_outliers_removal_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
qt5_wrap_ui( point_set_selectionUI_FILES Point_set_selection_widget.ui)
|
qt5_wrap_ui( point_set_selectionUI_FILES Point_set_selection_widget.ui)
|
||||||
polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES})
|
polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES})
|
||||||
|
|
@ -41,12 +41,11 @@ endif()
|
||||||
|
|
||||||
qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui)
|
qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES})
|
polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES})
|
||||||
target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item)
|
target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_polyhedron_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler)
|
||||||
|
|
||||||
qt5_wrap_ui(point_set_simplificationUI_FILES Point_set_simplification_plugin.ui)
|
qt5_wrap_ui(point_set_simplificationUI_FILES Point_set_simplification_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_simplification_plugin Point_set_simplification_plugin ${point_set_simplificationUI_FILES})
|
polyhedron_demo_plugin(point_set_simplification_plugin Point_set_simplification_plugin ${point_set_simplificationUI_FILES})
|
||||||
target_link_libraries(point_set_simplification_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_simplification_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
|
|
||||||
qt5_wrap_ui(point_set_upsamplingUI_FILES Point_set_upsampling_plugin.ui)
|
qt5_wrap_ui(point_set_upsamplingUI_FILES Point_set_upsampling_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_upsampling_plugin Point_set_upsampling_plugin ${point_set_upsamplingUI_FILES})
|
polyhedron_demo_plugin(point_set_upsampling_plugin Point_set_upsampling_plugin ${point_set_upsamplingUI_FILES})
|
||||||
|
|
@ -54,7 +53,7 @@ endif()
|
||||||
|
|
||||||
qt5_wrap_ui(point_set_wlopFILES Point_set_wlop_plugin.ui)
|
qt5_wrap_ui(point_set_wlopFILES Point_set_wlop_plugin.ui)
|
||||||
polyhedron_demo_plugin(point_set_wlop_plugin Point_set_wlop_plugin ${point_set_wlopFILES})
|
polyhedron_demo_plugin(point_set_wlop_plugin Point_set_wlop_plugin ${point_set_wlopFILES})
|
||||||
target_link_libraries(point_set_wlop_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(point_set_wlop_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler)
|
||||||
|
|
||||||
polyhedron_demo_plugin(merge_point_sets_plugin Merge_point_sets_plugin)
|
polyhedron_demo_plugin(merge_point_sets_plugin Merge_point_sets_plugin)
|
||||||
target_link_libraries(merge_point_sets_plugin PUBLIC scene_points_with_normal_item)
|
target_link_libraries(merge_point_sets_plugin PUBLIC scene_points_with_normal_item)
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
|
//#undef CGAL_LINKED_WITH_TBB
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Scene_points_with_normal_item.h"
|
#include "Scene_points_with_normal_item.h"
|
||||||
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
|
||||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||||
|
|
||||||
#include <CGAL/compute_average_spacing.h>
|
#include <CGAL/compute_average_spacing.h>
|
||||||
#include <CGAL/Timer.h>
|
#include <CGAL/Real_timer.h>
|
||||||
#include <CGAL/Memory_sizer.h>
|
#include <CGAL/Memory_sizer.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -14,6 +16,9 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
|
@ -21,6 +26,26 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Compute_average_spacing_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
const int nb_neighbors;
|
||||||
|
boost::shared_ptr<double> result;
|
||||||
|
|
||||||
|
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
|
||||||
|
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::compute_average_spacing<Concurrency_tag>(
|
||||||
|
points->all_or_selection_if_not_empty(),
|
||||||
|
nb_neighbors,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_average_spacing_plugin :
|
class Polyhedron_demo_point_set_average_spacing_plugin :
|
||||||
public QObject,
|
public QObject,
|
||||||
|
|
@ -85,27 +110,27 @@ void Polyhedron_demo_point_set_average_spacing_plugin::on_actionAverageSpacing_t
|
||||||
&ok);
|
&ok);
|
||||||
if(!ok)
|
if(!ok)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
CGAL::Real_timer task_timer; task_timer.start();
|
||||||
std::cerr << "Average spacing (k=" << nb_neighbors <<")...\n";
|
std::cerr << "Average spacing (k=" << nb_neighbors <<")...\n";
|
||||||
|
|
||||||
// Computes average spacing
|
// Computes average spacing
|
||||||
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(
|
Compute_average_spacing_functor functor (points, nb_neighbors);
|
||||||
points->all_or_selection_if_not_empty(),
|
run_with_qprogressdialog (functor, "Computing average spacing...", mw);
|
||||||
nb_neighbors,
|
|
||||||
points->parameters());
|
double average_spacing = *functor.result;
|
||||||
|
|
||||||
// Print result
|
// Print result
|
||||||
Kernel::Sphere_3 bsphere = points->bounding_sphere();
|
Kernel::Sphere_3 bsphere = points->bounding_sphere();
|
||||||
double radius = std::sqrt(bsphere.squared_radius());
|
double radius = std::sqrt(bsphere.squared_radius());
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << "Average spacing = " << average_spacing
|
std::cerr << "Average spacing = " << average_spacing
|
||||||
<< " = " << average_spacing/radius << " * point set radius ("
|
<< " = " << average_spacing/radius << " * point set radius ("
|
||||||
<< task_timer.time() << " seconds, "
|
<< task_timer.time() << " seconds, "
|
||||||
<< (memory>>20) << " Mb allocated)"
|
<< (memory>>20) << " Mb allocated)"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
||||||
QMessageBox::information(NULL,
|
QMessageBox::information(NULL,
|
||||||
|
|
@ -113,6 +138,7 @@ void Polyhedron_demo_point_set_average_spacing_plugin::on_actionAverageSpacing_t
|
||||||
tr("Average Spacing = %1 = %2 * point set radius")
|
tr("Average Spacing = %1 = %2 * point set radius")
|
||||||
.arg(average_spacing)
|
.arg(average_spacing)
|
||||||
.arg(average_spacing/radius));
|
.arg(average_spacing/radius));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
#include "ui_Point_set_bilateral_smoothing_plugin.h"
|
#include "ui_Point_set_bilateral_smoothing_plugin.h"
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
|
|
@ -23,6 +27,30 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Bilateral_smoothing_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
unsigned int neighborhood_size;
|
||||||
|
unsigned int sharpness_angle;
|
||||||
|
boost::shared_ptr<double> result;
|
||||||
|
|
||||||
|
Bilateral_smoothing_functor (Point_set* points,
|
||||||
|
unsigned int neighborhood_size,
|
||||||
|
unsigned int sharpness_angle)
|
||||||
|
: points (points), neighborhood_size (neighborhood_size)
|
||||||
|
, sharpness_angle (sharpness_angle), result (new double(0)) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::bilateral_smooth_point_set<Concurrency_tag>
|
||||||
|
(points->all_or_selection_if_not_empty(),
|
||||||
|
neighborhood_size,
|
||||||
|
points->parameters().
|
||||||
|
sharpness_angle(sharpness_angle).
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_bilateral_smoothing_plugin :
|
class Polyhedron_demo_point_set_bilateral_smoothing_plugin :
|
||||||
|
|
@ -103,21 +131,24 @@ void Polyhedron_demo_point_set_bilateral_smoothing_plugin::on_actionBilateralSmo
|
||||||
<< dialog.iterations () << " iteration(s), neighborhood size of "
|
<< dialog.iterations () << " iteration(s), neighborhood size of "
|
||||||
<< dialog.neighborhood_size () << " and sharpness angle of "
|
<< dialog.neighborhood_size () << " and sharpness angle of "
|
||||||
<< dialog.sharpness_angle () << "... ";
|
<< dialog.sharpness_angle () << "... ";
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
CGAL::Timer task_timer; task_timer.start();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < dialog.iterations (); ++i)
|
for (unsigned int i = 0; i < dialog.iterations (); ++i)
|
||||||
{
|
{
|
||||||
/* double error = */
|
std::ostringstream oss;
|
||||||
CGAL::bilateral_smooth_point_set<Concurrency_tag>
|
oss << "Bilateral smoothing (iteration " << i+1 << "/" << dialog.iterations() << ")";
|
||||||
(points->all_or_selection_if_not_empty(),
|
|
||||||
dialog.neighborhood_size (),
|
Bilateral_smoothing_functor functor (points,
|
||||||
points->parameters().
|
dialog.neighborhood_size (),
|
||||||
sharpness_angle(dialog.sharpness_angle ()));
|
dialog.sharpness_angle ());
|
||||||
|
run_with_qprogressdialog (functor, oss.str().c_str(), mw);
|
||||||
|
double error = *functor.result;
|
||||||
|
|
||||||
|
if (std::isnan(error)) // NaN return means algorithm was interrupted
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << task_timer.time() << " seconds, "
|
std::cerr << task_timer.time() << " seconds, "
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
#include "ui_Point_set_normal_estimation_plugin.h"
|
#include "ui_Point_set_normal_estimation_plugin.h"
|
||||||
|
|
||||||
#if BOOST_VERSION == 105700
|
#if BOOST_VERSION == 105700
|
||||||
|
|
@ -32,6 +34,49 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
#else
|
#else
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct PCA_estimate_normals_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
int neighborhood_size;
|
||||||
|
unsigned int sharpness_angle;
|
||||||
|
|
||||||
|
PCA_estimate_normals_functor (Point_set* points,
|
||||||
|
int neighborhood_size)
|
||||||
|
: points (points), neighborhood_size (neighborhood_size)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
CGAL::pca_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||||
|
neighborhood_size,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Jet_estimate_normals_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
int neighborhood_size;
|
||||||
|
unsigned int sharpness_angle;
|
||||||
|
|
||||||
|
Jet_estimate_normals_functor (Point_set* points,
|
||||||
|
int neighborhood_size)
|
||||||
|
: points (points), neighborhood_size (neighborhood_size)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
CGAL::jet_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||||
|
neighborhood_size,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
|
|
||||||
class Polyhedron_demo_point_set_normal_estimation_plugin :
|
class Polyhedron_demo_point_set_normal_estimation_plugin :
|
||||||
|
|
@ -49,6 +94,7 @@ public:
|
||||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||||
|
|
||||||
scene = scene_interface;
|
scene = scene_interface;
|
||||||
|
mw = mainWindow;
|
||||||
actionNormalEstimation = new QAction(tr("Normal Estimation"), mainWindow);
|
actionNormalEstimation = new QAction(tr("Normal Estimation"), mainWindow);
|
||||||
actionNormalEstimation->setObjectName("actionNormalEstimation");
|
actionNormalEstimation->setObjectName("actionNormalEstimation");
|
||||||
actionNormalEstimation->setProperty("subMenuName","Point Set Processing");
|
actionNormalEstimation->setProperty("subMenuName","Point Set Processing");
|
||||||
|
|
@ -160,7 +206,7 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
|
||||||
if(!dialog.exec())
|
if(!dialog.exec())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
|
|
||||||
// First point to delete
|
// First point to delete
|
||||||
|
|
@ -175,9 +221,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
|
||||||
std::cerr << "Estimates normal direction by PCA (k=" << dialog.pca_neighbors() <<")...\n";
|
std::cerr << "Estimates normal direction by PCA (k=" << dialog.pca_neighbors() <<")...\n";
|
||||||
|
|
||||||
// Estimates normals direction.
|
// Estimates normals direction.
|
||||||
CGAL::pca_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
PCA_estimate_normals_functor functor (points, dialog.pca_neighbors());
|
||||||
dialog.pca_neighbors(),
|
run_with_qprogressdialog (functor, "Estimating normals by PCA...", mw);
|
||||||
points->parameters());
|
|
||||||
|
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
||||||
|
|
@ -190,9 +235,8 @@ void Polyhedron_demo_point_set_normal_estimation_plugin::on_actionNormalEstimati
|
||||||
std::cerr << "Estimates normal direction by Jet Fitting (k=" << dialog.jet_neighbors() <<")...\n";
|
std::cerr << "Estimates normal direction by Jet Fitting (k=" << dialog.jet_neighbors() <<")...\n";
|
||||||
|
|
||||||
// Estimates normals direction.
|
// Estimates normals direction.
|
||||||
CGAL::jet_estimate_normals<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
Jet_estimate_normals_functor functor (points, dialog.pca_neighbors());
|
||||||
dialog.jet_neighbors(),
|
run_with_qprogressdialog (functor, "Estimating normals by jet fitting...", mw);
|
||||||
points->parameters());
|
|
||||||
|
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
std::cerr << "Estimates normal direction: " << task_timer.time() << " seconds, "
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,39 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "ui_Point_set_outliers_removal_plugin.h"
|
#include "ui_Point_set_outliers_removal_plugin.h"
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
|
struct Outlier_removal_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
int nb_neighbors;
|
||||||
|
double removed_percentage;
|
||||||
|
double distance_threshold;
|
||||||
|
boost::shared_ptr<Point_set::iterator> result;
|
||||||
|
|
||||||
|
Outlier_removal_functor (Point_set* points,
|
||||||
|
int nb_neighbors,
|
||||||
|
double removed_percentage,
|
||||||
|
double distance_threshold)
|
||||||
|
: points (points), nb_neighbors (nb_neighbors)
|
||||||
|
, removed_percentage (removed_percentage), distance_threshold (distance_threshold)
|
||||||
|
, result (new Point_set::iterator) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
// Computes outliers
|
||||||
|
*result =
|
||||||
|
CGAL::remove_outliers(*points,
|
||||||
|
nb_neighbors,
|
||||||
|
points->parameters().
|
||||||
|
threshold_percent(removed_percentage).
|
||||||
|
threshold_distance(distance_threshold).
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_outliers_removal_plugin :
|
class Polyhedron_demo_point_set_outliers_removal_plugin :
|
||||||
public QObject,
|
public QObject,
|
||||||
|
|
@ -31,6 +64,7 @@ private:
|
||||||
public:
|
public:
|
||||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||||
scene = scene_interface;
|
scene = scene_interface;
|
||||||
|
mw = mainWindow;
|
||||||
actionOutlierRemoval = new QAction(tr("Outliers Selection"), mainWindow);
|
actionOutlierRemoval = new QAction(tr("Outliers Selection"), mainWindow);
|
||||||
actionOutlierRemoval->setProperty("subMenuName","Point Set Processing");
|
actionOutlierRemoval->setProperty("subMenuName","Point Set Processing");
|
||||||
actionOutlierRemoval->setObjectName("actionOutlierRemoval");
|
actionOutlierRemoval->setObjectName("actionOutlierRemoval");
|
||||||
|
|
@ -87,27 +121,23 @@ void Polyhedron_demo_point_set_outliers_removal_plugin::on_actionOutlierRemoval_
|
||||||
const double distance_threshold = dialog.distance();
|
const double distance_threshold = dialog.distance();
|
||||||
const int nb_neighbors = dialog.nbNeighbors();
|
const int nb_neighbors = dialog.nbNeighbors();
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
CGAL::Timer task_timer; task_timer.start();
|
||||||
std::cerr << "Select outliers (" << removed_percentage <<"% with distance threshold "
|
std::cerr << "Select outliers (" << removed_percentage <<"% with distance threshold "
|
||||||
<< distance_threshold << ")...\n";
|
<< distance_threshold << ")...\n";
|
||||||
|
|
||||||
// Computes outliers
|
// Computes outliers
|
||||||
Point_set::iterator first_point_to_remove =
|
Outlier_removal_functor functor (points, nb_neighbors, removed_percentage, distance_threshold);
|
||||||
CGAL::remove_outliers(*points,
|
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Selecting outliers...", mw);
|
||||||
nb_neighbors,
|
Point_set::iterator first_point_to_remove = *functor.result;
|
||||||
points->parameters().
|
|
||||||
threshold_percent(removed_percentage).
|
|
||||||
threshold_distance(distance_threshold));
|
|
||||||
|
|
||||||
|
|
||||||
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
|
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << "Simplification: " << nb_points_to_remove << " point(s) are selected ("
|
std::cerr << "Outliers: " << nb_points_to_remove << " point(s) are selected ("
|
||||||
<< task_timer.time() << " seconds, "
|
<< task_timer.time() << " seconds, "
|
||||||
<< (memory>>20) << " Mb allocated)"
|
<< (memory>>20) << " Mb allocated)"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
// Selects points to delete
|
// Selects points to delete
|
||||||
points->set_first_selected (first_point_to_remove);
|
points->set_first_selected (first_point_to_remove);
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,27 @@
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/function_output_iterator.hpp>
|
#include <boost/function_output_iterator.hpp>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
#include "ui_Point_set_shape_detection_plugin.h"
|
#include "ui_Point_set_shape_detection_plugin.h"
|
||||||
|
|
||||||
|
template <typename Shape_detection>
|
||||||
|
struct Detect_shapes_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Shape_detection& shape_detection;
|
||||||
|
typename Shape_detection::Parameters& op;
|
||||||
|
|
||||||
|
Detect_shapes_functor (Shape_detection& shape_detection,
|
||||||
|
typename Shape_detection::Parameters& op)
|
||||||
|
: shape_detection (shape_detection), op (op)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
shape_detection.detect(op, *(this->callback()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct build_from_pair
|
struct build_from_pair
|
||||||
{
|
{
|
||||||
|
|
@ -55,93 +74,6 @@ struct build_from_pair
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Progress_bar_callback
|
|
||||||
{
|
|
||||||
mutable int nb;
|
|
||||||
CGAL::Real_timer timer;
|
|
||||||
double t_start;
|
|
||||||
mutable double t_latest;
|
|
||||||
int bar_size;
|
|
||||||
mutable std::size_t string_size;
|
|
||||||
|
|
||||||
Progress_bar_callback() : nb(0), bar_size (30), string_size(0)
|
|
||||||
{
|
|
||||||
timer.start();
|
|
||||||
t_start = timer.time();
|
|
||||||
t_latest = t_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(double advancement) const
|
|
||||||
{
|
|
||||||
// Avoid calling time() at every single iteration, which could
|
|
||||||
// impact performances very badly
|
|
||||||
++ nb;
|
|
||||||
if (advancement != 1 && nb % 1000 != 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If the limit is reach, interrupt the algorithm
|
|
||||||
double t = timer.time();
|
|
||||||
if (advancement == 1 || (t - t_latest) > 1.)
|
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "[";
|
|
||||||
int adv = int(advancement * bar_size);
|
|
||||||
for (int i = 0; i < adv; ++ i)
|
|
||||||
oss << "=";
|
|
||||||
if (adv != bar_size)
|
|
||||||
oss << ">";
|
|
||||||
for (int i = adv; i < bar_size; ++ i)
|
|
||||||
oss << " ";
|
|
||||||
|
|
||||||
oss << "] " << int(advancement * 100) << "% (";
|
|
||||||
|
|
||||||
display_time (oss, t);
|
|
||||||
|
|
||||||
oss << " elapsed, ";
|
|
||||||
|
|
||||||
display_time (oss, estimate_remaining(t, advancement));
|
|
||||||
|
|
||||||
oss << " remaining)";
|
|
||||||
|
|
||||||
std::string bar_string = oss.str();
|
|
||||||
std::cerr << "\r" << bar_string;
|
|
||||||
for (std::size_t i = bar_string.size(); i < string_size; ++ i)
|
|
||||||
std::cerr << " ";
|
|
||||||
string_size = (std::max) (string_size, bar_string.size());
|
|
||||||
|
|
||||||
if (advancement == 1)
|
|
||||||
std::cerr << std::endl;
|
|
||||||
|
|
||||||
t_latest = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void display_time (std::ostringstream& oss, double seconds) const
|
|
||||||
{
|
|
||||||
if (seconds > 3600.)
|
|
||||||
{
|
|
||||||
int hours = int(seconds / 3600.);
|
|
||||||
oss << hours << "h";
|
|
||||||
seconds -= hours * 3600.;
|
|
||||||
}
|
|
||||||
if (seconds > 60.)
|
|
||||||
{
|
|
||||||
int minutes = (int)(seconds / 60.);
|
|
||||||
oss << minutes << "min";
|
|
||||||
seconds -= minutes * 60.;
|
|
||||||
}
|
|
||||||
oss << int(seconds) << "sec";
|
|
||||||
}
|
|
||||||
|
|
||||||
double estimate_remaining (double seconds, double advancement) const
|
|
||||||
{
|
|
||||||
return ((1. - advancement) * (seconds - t_start) / advancement);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Point_set_demo_point_set_shape_detection_dialog : public QDialog, private Ui::PointSetShapeDetectionDialog
|
class Point_set_demo_point_set_shape_detection_dialog : public QDialog, private Ui::PointSetShapeDetectionDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -303,7 +235,7 @@ private:
|
||||||
comments += "shape -1 no assigned shape\n";
|
comments += "shape -1 no assigned shape\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
|
||||||
Shape_detection shape_detection;
|
Shape_detection shape_detection;
|
||||||
shape_detection.set_input(*points, points->point_map(), points->normal_map());
|
shape_detection.set_input(*points, points->point_map(), points->normal_map());
|
||||||
|
|
@ -340,8 +272,8 @@ private:
|
||||||
// The actual shape detection.
|
// The actual shape detection.
|
||||||
CGAL::Real_timer t;
|
CGAL::Real_timer t;
|
||||||
t.start();
|
t.start();
|
||||||
Progress_bar_callback callback;
|
Detect_shapes_functor<Shape_detection> functor (shape_detection, op);
|
||||||
shape_detection.detect(op, callback);
|
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Detecting shapes...", mw);
|
||||||
t.stop();
|
t.stop();
|
||||||
|
|
||||||
std::cout << shape_detection.shapes().size() << " shapes found in "
|
std::cout << shape_detection.shapes().size() << " shapes found in "
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
#include "ui_Point_set_simplification_plugin.h"
|
#include "ui_Point_set_simplification_plugin.h"
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
|
|
@ -26,6 +28,68 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Compute_average_spacing_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
const int nb_neighbors;
|
||||||
|
boost::shared_ptr<double> result;
|
||||||
|
|
||||||
|
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
|
||||||
|
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::compute_average_spacing<Concurrency_tag>(
|
||||||
|
points->all_or_selection_if_not_empty(),
|
||||||
|
nb_neighbors,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Grid_simplify_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
double grid_size;
|
||||||
|
boost::shared_ptr<Point_set::iterator> result;
|
||||||
|
|
||||||
|
Grid_simplify_functor (Point_set* points, double grid_size)
|
||||||
|
: points (points), grid_size (grid_size), result (new Point_set::iterator) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::grid_simplify_point_set(*points,
|
||||||
|
grid_size,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Hierarchy_simplify_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
unsigned int max_cluster_size;
|
||||||
|
double max_surface_variation;
|
||||||
|
boost::shared_ptr<Point_set::iterator> result;
|
||||||
|
|
||||||
|
Hierarchy_simplify_functor (Point_set* points,
|
||||||
|
double max_cluster_size,
|
||||||
|
double max_surface_variation)
|
||||||
|
: points (points), max_cluster_size (max_cluster_size)
|
||||||
|
, max_surface_variation (max_surface_variation), result (new Point_set::iterator) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::hierarchy_simplify_point_set(*points,
|
||||||
|
points->parameters().
|
||||||
|
size(max_cluster_size).
|
||||||
|
maximum_variation(max_surface_variation).
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_simplification_plugin :
|
class Polyhedron_demo_point_set_simplification_plugin :
|
||||||
|
|
@ -41,6 +105,7 @@ class Polyhedron_demo_point_set_simplification_plugin :
|
||||||
public:
|
public:
|
||||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) {
|
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,Messages_interface*) {
|
||||||
scene = scene_interface;
|
scene = scene_interface;
|
||||||
|
mw = mainWindow;
|
||||||
actionSimplify = new QAction(tr("Simplification Selection"), mainWindow);
|
actionSimplify = new QAction(tr("Simplification Selection"), mainWindow);
|
||||||
actionSimplify->setProperty("subMenuName","Point Set Processing");
|
actionSimplify->setProperty("subMenuName","Point Set Processing");
|
||||||
|
|
||||||
|
|
@ -130,7 +195,7 @@ void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggere
|
||||||
if(!dialog.exec())
|
if(!dialog.exec())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
CGAL::Timer task_timer; task_timer.start();
|
||||||
|
|
||||||
|
|
@ -152,24 +217,30 @@ void Polyhedron_demo_point_set_simplification_plugin::on_actionSimplify_triggere
|
||||||
std::cerr << "Point set grid simplification (cell size = " << dialog.gridCellSize() <<" * average spacing)...\n";
|
std::cerr << "Point set grid simplification (cell size = " << dialog.gridCellSize() <<" * average spacing)...\n";
|
||||||
|
|
||||||
// Computes average spacing
|
// Computes average spacing
|
||||||
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(*points, 6 /* knn = 1 ring */);
|
Compute_average_spacing_functor functor_as (points, 6);
|
||||||
|
run_with_qprogressdialog (functor_as, "Simplification: computing average spacing...", mw);
|
||||||
|
|
||||||
|
double average_spacing = *functor_as.result;
|
||||||
|
|
||||||
|
Grid_simplify_functor functor (points, dialog.gridCellSize() * average_spacing);
|
||||||
|
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Grid simplyfing...", mw);
|
||||||
|
|
||||||
// Computes points to remove by Grid Clustering
|
// Computes points to remove by Grid Clustering
|
||||||
first_point_to_remove =
|
first_point_to_remove = *functor.result;
|
||||||
CGAL::grid_simplify_point_set(*points,
|
|
||||||
dialog.gridCellSize()*average_spacing);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize()
|
std::cerr << "Point set hierarchy simplification (cluster size = " << dialog.maximumClusterSize()
|
||||||
<< ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n";
|
<< ", maximum variation = " << dialog.maximumSurfaceVariation() << ")...\n";
|
||||||
|
|
||||||
// Computes points to remove by Grid Clustering
|
// Computes points to remove by Hierarchy
|
||||||
first_point_to_remove =
|
Hierarchy_simplify_functor functor (points, dialog.maximumClusterSize(),
|
||||||
CGAL::hierarchy_simplify_point_set(*points,
|
dialog.maximumSurfaceVariation());
|
||||||
points->parameters().
|
run_with_qprogressdialog<CGAL::Sequential_tag> (functor, "Hierarchy simplyfing...", mw);
|
||||||
size(dialog.maximumClusterSize()).
|
|
||||||
maximum_variation(dialog.maximumSurfaceVariation()));
|
first_point_to_remove = *functor.result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
|
std::size_t nb_points_to_remove = std::distance(first_point_to_remove, points->end());
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include <CGAL/jet_smooth_point_set.h>
|
#include <CGAL/jet_smooth_point_set.h>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
#ifdef CGAL_LINKED_WITH_TBB
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
typedef CGAL::Parallel_tag Concurrency_tag;
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
|
@ -19,6 +21,24 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Jet_smoothing_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
const int nb_neighbors;
|
||||||
|
|
||||||
|
Jet_smoothing_functor (Point_set* points, const int nb_neighbors)
|
||||||
|
: points (points), nb_neighbors (nb_neighbors) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
CGAL::jet_smooth_point_set<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
||||||
|
nb_neighbors,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_smoothing_plugin :
|
class Polyhedron_demo_point_set_smoothing_plugin :
|
||||||
public QObject,
|
public QObject,
|
||||||
|
|
@ -79,17 +99,14 @@ void Polyhedron_demo_point_set_smoothing_plugin::on_actionJetSmoothing_triggered
|
||||||
&ok);
|
&ok);
|
||||||
if(!ok) return;
|
if(!ok) return;
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
CGAL::jet_smooth_point_set<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
|
||||||
nb_neighbors,
|
Jet_smoothing_functor functor (points, nb_neighbors);
|
||||||
points->parameters());
|
run_with_qprogressdialog (functor, "Smoothing point set...", mw);
|
||||||
|
|
||||||
points->invalidate_bounds();
|
points->invalidate_bounds();
|
||||||
|
|
||||||
// calling jet_smooth_point_set breaks the normals
|
|
||||||
points->remove_normal_map();
|
|
||||||
|
|
||||||
// update scene
|
// update scene
|
||||||
item->invalidateOpenGLBuffers();
|
item->invalidateOpenGLBuffers();
|
||||||
scene->itemChanged(index);
|
scene->itemChanged(index);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include "run_with_qprogressdialog.h"
|
||||||
|
|
||||||
#include "ui_Point_set_wlop_plugin.h"
|
#include "ui_Point_set_wlop_plugin.h"
|
||||||
|
|
||||||
// Concurrency
|
// Concurrency
|
||||||
|
|
@ -24,6 +26,53 @@ typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
typedef CGAL::Sequential_tag Concurrency_tag;
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Compute_average_spacing_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
const int nb_neighbors;
|
||||||
|
boost::shared_ptr<double> result;
|
||||||
|
|
||||||
|
Compute_average_spacing_functor (Point_set* points, const int nb_neighbors)
|
||||||
|
: points (points), nb_neighbors (nb_neighbors), result (new double(0)) { }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
*result = CGAL::compute_average_spacing<Concurrency_tag>(
|
||||||
|
points->all_or_selection_if_not_empty(),
|
||||||
|
nb_neighbors,
|
||||||
|
points->parameters().
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Wlop_functor
|
||||||
|
: public Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
Point_set* points;
|
||||||
|
double select_percentage;
|
||||||
|
double neighbor_radius;
|
||||||
|
Scene_points_with_normal_item* new_item;
|
||||||
|
|
||||||
|
Wlop_functor (Point_set* points, double select_percentage, double neighbor_radius,
|
||||||
|
Scene_points_with_normal_item* new_item)
|
||||||
|
: points (points), select_percentage (select_percentage)
|
||||||
|
, neighbor_radius (neighbor_radius), new_item (new_item)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()()
|
||||||
|
{
|
||||||
|
CGAL::wlop_simplify_and_regularize_point_set<Concurrency_tag>
|
||||||
|
(points->all_or_selection_if_not_empty(),
|
||||||
|
new_item->point_set()->point_back_inserter(),
|
||||||
|
points->parameters().
|
||||||
|
select_percentage (select_percentage).
|
||||||
|
neighbor_radius (neighbor_radius).
|
||||||
|
callback (*(this->callback())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_point_set_wlop_plugin :
|
class Polyhedron_demo_point_set_wlop_plugin :
|
||||||
public QObject,
|
public QObject,
|
||||||
|
|
@ -38,6 +87,7 @@ class Polyhedron_demo_point_set_wlop_plugin :
|
||||||
public:
|
public:
|
||||||
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) {
|
||||||
scene = scene_interface;
|
scene = scene_interface;
|
||||||
|
mw = mainWindow;
|
||||||
actionSimplifyAndRegularize = new QAction(tr("WLOP Simplification and Regularization Selection"), mainWindow);
|
actionSimplifyAndRegularize = new QAction(tr("WLOP Simplification and Regularization Selection"), mainWindow);
|
||||||
actionSimplifyAndRegularize->setProperty("subMenuName","Point Set Processing");
|
actionSimplifyAndRegularize->setProperty("subMenuName","Point Set Processing");
|
||||||
actionSimplifyAndRegularize->setObjectName("actionSimplifyAndRegularize");
|
actionSimplifyAndRegularize->setObjectName("actionSimplifyAndRegularize");
|
||||||
|
|
@ -89,7 +139,7 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
|
||||||
if(!dialog.exec())
|
if(!dialog.exec())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::BusyCursor);
|
||||||
|
|
||||||
CGAL::Timer task_timer; task_timer.start();
|
CGAL::Timer task_timer; task_timer.start();
|
||||||
|
|
||||||
|
|
@ -98,9 +148,9 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
|
||||||
<< dialog.neighborhoodRadius() <<" * average spacing)...\n";
|
<< dialog.neighborhoodRadius() <<" * average spacing)...\n";
|
||||||
|
|
||||||
// Computes average spacing
|
// Computes average spacing
|
||||||
double average_spacing = CGAL::compute_average_spacing<Concurrency_tag>(points->all_or_selection_if_not_empty(),
|
Compute_average_spacing_functor functor_as (points, 6);
|
||||||
6 /* knn = 1 ring */,
|
run_with_qprogressdialog (functor_as, "WLOP: computing average spacing...", mw);
|
||||||
points->parameters());
|
double average_spacing = *functor_as.result;
|
||||||
|
|
||||||
Scene_points_with_normal_item* new_item
|
Scene_points_with_normal_item* new_item
|
||||||
= new Scene_points_with_normal_item();
|
= new Scene_points_with_normal_item();
|
||||||
|
|
@ -108,13 +158,10 @@ void Polyhedron_demo_point_set_wlop_plugin::on_actionSimplifyAndRegularize_trigg
|
||||||
new_item->setVisible(true);
|
new_item->setVisible(true);
|
||||||
item->setVisible(false);
|
item->setVisible(false);
|
||||||
scene->addItem(new_item);
|
scene->addItem(new_item);
|
||||||
|
|
||||||
CGAL::wlop_simplify_and_regularize_point_set<Concurrency_tag>
|
Wlop_functor functor (points, dialog.retainedPercentage(),
|
||||||
(points->all_or_selection_if_not_empty(),
|
dialog.neighborhoodRadius() * average_spacing, new_item);
|
||||||
new_item->point_set()->point_back_inserter(),
|
run_with_qprogressdialog (functor, "WLOP simplification and regularization...", mw);
|
||||||
points->parameters().
|
|
||||||
select_percentage (dialog.retainedPercentage()).
|
|
||||||
neighbor_radius (dialog.neighborhoodRadius()*average_spacing));
|
|
||||||
|
|
||||||
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
std::size_t memory = CGAL::Memory_sizer().virtual_size();
|
||||||
std::cerr << "Simplification and regularization: "
|
std::cerr << "Simplification and regularization: "
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef PROGRESS_BAR_CALLBACK_H
|
||||||
|
#define PROGRESS_BAR_CALLBACK_H
|
||||||
|
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
struct Progress_bar_callback
|
||||||
|
{
|
||||||
|
mutable std::size_t nb;
|
||||||
|
CGAL::Real_timer timer;
|
||||||
|
double t_start;
|
||||||
|
mutable double t_start_estimate;
|
||||||
|
mutable double t_latest;
|
||||||
|
int bar_size;
|
||||||
|
mutable std::size_t string_size;
|
||||||
|
|
||||||
|
Progress_bar_callback(const char* title = NULL,
|
||||||
|
void* = NULL) // Hack to have same constructor as Qt_progress_bar_callback
|
||||||
|
: nb(0), bar_size (30), string_size(0)
|
||||||
|
{
|
||||||
|
if (title != NULL)
|
||||||
|
std::cerr << title << std::endl;
|
||||||
|
|
||||||
|
timer.start();
|
||||||
|
t_start = timer.time();
|
||||||
|
t_start_estimate = 0.;
|
||||||
|
t_latest = t_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(double advancement) const
|
||||||
|
{
|
||||||
|
// Avoid calling time() at every single iteration, which could
|
||||||
|
// impact performances very badly
|
||||||
|
++ nb;
|
||||||
|
if (advancement != 1 && nb % 1000 != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If the limit is reach, interrupt the algorithm
|
||||||
|
double t = timer.time();
|
||||||
|
if (advancement == 1 || (t - t_latest) > 1.)
|
||||||
|
{
|
||||||
|
if (advancement != 0. && t_start_estimate == 0.)
|
||||||
|
t_start_estimate = t_latest;
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "[";
|
||||||
|
int adv = int(advancement * bar_size);
|
||||||
|
for (int i = 0; i < adv; ++ i)
|
||||||
|
oss << "=";
|
||||||
|
if (adv != bar_size)
|
||||||
|
oss << ">";
|
||||||
|
for (int i = adv; i < bar_size; ++ i)
|
||||||
|
oss << " ";
|
||||||
|
|
||||||
|
oss << "] " << int(advancement * 100) << "% (";
|
||||||
|
|
||||||
|
display_time (oss, t);
|
||||||
|
|
||||||
|
oss << " elapsed, ";
|
||||||
|
|
||||||
|
display_time (oss, estimate_remaining(t, advancement));
|
||||||
|
|
||||||
|
oss << " remaining)";
|
||||||
|
|
||||||
|
std::string bar_string = oss.str();
|
||||||
|
std::cerr << "\r" << bar_string;
|
||||||
|
for (std::size_t i = bar_string.size(); i < string_size; ++ i)
|
||||||
|
std::cerr << " ";
|
||||||
|
string_size = (std::max) (string_size, bar_string.size());
|
||||||
|
|
||||||
|
t_latest = t;
|
||||||
|
|
||||||
|
if (advancement == 1)
|
||||||
|
std::cerr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_time (std::ostringstream& oss, double seconds) const
|
||||||
|
{
|
||||||
|
if (seconds == std::numeric_limits<double>::infinity())
|
||||||
|
{
|
||||||
|
oss << "unknown";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (seconds > 3600.)
|
||||||
|
{
|
||||||
|
int hours = int(seconds / 3600.);
|
||||||
|
oss << hours << "h";
|
||||||
|
seconds -= hours * 3600.;
|
||||||
|
}
|
||||||
|
if (seconds > 60.)
|
||||||
|
{
|
||||||
|
int minutes = (int)(seconds / 60.);
|
||||||
|
oss << minutes << "min";
|
||||||
|
seconds -= minutes * 60.;
|
||||||
|
}
|
||||||
|
oss << int(seconds) << "sec";
|
||||||
|
}
|
||||||
|
|
||||||
|
double estimate_remaining (double seconds, double advancement) const
|
||||||
|
{
|
||||||
|
if (advancement == 0.)
|
||||||
|
return std::numeric_limits<double>::infinity();
|
||||||
|
|
||||||
|
return ((1. - advancement) * (seconds - t_start_estimate) / advancement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // PROGRESS_BAR_CALLBACK_H
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef QT_PROGRESS_BAR_CALLBACK_H
|
||||||
|
#define QT_PROGRESS_BAR_CALLBACK_H
|
||||||
|
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
class Qt_progress_bar_callback
|
||||||
|
{
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
CGAL::Real_timer timer;
|
||||||
|
double t_start;
|
||||||
|
mutable double t_latest;
|
||||||
|
|
||||||
|
mutable std::size_t nb;
|
||||||
|
|
||||||
|
QProgressDialog* dialog;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Qt_progress_bar_callback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt_progress_bar_callback(const char* title, QWidget* parent)
|
||||||
|
: dialog (new QProgressDialog (QString(title),
|
||||||
|
QString("Cancel"),
|
||||||
|
0, 100,
|
||||||
|
parent))
|
||||||
|
{
|
||||||
|
dialog->setMinimumDuration(0);
|
||||||
|
dialog->setWindowModality(Qt::WindowModal);
|
||||||
|
timer.start();
|
||||||
|
t_start = timer.time();
|
||||||
|
t_latest = t_start;
|
||||||
|
}
|
||||||
|
~Qt_progress_bar_callback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator() (double advancement) const
|
||||||
|
{
|
||||||
|
// Avoid calling time() at every single iteration, which could
|
||||||
|
// impact performances very badly
|
||||||
|
++ nb;
|
||||||
|
if (advancement != 1 && nb % 1000 != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If the limit is reach, interrupt the algorithm
|
||||||
|
double t = timer.time();
|
||||||
|
if (advancement == 1 || (t - t_latest) > 0.25)
|
||||||
|
{
|
||||||
|
dialog->setValue (int (100. * advancement));
|
||||||
|
t_latest = t;
|
||||||
|
|
||||||
|
if (dialog->wasCanceled())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // QT_PROGRESS_BAR_CALLBACK_H
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
#ifndef RUN_WITH_QPROGRESSDIALOG_H
|
||||||
|
#define RUN_WITH_QPROGRESSDIALOG_H
|
||||||
|
|
||||||
|
#include <QProgressDialog>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
#include <CGAL/thread.h>
|
||||||
|
|
||||||
|
#include "Callback_signaler.h"
|
||||||
|
|
||||||
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
|
typedef CGAL::Parallel_tag Concurrency_tag;
|
||||||
|
#else
|
||||||
|
typedef CGAL::Sequential_tag Concurrency_tag;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class Signal_callback
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
CGAL::Real_timer timer;
|
||||||
|
double t_start;
|
||||||
|
mutable double t_latest;
|
||||||
|
mutable std::size_t nb;
|
||||||
|
|
||||||
|
public:
|
||||||
|
boost::shared_ptr<double> latest_adv;
|
||||||
|
boost::shared_ptr<bool> state;
|
||||||
|
boost::shared_ptr<Callback_signaler> signaler;
|
||||||
|
|
||||||
|
Signal_callback(bool)
|
||||||
|
: latest_adv (new double(0))
|
||||||
|
, state (new bool(true))
|
||||||
|
, signaler (new Callback_signaler())
|
||||||
|
{
|
||||||
|
timer.start();
|
||||||
|
t_start = timer.time();
|
||||||
|
t_latest = t_start;
|
||||||
|
}
|
||||||
|
~Signal_callback()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator() (double advancement) const
|
||||||
|
{
|
||||||
|
if (!state)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*latest_adv = advancement;
|
||||||
|
|
||||||
|
// Avoid calling time() at every single iteration, which could
|
||||||
|
// impact performances very badly
|
||||||
|
++ nb;
|
||||||
|
if (advancement != 1 && nb % 1000 != 0)
|
||||||
|
return *state;
|
||||||
|
|
||||||
|
// If the limit is reach, interrupt the algorithm
|
||||||
|
double t = timer.time();
|
||||||
|
if (advancement == 1 || (t - t_latest) > 0.25)
|
||||||
|
{
|
||||||
|
signaler->emit_signal (int (100. * advancement));
|
||||||
|
|
||||||
|
t_latest = t;
|
||||||
|
|
||||||
|
if (signaler->is_canceled)
|
||||||
|
*state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *state;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Functor_with_signal_callback
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
boost::shared_ptr<Signal_callback> m_callback;
|
||||||
|
public:
|
||||||
|
|
||||||
|
Signal_callback* callback() { return m_callback.get(); }
|
||||||
|
|
||||||
|
Functor_with_signal_callback()
|
||||||
|
: m_callback (new Signal_callback(true)) { }
|
||||||
|
|
||||||
|
virtual void operator()() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Functor>
|
||||||
|
void run_with_qprogressdialog (Functor& functor,
|
||||||
|
const char* title,
|
||||||
|
QWidget* mainWindow)
|
||||||
|
{
|
||||||
|
return run_with_qprogressdialog<Concurrency_tag> (functor, title, mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ConcurrencyTag, typename Functor>
|
||||||
|
void run_with_qprogressdialog (Functor& functor,
|
||||||
|
const char* title,
|
||||||
|
QWidget* mainWindow)
|
||||||
|
{
|
||||||
|
mainWindow->setEnabled(false);
|
||||||
|
QProgressDialog progress (QString(title),
|
||||||
|
QString("Cancel"),
|
||||||
|
0, 100,
|
||||||
|
mainWindow);
|
||||||
|
progress.setMinimumDuration(0);
|
||||||
|
|
||||||
|
Signal_callback* signal_callback = functor.callback();
|
||||||
|
|
||||||
|
QEventLoop::connect (signal_callback->signaler.get(), SIGNAL(progressChanged(int)),
|
||||||
|
&progress, SLOT(setValue(int)));
|
||||||
|
QEventLoop::connect (&progress, SIGNAL(canceled()),
|
||||||
|
signal_callback->signaler.get(), SLOT(cancel()));
|
||||||
|
|
||||||
|
#ifdef CGAL_HAS_STD_THREADS
|
||||||
|
if (boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
|
||||||
|
{
|
||||||
|
CGAL::cpp11::thread thread (functor);
|
||||||
|
|
||||||
|
while (*signal_callback->latest_adv != 1. &&
|
||||||
|
*signal_callback->state)
|
||||||
|
{
|
||||||
|
CGAL::cpp11::sleep_for (0.1);
|
||||||
|
QApplication::processEvents ();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // Sequential version
|
||||||
|
{
|
||||||
|
progress.setWindowModality(Qt::WindowModal);
|
||||||
|
functor();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RUN_WITH_QPROGRESSDIALOG_H
|
||||||
|
|
@ -37,7 +37,8 @@
|
||||||
#include <CGAL/iterator.h>
|
#include <CGAL/iterator.h>
|
||||||
#include <CGAL/CC_safe_handle.h>
|
#include <CGAL/CC_safe_handle.h>
|
||||||
|
|
||||||
#include <tbb/tbb.h>
|
#include <tbb/enumerable_thread_specific.h>
|
||||||
|
#include <tbb/queuing_mutex.h>
|
||||||
|
|
||||||
#include <boost/mpl/if.hpp>
|
#include <boost/mpl/if.hpp>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright (c) 2018 GeometryFactory Sarl (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 Lesser 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$
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
//
|
||||||
|
// Author(s) : Simon Giraudot
|
||||||
|
|
||||||
|
#ifndef CGAL_THREAD_H
|
||||||
|
#define CGAL_THREAD_H
|
||||||
|
|
||||||
|
#include <CGAL/config.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file defines the following:
|
||||||
|
- CGAL::cpp11::thread
|
||||||
|
- CGAL::cpp11::atomic
|
||||||
|
- CGAL::cpp11::sleep_for
|
||||||
|
|
||||||
|
It uses either TBB or STD depending on what's available: as TBB can
|
||||||
|
quite often override `std::thread`, it is possible that TBB will be
|
||||||
|
used instead of STD even if the real CXX11 `std::thread` is
|
||||||
|
available.
|
||||||
|
|
||||||
|
As the conflicting API between TBB and STD can be quite complicated,
|
||||||
|
we offer a more generic `sleep_for()` function that takes
|
||||||
|
double-typed seconds as argument and deals with it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CGAL_LINKED_WITH_TBB)
|
||||||
|
# include <tbb/tbb_config.h>
|
||||||
|
# if TBB_IMPLEMENT_CPP0X
|
||||||
|
# include <tbb/compat/thread>
|
||||||
|
# include <tbb/atomic.h>
|
||||||
|
# include <tbb/tick_count.h>
|
||||||
|
# define CGAL_USE_TBB_THREADS 1
|
||||||
|
# else
|
||||||
|
# define CGAL_USE_TBB_THREADS 0
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define CGAL_USE_TBB_THREADS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !CGAL_USE_TBB_THREADS
|
||||||
|
# include <thread>
|
||||||
|
# include <atomic>
|
||||||
|
# include <chrono>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
|
||||||
|
namespace cpp11 {
|
||||||
|
|
||||||
|
#if CGAL_USE_TBB_THREADS
|
||||||
|
|
||||||
|
using std::thread; // std::thread is declared by TBB if TBB_IMPLEMENT_CPP0X == 1
|
||||||
|
using tbb::atomic;
|
||||||
|
|
||||||
|
inline void sleep_for (double seconds)
|
||||||
|
{
|
||||||
|
// std::this_thread::sleep_for is declared by TBB if TBB_IMPLEMENT_CPP0X == 1
|
||||||
|
// It takes interval_t types as argument (!= from the std norm)
|
||||||
|
std::this_thread::sleep_for(tbb::tick_count::interval_t(seconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
using std::thread;
|
||||||
|
using std::atomic;
|
||||||
|
|
||||||
|
inline void sleep_for (double seconds)
|
||||||
|
{
|
||||||
|
// MSVC2013 cannot call `sleep_for()` with other types than
|
||||||
|
// std::chrono::nanoseconds (bug in the implementation of the norm).
|
||||||
|
typedef std::chrono::nanoseconds nanoseconds;
|
||||||
|
nanoseconds ns (nanoseconds::rep (1000000000.0 * seconds));
|
||||||
|
std::this_thread::sleep_for(ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // cpp11
|
||||||
|
|
||||||
|
|
||||||
|
} //namespace CGAL
|
||||||
|
|
||||||
|
#undef CGAL_USE_TBB_THREADS
|
||||||
|
|
||||||
|
#endif // CGAL_THREAD_H
|
||||||
Loading…
Reference in New Issue