Merge pull request #3129 from sgiraudot/Point_set_processing-Callbacks-GF

Point Set Processing: Callbacks
This commit is contained in:
Laurent Rineau 2018-06-27 10:21:40 +02:00
commit c68cf8fc4c
40 changed files with 1447 additions and 232 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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
*/ */

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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;
}
} }

View File

@ -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;
} }
} }
} }

View File

@ -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;
} }
} }

View File

@ -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.

View File

@ -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;
} }
} }

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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));
} }
} }

View File

@ -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, "

View File

@ -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, "

View File

@ -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);

View File

@ -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 "

View File

@ -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());

View File

@ -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);

View File

@ -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: "

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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