Update branch from master after trailing whitespaces and tabs removal

This commit is contained in:
Sébastien Loriot 2020-03-26 19:29:05 +01:00
commit a0345b135c
21 changed files with 1323 additions and 1585 deletions

View File

@ -407,7 +407,7 @@ public:
Point_3_from_sample()), Point_3_from_sample()),
boost::make_transform_iterator (m_samples.end(), boost::make_transform_iterator (m_samples.end(),
Point_3_from_sample())), Point_3_from_sample())),
3); 3, CGAL::parameters::point_map (CGAL::Identity_property_map_no_lvalue<K::Point_3>()));
std::cerr << "Average spacing = " << spacing << std::endl; std::cerr << "Average spacing = " << spacing << std::endl;
} }

View File

@ -0,0 +1,184 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Simon Giraudot
#ifndef CGAL_PSP_INTERNAL_CALLBACK_WRAPPER_H
#define CGAL_PSP_INTERNAL_CALLBACK_WRAPPER_H
#include <CGAL/license/Point_set_processing_3.h>
#include <functional>
#include <CGAL/thread.h>
namespace CGAL {
namespace Point_set_processing_3 {
namespace internal {
template <typename ConcurrencyTag>
class Callback_wrapper
{
std::size_t m_advancement;
bool m_interrupted;
public:
Callback_wrapper (const std::function<bool(double)>&, std::size_t, std::size_t, bool = false) { }
void reset (std::size_t, std::size_t, bool = false) { }
std::size_t& advancement() { return m_advancement; }
bool& interrupted() { return m_interrupted; }
void join() { }
};
template <>
class Callback_wrapper<CGAL::Sequential_tag>
{
const std::function<bool(double)>& m_callback;
std::size_t m_advancement;
bool m_interrupted;
std::size_t m_size;
public:
Callback_wrapper (const std::function<bool(double)>& callback,
std::size_t size,
std::size_t advancement = 0,
bool interrupted = false)
: m_callback (callback)
, m_advancement (advancement)
, m_interrupted (interrupted)
, m_size (size)
{ }
Callback_wrapper (const Callback_wrapper& other)
: m_callback (other.m_callback)
, m_advancement (other.m_advancement)
, m_interrupted (other.m_interrupted)
, m_size (other.m_size)
{ }
~Callback_wrapper () { }
void reset (std::size_t size, std::size_t advancement, bool interrupted = false)
{
m_size = size;
m_advancement = advancement;
m_interrupted = interrupted;
}
std::size_t& advancement()
{
return m_advancement;
}
bool& interrupted()
{
if (m_callback)
m_interrupted = !(m_callback(m_advancement / double(m_size)));
return m_interrupted;
}
void join() { }
};
#ifdef CGAL_LINKED_WITH_TBB
template <>
class Callback_wrapper<CGAL::Parallel_tag>
{
const std::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)
Callback_wrapper& operator= (const Callback_wrapper&)
{
return *this;
}
public:
Callback_wrapper (const std::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 (nullptr)
{
// 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);
}
Callback_wrapper (const Callback_wrapper& 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 (nullptr)
{
}
~Callback_wrapper ()
{
if (m_creator)
{
delete m_advancement;
delete m_interrupted;
}
if (m_thread != nullptr)
delete m_thread;
}
void reset (std::size_t size, std::size_t advancement, bool interrupted = false)
{
m_size = size;
*m_advancement = advancement;
*m_interrupted = interrupted;
if (m_callback)
m_thread = new cpp11::thread (*this);
}
cpp11::atomic<std::size_t>& advancement() { return *m_advancement; }
cpp11::atomic<bool>& interrupted() { return *m_interrupted; }
void join()
{
if (m_thread != nullptr)
m_thread->join();
}
void operator()()
{
while (*m_advancement != m_size)
{
if (m_callback && !m_callback (*m_advancement / double(m_size)))
*m_interrupted = true;
if (*m_interrupted)
return;
cpp11::sleep_for (0.00001);
}
if (m_callback)
m_callback (1.);
}
};
#endif
} // namespace internal
} // namespace Point_set_processing_3
} // namespace CGAL
#endif // CGAL_PSP_INTERNAL_CALLBACK_WRAPPER_H

View File

@ -0,0 +1,180 @@
// Copyright (c) 2019 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Simon Giraudot
#ifndef CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H
#define CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H
#include <CGAL/license/Point_set_processing_3.h>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/point_set_processing_assertions.h>
#include <CGAL/iterator.h>
#include <boost/function_output_iterator.hpp>
namespace CGAL {
namespace Point_set_processing_3 {
namespace internal {
struct Maximum_points_reached_exception : public std::exception { };
template <typename Kernel_, typename PointRangeRef, typename PointMap>
class Neighbor_query
{
public:
typedef Kernel_ Kernel;
typedef PointRangeRef Point_range;
typedef PointMap Point_map;
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point_3;
typedef typename Range_iterator_type<PointRangeRef>::type input_iterator;
typedef typename input_iterator::value_type value_type;
typedef CGAL::Prevent_deref<input_iterator> iterator;
struct Deref_point_map
{
typedef input_iterator key_type;
typedef typename boost::property_traits<PointMap>::reference reference;
typedef typename boost::property_traits<PointMap>::value_type value_type;
typedef typename boost::property_traits<PointMap>::category category;
PointMap point_map;
Deref_point_map () { }
Deref_point_map (PointMap point_map) : point_map(point_map) { }
friend reference get (const Deref_point_map& map, key_type it)
{
return get(map.point_map, *it);
}
};
typedef CGAL::Search_traits_3<Kernel> Tree_traits_base;
typedef CGAL::Search_traits_adapter<input_iterator, Deref_point_map, Tree_traits_base> Tree_traits;
typedef CGAL::Sliding_midpoint<Tree_traits> Splitter;
typedef CGAL::Distance_adapter<input_iterator, Deref_point_map, CGAL::Euclidean_distance<Tree_traits_base> > Distance;
typedef CGAL::Kd_tree<Tree_traits, Splitter, CGAL::Tag_true, CGAL::Tag_true> Tree;
typedef CGAL::Fuzzy_sphere<Tree_traits> Sphere;
typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits, Distance, Splitter, Tree> Neighbor_search;
typedef typename Neighbor_search::iterator Search_iterator;
private:
PointRangeRef m_points;
PointMap m_point_map;
Deref_point_map m_deref_map;
Tree_traits m_traits;
Tree m_tree;
Distance m_distance;
// Forbid copy
Neighbor_query (const Neighbor_query&) { }
public:
Neighbor_query (PointRangeRef points, PointMap point_map)
: m_points (points)
, m_point_map (point_map)
, m_deref_map (point_map)
, m_traits (m_deref_map)
, m_tree (iterator(m_points.begin()), iterator(m_points.end()), Splitter(), m_traits)
, m_distance (m_deref_map)
{
m_tree.build();
}
PointMap point_map() const { return m_point_map; }
template <typename OutputIterator>
void get_iterators (const Point_3& query, unsigned int k, FT neighbor_radius,
OutputIterator output) const
{
if (neighbor_radius != FT(0))
{
Sphere fs (query, neighbor_radius, 0, m_traits);
// if k=0, no limit on the number of neighbors returned
if (k == 0)
k = (std::numeric_limits<unsigned int>::max)();
unsigned int nb = 0;
try
{
std::function<void(const input_iterator&)> output_iterator_with_limit
= [&](const input_iterator& it)
{
*(output ++) = it;
if (++ nb == k)
throw Maximum_points_reached_exception();
};
auto function_output_iterator
= boost::make_function_output_iterator (output_iterator_with_limit);
m_tree.search (function_output_iterator, fs);
}
catch (const Maximum_points_reached_exception&)
{ }
// Fallback, if less than 3 points are return, search for the 3
// first points
if (nb < 3)
k = 3;
// Else, no need to search for K nearest neighbors
else
k = 0;
}
if (k != 0)
{
// Gather set of (k+1) neighboring points.
// Perform k+1 queries (as in point set, the query point is
// output first). Search may be aborted if k is greater
// than number of input points.
Neighbor_search search (m_tree, query, k+1, 0, true, m_distance);
Search_iterator search_iterator = search.begin();
unsigned int i;
for (i = 0; i < (k+1); ++ i)
{
if(search_iterator == search.end())
break; // premature ending
*(output ++) = search_iterator->first;
search_iterator++;
}
}
}
template <typename OutputIterator>
void get_points (const Point_3& query, unsigned int k, FT neighbor_radius,
OutputIterator output) const
{
return get_iterators(query, k, neighbor_radius,
boost::make_function_output_iterator
([&](const input_iterator& it)
{
*(output ++) = get (m_point_map, *it);
}));
}
};
} } } // namespace CGAL::Point_set_processing_3::internal
#endif // CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H

View File

@ -1,108 +0,0 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Simon Giraudot
#ifndef CGAL_PSP_INTERNAL_PARALLEL_CALLBACK_H
#define CGAL_PSP_INTERNAL_PARALLEL_CALLBACK_H
#include <CGAL/license/Point_set_processing_3.h>
#include <functional>
#include <CGAL/thread.h>
namespace CGAL {
namespace Point_set_processing_3 {
namespace internal {
class Parallel_callback
{
const std::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 std::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 (nullptr)
{
// 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 (nullptr)
{
}
~Parallel_callback ()
{
if (m_creator)
{
delete m_advancement;
delete m_interrupted;
}
if (m_thread != nullptr)
delete m_thread;
}
cpp11::atomic<std::size_t>& advancement() { return *m_advancement; }
cpp11::atomic<bool>& interrupted() { return *m_interrupted; }
void join()
{
if (m_thread != nullptr)
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 internal
} // namespace Point_set_processing_3
} // namespace CGAL
#endif // CGAL_PSP_INTERNAL_PARALLEL_CALLBACK_H

View File

@ -1,104 +0,0 @@
// Copyright (c) 2019 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Simon Giraudot
#ifndef CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H
#define CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H
#include <CGAL/license/Point_set_processing_3.h>
#include <CGAL/Search_traits_3.h>
#include <CGAL/Fuzzy_sphere.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/point_set_processing_assertions.h>
#include <boost/function_output_iterator.hpp>
namespace CGAL {
namespace Point_set_processing_3 {
namespace internal {
struct Maximum_points_reached_exception : public std::exception { };
template <typename Point,
typename TreeTraits,
typename TreeSplitter,
typename TreeUseExtendedNode,
typename FT,
typename PointContainer>
void neighbor_query (const Point& query,
const CGAL::Kd_tree<TreeTraits, TreeSplitter, TreeUseExtendedNode>& tree,
unsigned int k,
FT neighbor_radius,
PointContainer& points)
{
typedef typename CGAL::Orthogonal_k_neighbor_search<TreeTraits> Neighbor_search;
typedef typename Neighbor_search::iterator Search_iterator;
typedef CGAL::Fuzzy_sphere<TreeTraits> Sphere;
if (neighbor_radius != FT(0))
{
Sphere fs (query, neighbor_radius, 0, tree.traits());
// if k=0, no limit on the number of neighbors returned
if (k == 0)
k = (std::numeric_limits<unsigned int>::max)();
try
{
std::function<void(const Point&)> back_insert_with_limit
= [&](const Point& point) -> void
{
points.push_back (point);
if (points.size() == k)
throw Maximum_points_reached_exception();
};
auto function_output_iterator
= boost::make_function_output_iterator (back_insert_with_limit);
tree.search (function_output_iterator, fs);
}
catch (const Maximum_points_reached_exception&)
{ }
// Fallback, if less than 3 points are return, search for the 3
// first points
if (points.size() < 3)
k = 3;
// Else, no need to search for K nearest neighbors
else
k = 0;
}
if (k != 0)
{
// Gather set of (k+1) neighboring points.
// Perform k+1 queries (as in point set, the query point is
// output first). Search may be aborted if k is greater
// than number of input points.
points.reserve(k+1);
Neighbor_search search(tree,query,k+1);
Search_iterator search_iterator = search.begin();
unsigned int i;
for(i=0;i<(k+1);i++)
{
if(search_iterator == search.end())
break; // premature ending
points.push_back(search_iterator->first);
search_iterator++;
}
CGAL_point_set_processing_precondition(points.size() >= 1);
}
}
} } } // namespace CGAL::Point_set_processing_3::internal
#endif // CGAL_PSP_INTERNAL_NEIGHBOR_QUERY_H

View File

@ -17,18 +17,19 @@
#include <CGAL/disable_warnings.h> #include <CGAL/disable_warnings.h>
#include <CGAL/number_type_config.h> #include <CGAL/number_type_config.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.h> #include <CGAL/for_each.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/Point_with_normal_3.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>
#include <functional> #include <functional>
#include <CGAL/boost/graph/Named_function_parameters.h> #include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
#include <boost/iterator/zip_iterator.hpp>
#include <iterator> #include <iterator>
#include <set> #include <set>
#include <algorithm> #include <algorithm>
@ -38,23 +39,6 @@
#include <CGAL/Memory_sizer.h> #include <CGAL/Memory_sizer.h>
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#include <atomic>
#endif // CGAL_LINKED_WITH_TBB
// Default allocator: use TBB allocators if available
#ifdef CGAL_LINKED_WITH_TBB
# define CGAL_PSP3_DEFAULT_ALLOCATOR tbb::scalable_allocator
#else // CGAL_LINKED_WITH_TBB
# define CGAL_PSP3_DEFAULT_ALLOCATOR std::allocator
#endif // CGAL_LINKED_WITH_TBB
//#define CGAL_PSP3_VERBOSE //#define CGAL_PSP3_VERBOSE
namespace CGAL { namespace CGAL {
@ -66,47 +50,6 @@ namespace CGAL {
namespace bilateral_smooth_point_set_internal{ namespace bilateral_smooth_point_set_internal{
// Item in the Kd-tree: position (Point_3) + index
template <typename Kernel>
class Kd_tree_element : public Point_with_normal_3<Kernel>
{
public:
unsigned int index;
// basic geometric types
typedef typename CGAL::Origin Origin;
typedef CGAL::Point_with_normal_3<Kernel> Base;
Kd_tree_element(const Origin& o = ORIGIN, unsigned int id=0)
: Base(o), index(id)
{}
Kd_tree_element(const Base& p, unsigned int id=0)
: Base(p), index(id)
{}
Kd_tree_element(const Kd_tree_element& other)
: Base(other), index(other.index)
{}
Kd_tree_element& operator=(const Kd_tree_element&)=default;
};
// Helper class for the Kd-tree
template <typename Kernel>
class Kd_tree_gt : public Kernel
{
public:
typedef Kd_tree_element<Kernel> Point_3;
};
template <typename Kernel>
class Kd_tree_traits : public CGAL::Search_traits_3<Kd_tree_gt<Kernel> >
{
public:
typedef typename Kernel::Point_3 PointType;
};
/// Compute bilateral projection for each point /// Compute bilateral projection for each point
/// according to their KNN neighborhood points /// according to their KNN neighborhood points
/// ///
@ -117,12 +60,14 @@ public:
/// ///
/// @return /// @return
template <typename Kernel> template <typename Kernel, typename PointRange,
CGAL::Point_with_normal_3<Kernel> typename PointMap, typename VectorMap>
std::pair<typename Kernel::Point_3, typename Kernel::Vector_3>
compute_denoise_projection( compute_denoise_projection(
const CGAL::Point_with_normal_3<Kernel>& query, ///< 3D point to project const typename PointRange::iterator::value_type& vt,
const std::vector<CGAL::Point_with_normal_3<Kernel>, PointMap point_map,
CGAL_PSP3_DEFAULT_ALLOCATOR<CGAL::Point_with_normal_3<Kernel> > >& neighbor_pwns, // VectorMap normal_map,
const std::vector<typename PointRange::iterator>& neighbor_pwns,
typename Kernel::FT radius, ///< accept neighborhood radius typename Kernel::FT radius, ///< accept neighborhood radius
typename Kernel::FT sharpness_angle ///< control sharpness(0-90) typename Kernel::FT sharpness_angle ///< control sharpness(0-90)
) )
@ -133,7 +78,6 @@ compute_denoise_projection(
// basic geometric types // basic geometric types
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
typedef CGAL::Point_with_normal_3<Kernel> Pwn;
typedef typename Kernel::Vector_3 Vector; typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
@ -148,23 +92,21 @@ compute_denoise_projection(
FT cos_sigma = cos(sharpness_angle * CGAL_PI / 180.0); FT cos_sigma = cos(sharpness_angle * CGAL_PI / 180.0);
FT sharpness_bandwidth = std::pow((CGAL::max)(1e-8, 1 - cos_sigma), 2); FT sharpness_bandwidth = std::pow((CGAL::max)(1e-8, 1 - cos_sigma), 2);
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::const_iterator for (typename PointRange::iterator it : neighbor_pwns)
pwn_iter = neighbor_pwns.begin();
for (; pwn_iter != neighbor_pwns.end(); ++pwn_iter)
{ {
const Point& np = pwn_iter->position(); const Point& np = get(point_map, *it);
const Vector& nn = pwn_iter->normal(); const Vector& nn = get(normal_map, *it);
FT dist2 = CGAL::squared_distance(query.position(), np); FT dist2 = CGAL::squared_distance(get(point_map, vt), np);
if (dist2 < radius2) if (dist2 < radius2)
{ {
FT theta = std::exp(dist2 * iradius16); FT theta = std::exp(dist2 * iradius16);
FT psi = std::exp(-std::pow(1 - query.normal() * nn, 2) FT psi = std::exp(-std::pow(1 - get(normal_map, vt) * nn, 2)
/ sharpness_bandwidth); / sharpness_bandwidth);
weight = theta * psi; weight = theta * psi;
project_dist_sum += ((query.position() - np) * nn) * weight; project_dist_sum += ((get(point_map, vt) - np) * nn) * weight;
project_weight_sum += weight; project_weight_sum += weight;
normal_sum = normal_sum + nn * weight; normal_sum = normal_sum + nn * weight;
} }
@ -173,10 +115,10 @@ compute_denoise_projection(
Vector update_normal = normal_sum / project_weight_sum; Vector update_normal = normal_sum / project_weight_sum;
update_normal = update_normal / sqrt(update_normal.squared_length()); update_normal = update_normal / sqrt(update_normal.squared_length());
Point update_point = query.position() - update_normal * Point update_point = get(point_map, vt) - update_normal *
(project_dist_sum / project_weight_sum); (project_dist_sum / project_weight_sum);
return Pwn(update_point, update_normal); return std::make_pair (update_point, update_normal);
} }
/// Computes max-spacing of one query point from K nearest neighbors. /// Computes max-spacing of one query point from K nearest neighbors.
@ -187,41 +129,30 @@ compute_denoise_projection(
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return max spacing. /// @return max spacing.
template < typename Kernel, template <typename NeighborQuery>
typename Tree > typename NeighborQuery::Kernel::FT
typename Kernel::FT
compute_max_spacing( compute_max_spacing(
const CGAL::Point_with_normal_3<Kernel>& query, ///< 3D point const typename NeighborQuery::value_type& vt,
Tree& tree, ///< KD-tree typename NeighborQuery::Point_map point_map,
NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k) ///< number of neighbors unsigned int k) ///< number of neighbors
{ {
// basic geometric types // basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
typedef CGAL::Point_with_normal_3<Kernel> Pwn;
// types for K nearest neighbors search
typedef bilateral_smooth_point_set_internal::Kd_tree_traits<Kernel> Tree_traits;
typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::iterator Search_iterator;
// performs k + 1 queries (if unique the query point is // performs k + 1 queries (if unique the query point is
// output first). search may be aborted when k is greater // output first). search may be aborted when k is greater
// than number of input points // than number of input points
Neighbor_search search(tree,query,k+1);
Search_iterator search_iterator = search.begin();
++search_iterator;
FT max_distance = (FT)0.0; FT max_distance = (FT)0.0;
unsigned int i; neighbor_query.get_iterators
for(i = 0; i < (k+1) ; ++i) (get(point_map, vt), k, (FT)(0.0),
boost::make_function_output_iterator
([&](const typename NeighborQuery::input_iterator& it)
{ {
if(search_iterator == search.end()) double dist2 = CGAL::squared_distance (get(point_map, vt), get(point_map, *it));
break; // premature ending
Pwn pwn = search_iterator->first;
double dist2 = CGAL::squared_distance(query.position(), pwn.position());
max_distance = (CGAL::max)(dist2, max_distance); max_distance = (CGAL::max)(dist2, max_distance);
++search_iterator; }));
}
// output max spacing // output max spacing
return std::sqrt(max_distance); return std::sqrt(max_distance);
@ -231,102 +162,6 @@ compute_max_spacing(
/// \endcond /// \endcond
#ifdef CGAL_LINKED_WITH_TBB
/// \cond SKIP_IN_MANUAL
/// This is for parallelization of function: bilateral_smooth_point_set()
template <typename Kernel, typename Tree>
class Compute_pwns_neighbors
{
typedef typename CGAL::Point_with_normal_3<Kernel> Pwn;
typedef typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> > Pwns;
typedef typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >
Pwns_neighbors;
typedef typename Kernel::FT FT;
unsigned int m_k;
FT m_neighbor_radius;
const Tree & m_tree;
const Pwns & m_pwns;
Pwns_neighbors & m_pwns_neighbors;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Compute_pwns_neighbors(unsigned int k, FT neighbor_radius, const Tree &tree,
const Pwns &pwns, Pwns_neighbors &neighbors,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: m_k(k), m_neighbor_radius (neighbor_radius), m_tree(tree)
, m_pwns(pwns), m_pwns_neighbors(neighbors)
, advancement (advancement), interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const
{
for (size_t i = r.begin(); i!=r.end(); i++)
{
if (interrupted)
break;
CGAL::Point_set_processing_3::internal::neighbor_query
(m_pwns[i], m_tree, m_k, m_neighbor_radius, m_pwns_neighbors[i]);
++ advancement;
}
}
};
/// \endcond
/// \cond SKIP_IN_MANUAL
/// This is for parallelization of function: compute_denoise_projection()
template <typename Kernel>
class Pwn_updater
{
typedef typename CGAL::Point_with_normal_3<Kernel> Pwn;
typedef typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> > Pwns;
typedef typename Kernel::FT FT;
FT sharpness_angle;
FT radius;
Pwns* pwns;
Pwns* update_pwns;
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* pwns_neighbors;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Pwn_updater(FT sharpness,
FT r,
Pwns *in,
Pwns *out,
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >* neighbors,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted):
sharpness_angle(sharpness),
radius(r),
pwns(in),
update_pwns(out),
pwns_neighbors(neighbors),
advancement (advancement),
interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const
{
for (size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
(*update_pwns)[i] = bilateral_smooth_point_set_internal::
compute_denoise_projection<Kernel>((*pwns)[i],
(*pwns_neighbors)[i],
radius,
sharpness_angle);
++ advancement;
}
}
};
/// \endcond
#endif // CGAL_LINKED_WITH_TBB
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Public section // Public section
@ -400,16 +235,18 @@ bilateral_smooth_point_set(
using parameters::get_parameter; using parameters::get_parameter;
// basic geometric types // basic geometric types
typedef typename PointRange::iterator iterator;
typedef typename iterator::value_type value_type;
typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap; typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap;
typedef typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap; typedef typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap;
typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel; typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel;
typedef typename Kernel::Point_3 Point_3;
typedef typename Kernel::Vector_3 Vector_3;
CGAL_static_assertion_msg(!(boost::is_same<NormalMap, CGAL_static_assertion_msg(!(boost::is_same<NormalMap,
typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::NoMap>::value), typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::NoMap>::value),
"Error: no normal map"); "Error: no normal map");
typedef typename CGAL::Point_with_normal_3<Kernel> Pwn;
typedef typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> > Pwns;
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
double sharpness_angle = choose_parameter(get_parameter(np, internal_np::sharpness_angle), 30.); double sharpness_angle = choose_parameter(get_parameter(np, internal_np::sharpness_angle), 30.);
@ -420,43 +257,20 @@ bilateral_smooth_point_set(
CGAL_point_set_processing_precondition(k > 1); CGAL_point_set_processing_precondition(k > 1);
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef bilateral_smooth_point_set_internal:: typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
Kd_tree_element<Kernel> Kd_tree_element;
typedef bilateral_smooth_point_set_internal::Kd_tree_traits<Kernel> Tree_traits;
typedef CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
PointMap point_map = choose_parameter<PointMap>(get_parameter(np, internal_np::point_map)); PointMap point_map = choose_parameter<PointMap>(get_parameter(np, internal_np::point_map));
NormalMap normal_map = choose_parameter<NormalMap>(get_parameter(np, internal_np::normal_map)); NormalMap normal_map = choose_parameter<NormalMap>(get_parameter(np, internal_np::normal_map));
FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0)); FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0));
// copy points and normals std::size_t nb_points = points.size();
Pwns pwns;
for(typename PointRange::iterator it = points.begin(); it != points.end(); ++it)
{
typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
typename boost::property_traits<NormalMap>::reference n = get(normal_map, *it);
CGAL_point_set_processing_precondition(n.squared_length() > 1e-10);
pwns.push_back(Pwn(p, n));
}
std::size_t nb_points = pwns.size();
#ifdef CGAL_PSP3_VERBOSE #ifdef CGAL_PSP3_VERBOSE
std::cout << "Initialization and compute max spacing: " << std::endl; std::cout << "Initialization and compute max spacing: " << std::endl;
#endif #endif
// initiate a KD-tree search for points // initiate a KD-tree search for points
std::vector<Kd_tree_element, Neighbor_query neighbor_query (points, point_map);
CGAL_PSP3_DEFAULT_ALLOCATOR<Kd_tree_element> > treeElements;
treeElements.reserve(pwns.size());
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
pwn_iter = pwns.begin();
for (unsigned int i = 0; pwn_iter != pwns.end(); ++pwn_iter)
{
treeElements.push_back(Kd_tree_element(*pwn_iter, i));
}
Tree tree(treeElements.begin(), treeElements.end());
// Guess spacing // Guess spacing
#ifdef CGAL_PSP3_VERBOSE #ifdef CGAL_PSP3_VERBOSE
CGAL::Real_timer task_timer; CGAL::Real_timer task_timer;
@ -464,10 +278,10 @@ bilateral_smooth_point_set(
#endif #endif
FT guess_neighbor_radius = 0.0; FT guess_neighbor_radius = 0.0;
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter) for (const value_type& vt : points)
{ {
FT max_spacing = bilateral_smooth_point_set_internal:: FT max_spacing = bilateral_smooth_point_set_internal::
compute_max_spacing<Kernel,Tree>(*pwn_iter, tree, k); compute_max_spacing (vt, point_map, neighbor_query, k);
guess_neighbor_radius = (CGAL::max)(max_spacing, guess_neighbor_radius); guess_neighbor_radius = (CGAL::max)(max_spacing, guess_neighbor_radius);
} }
@ -486,49 +300,40 @@ bilateral_smooth_point_set(
task_timer.start(); task_timer.start();
#endif #endif
// compute all neighbors // compute all neighbors
std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> > pwns_neighbors; typedef std::vector<iterator> iterators;
std::vector<iterators> pwns_neighbors;
pwns_neighbors.resize(nb_points); pwns_neighbors.resize(nb_points);
#ifndef CGAL_LINKED_WITH_TBB Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value), callback_wrapper (callback, 2 * nb_points);
"Parallel_tag is enabled but TBB is unavailable.");
#else typedef boost::zip_iterator<boost::tuple<iterator, typename std::vector<iterators>::iterator> > Zip_iterator;
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
CGAL::for_each<ConcurrencyTag>
(CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (points.begin(), pwns_neighbors.begin())),
boost::make_zip_iterator (boost::make_tuple (points.end(), pwns_neighbors.end()))),
[&](const typename Zip_iterator::reference& t)
{ {
Point_set_processing_3::internal::Parallel_callback if (callback_wrapper.interrupted())
parallel_callback (callback, 2 * nb_points); return false;
Compute_pwns_neighbors<Kernel, Tree> f(k, neighbor_radius, tree, pwns, pwns_neighbors, neighbor_query.get_iterators (get(point_map, get<0>(t)), k, neighbor_radius,
parallel_callback.advancement(), std::back_inserter (get<1>(t)));
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f);
bool interrupted = parallel_callback.interrupted(); ++ callback_wrapper.advancement();
return true;
});
bool interrupted = callback_wrapper.interrupted();
// We interrupt by hand as counter only goes halfway and won't terminate by itself // We interrupt by hand as counter only goes halfway and won't terminate by itself
parallel_callback.interrupted() = true; callback_wrapper.interrupted() = true;
parallel_callback.join(); callback_wrapper.join();
// If interrupted during this step, nothing is computed, we return NaN // If interrupted during this step, nothing is computed, we return NaN
if (interrupted) if (interrupted)
return std::numeric_limits<double>::quiet_NaN(); return std::numeric_limits<double>::quiet_NaN();
}
else
#endif
{
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
pwns_iter = pwns_neighbors.begin();
std::size_t nb = 0;
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end(); ++pwn_iter, ++pwns_iter, ++ nb)
{
CGAL::Point_set_processing_3::internal::neighbor_query
(*pwn_iter, tree, k, neighbor_radius, *pwns_iter);
if (callback && !callback ((nb+1) / double(2. * nb_points)))
return std::numeric_limits<double>::quiet_NaN();
}
}
#ifdef CGAL_PSP3_VERBOSE #ifdef CGAL_PSP3_VERBOSE
task_timer.stop(); task_timer.stop();
@ -541,53 +346,45 @@ bilateral_smooth_point_set(
task_timer.start(); task_timer.start();
#endif #endif
// update points and normals // update points and normals
Pwns update_pwns(nb_points); std::vector<std::pair<Point_3, Vector_3> > update_pwns(nb_points);
#ifdef CGAL_LINKED_WITH_TBB callback_wrapper.reset (2 * nb_points, nb_points);
if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
typedef boost::zip_iterator
<boost::tuple<iterator,
typename std::vector<iterators>::iterator,
typename std::vector<std::pair<Point_3, Vector_3> >::iterator> > Zip_iterator_2;
CGAL::for_each<ConcurrencyTag>
(CGAL::make_range (boost::make_zip_iterator (boost::make_tuple
(points.begin(), pwns_neighbors.begin(), update_pwns.begin())),
boost::make_zip_iterator (boost::make_tuple
(points.end(), pwns_neighbors.end(), update_pwns.end()))),
[&](const typename Zip_iterator_2::reference& t)
{ {
Point_set_processing_3::internal::Parallel_callback if (callback_wrapper.interrupted())
parallel_callback (callback, 2 * nb_points, nb_points); return false;
//tbb::task_scheduler_init init(4); get<2>(t) = bilateral_smooth_point_set_internal::
tbb::blocked_range<size_t> block(0, nb_points); compute_denoise_projection<Kernel, PointRange>
Pwn_updater<Kernel> pwn_updater(sharpness_angle, (get<0>(t),
guess_neighbor_radius, point_map, normal_map,
&pwns, get<1>(t),
&update_pwns,
&pwns_neighbors,
parallel_callback.advancement(),
parallel_callback.interrupted());
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
#endif // CGAL_LINKED_WITH_TBB
{
std::size_t nb = nb_points;
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::iterator
update_iter = update_pwns.begin();
typename std::vector<Pwns,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwns> >::iterator
neighbor_iter = pwns_neighbors.begin();
for(pwn_iter = pwns.begin(); pwn_iter != pwns.end();
++pwn_iter, ++update_iter, ++neighbor_iter, ++ nb)
{
*update_iter = bilateral_smooth_point_set_internal::
compute_denoise_projection<Kernel>
(*pwn_iter,
*neighbor_iter,
guess_neighbor_radius, guess_neighbor_radius,
sharpness_angle); sharpness_angle);
if (callback && !callback ((nb+1) / double(2. * nb_points)))
++ callback_wrapper.advancement();
return true;
});
callback_wrapper.join();
// If interrupted during this step, nothing is computed, we return NaN
if (callback_wrapper.interrupted())
return std::numeric_limits<double>::quiet_NaN(); return std::numeric_limits<double>::quiet_NaN();
}
}
#ifdef CGAL_PSP3_VERBOSE #ifdef CGAL_PSP3_VERBOSE
task_timer.stop(); task_timer.stop();
memory = CGAL::Memory_sizer().virtual_size(); memory = CGAL::Memory_sizer().virtual_size();
@ -596,13 +393,13 @@ bilateral_smooth_point_set(
#endif #endif
// save results // save results
FT sum_move_error = 0; FT sum_move_error = 0;
typename PointRange::iterator it = points.begin(); std::size_t nb = 0;
for(unsigned int i = 0 ; it != points.end(); ++it, ++i) for (value_type& vt : points)
{ {
typename boost::property_traits<PointMap>::reference p = get(point_map, *it); sum_move_error += CGAL::squared_distance(get(point_map, vt), update_pwns[nb].first);
sum_move_error += CGAL::squared_distance(p, update_pwns[i].position()); put (point_map, vt, update_pwns[nb].first);
put (point_map, *it, update_pwns[i].position()); put (normal_map, vt, update_pwns[nb].second);
put (normal_map, *it, update_pwns[i].normal()); ++ nb;
} }
return sum_move_error / nb_points; return sum_move_error / nb_points;

View File

@ -18,7 +18,9 @@
#include <CGAL/Search_traits_3.h> #include <CGAL/Search_traits_3.h>
#include <CGAL/squared_distance_3.h> #include <CGAL/squared_distance_3.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/for_each.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/assertions.h> #include <CGAL/assertions.h>
@ -27,15 +29,12 @@
#include <CGAL/boost/graph/Named_function_parameters.h> #include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/boost/graph/named_params_helper.h> #include <CGAL/boost/graph/named_params_helper.h>
#include <boost/iterator/zip_iterator.hpp>
#include <iterator> #include <iterator>
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
#ifdef DOXYGEN_RUNNING #ifdef DOXYGEN_RUNNING
#define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters
@ -60,81 +59,37 @@ namespace internal {
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return average spacing (scalar). /// @return average spacing (scalar).
template < typename Kernel, template <typename NeighborQuery>
typename Tree > typename NeighborQuery::Kernel::FT
typename Kernel::FT compute_average_spacing(const typename NeighborQuery::Kernel::Point_3& query, ///< 3D point whose spacing we want to compute
compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point whose spacing we want to compute const NeighborQuery& neighbor_query, ///< KD-tree
const Tree& tree, ///< KD-tree
unsigned int k) ///< number of neighbors unsigned int k) ///< number of neighbors
{ {
// basic geometric types // basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
// types for K nearest neighbors search
typedef Search_traits_3<Kernel> Tree_traits;
typedef Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::iterator Search_iterator;
// performs k + 1 queries (if unique the query point is // performs k + 1 queries (if unique the query point is
// output first). search may be aborted when k is greater // output first). search may be aborted when k is greater
// than number of input points // than number of input points
Neighbor_search search(tree,query,k+1);
Search_iterator search_iterator = search.begin();
FT sum_distances = (FT)0.0; FT sum_distances = (FT)0.0;
unsigned int i; unsigned int i = 0;
for(i=0;i<(k+1);i++) neighbor_query.get_points
(query, k, 0,
boost::make_function_output_iterator
([&](const Point& p)
{ {
if(search_iterator == search.end())
break; // premature ending
Point p = search_iterator->first;
sum_distances += std::sqrt(CGAL::squared_distance (query,p)); sum_distances += std::sqrt(CGAL::squared_distance (query,p));
search_iterator++; ++ i;
} }));
// output average spacing // output average spacing
return sum_distances / (FT)i; return sum_distances / (FT)i;
} }
#ifdef CGAL_LINKED_WITH_TBB
template <typename Kernel, typename Tree>
class Compute_average_spacings {
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
const Tree& tree;
const unsigned int k;
const std::vector<Point>& input;
std::vector<FT>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Compute_average_spacings(Tree& tree, unsigned int k, std::vector<Point>& points,
std::vector<FT>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ }
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
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);
++ advancement;
}
}
};
#endif // CGAL_LINKED_WITH_TBB
} /* namespace internal */ } /* namespace internal */
/// \endcond /// \endcond
@ -195,20 +150,17 @@ compute_average_spacing(
using parameters::get_parameter; using parameters::get_parameter;
// basic geometric types // basic geometric types
typedef typename PointRange::const_iterator iterator;
typedef typename CGAL::GetPointMap<PointRange, CGAL_BGL_NP_CLASS>::const_type PointMap; typedef typename CGAL::GetPointMap<PointRange, CGAL_BGL_NP_CLASS>::const_type PointMap;
typedef typename Point_set_processing_3::GetK<PointRange, CGAL_BGL_NP_CLASS>::Kernel Kernel; typedef typename Point_set_processing_3::GetK<PointRange, CGAL_BGL_NP_CLASS>::Kernel Kernel;
typedef typename Kernel::Point_3 Point; PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap());
PointMap point_map = choose_parameter<PointMap>(get_parameter(np, internal_np::point_map));
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback), const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>()); std::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;
typedef Search_traits_3<Kernel> Tree_traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, const PointRange&, PointMap> Neighbor_query;
typedef Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// precondition: at least one element in the container. // precondition: at least one element in the container.
// to fix: should have at least three distinct points // to fix: should have at least three distinct points
@ -219,32 +171,35 @@ compute_average_spacing(
CGAL_point_set_processing_precondition(k >= 2); CGAL_point_set_processing_precondition(k >= 2);
// Instanciate a KD-tree search. // Instanciate a KD-tree search.
// Note: We have to convert each input iterator to Point_3. Neighbor_query neighbor_query (points, point_map);
std::vector<Point> kd_tree_points;
for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++)
kd_tree_points.push_back(get(point_map, *it));
Tree tree(kd_tree_points.begin(), kd_tree_points.end());
// 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; std::size_t nb = 0;
std::size_t nb_points = std::distance(points.begin(), points.end());
#ifndef CGAL_LINKED_WITH_TBB Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value), callback_wrapper (callback, nb_points);
"Parallel_tag is enabled but TBB is unavailable.");
#else std::vector<FT> spacings (nb_points, -1);
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
typedef boost::zip_iterator<boost::tuple<iterator, typename std::vector<FT>::iterator> > Zip_iterator;
CGAL::for_each<ConcurrencyTag>
(CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (points.begin(), spacings.begin())),
boost::make_zip_iterator (boost::make_tuple (points.end(), spacings.end()))),
[&](const typename Zip_iterator::reference& t)
{ {
Point_set_processing_3::internal::Parallel_callback if (callback_wrapper.interrupted())
parallel_callback (callback, kd_tree_points.size()); return false;
std::vector<FT> spacings (kd_tree_points.size (), -1); get<1>(t) = CGAL::internal::compute_average_spacing<Neighbor_query>
CGAL::internal::Compute_average_spacings<Kernel, Tree> (get(point_map, get<0>(t)), neighbor_query, k);
f (tree, k, kd_tree_points, spacings, ++ callback_wrapper.advancement();
parallel_callback.advancement(),
parallel_callback.interrupted()); return true;
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)
if (spacings[i] >= 0.) if (spacings[i] >= 0.)
@ -252,24 +207,7 @@ compute_average_spacing(
sum_spacings += spacings[i]; sum_spacings += spacings[i];
++ nb; ++ nb;
} }
callback_wrapper.join();
parallel_callback.join();
}
else
#endif
{
for(typename PointRange::const_iterator it = points.begin(); it != points.end(); it++, nb++)
{
sum_spacings += internal::compute_average_spacing<Kernel,Tree>(
get(point_map,*it),
tree,k);
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
{
++ nb;
break;
}
}
}
// return average spacing // return average spacing
return sum_spacings / (FT)(nb); return sum_spacings / (FT)(nb);

View File

@ -17,9 +17,9 @@
#include <CGAL/disable_warnings.h> #include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h> #include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.h> #include <CGAL/for_each.h>
#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>
@ -32,13 +32,6 @@
#include <iterator> #include <iterator>
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
namespace CGAL { namespace CGAL {
@ -58,18 +51,16 @@ namespace internal {
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return Computed normal. Orientation is random. /// @return Computed normal. Orientation is random.
template < typename Kernel, template <typename SvdTraits, typename NeighborQuery>
typename SvdTraits, typename NeighborQuery::Kernel::Vector_3
typename Tree jet_estimate_normal(const typename NeighborQuery::Point_3& query, ///< point to compute the normal at
> const NeighborQuery& neighbor_query, ///< KD-tree
typename Kernel::Vector_3
jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute the normal at
Tree& tree, ///< KD-tree
unsigned int k, ///< number of neighbors unsigned int k, ///< number of neighbors
typename Kernel::FT neighbor_radius, typename NeighborQuery::FT neighbor_radius,
unsigned int degree_fitting) unsigned int degree_fitting)
{ {
// basic geometric types // basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
// types for jet fitting // types for jet fitting
@ -79,8 +70,7 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
typedef typename Monge_jet_fitting::Monge_form Monge_form; typedef typename Monge_jet_fitting::Monge_form Monge_form;
std::vector<Point> points; std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
(query, tree, k, neighbor_radius, points);
// performs jet fitting // performs jet fitting
Monge_jet_fitting monge_fit; Monge_jet_fitting monge_fit;
@ -92,49 +82,6 @@ jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
return monge_form.normal_direction(); return monge_form.normal_direction();
} }
#ifdef CGAL_LINKED_WITH_TBB
template <typename Kernel, typename SvdTraits, typename Tree>
class Jet_estimate_normals {
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
const Tree& tree;
const unsigned int k;
const FT neighbor_radius;
const unsigned int degree_fitting;
const std::vector<Point>& input;
std::vector<Vector>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Jet_estimate_normals(Tree& tree, unsigned int k, FT neighbor_radius,
std::vector<Point>& points,
unsigned int degree_fitting, std::vector<Vector>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), neighbor_radius (neighbor_radius)
, degree_fitting (degree_fitting), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ }
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
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, neighbor_radius, degree_fitting);
++ advancement;
}
}
};
#endif // CGAL_LINKED_WITH_TBB
} /* namespace internal */ } /* namespace internal */
/// \endcond /// \endcond
@ -202,6 +149,8 @@ jet_estimate_normals(
CGAL_TRACE("Calls jet_estimate_normals()\n"); CGAL_TRACE("Calls jet_estimate_normals()\n");
// basic geometric types // basic geometric types
typedef typename PointRange::iterator iterator;
typedef typename iterator::value_type value_type;
typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap; typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap;
typedef typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap; typedef typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap;
typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel; typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel;
@ -223,15 +172,8 @@ jet_estimate_normals(
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback), const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>()); std::function<bool(double)>());
typedef typename Kernel::Point_3 Point;
// Input points types
typedef typename boost::property_traits<NormalMap>::value_type Vector;
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// precondition: at least one element in the container. // precondition: at least one element in the container.
// to fix: should have at least three distinct points // to fix: should have at least three distinct points
@ -244,60 +186,32 @@ jet_estimate_normals(
std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Creates KD-tree\n"); CGAL_TRACE(" Creates KD-tree\n");
typename PointRange::iterator it; Neighbor_query neighbor_query (points, point_map);
// Instanciate a KD-tree search.
// Note: We have to convert each input iterator to Point_3.
std::vector<Point> kd_tree_points;
for(it = points.begin(); it != points.end(); it++)
kd_tree_points.push_back(get(point_map, *it));
Tree tree(kd_tree_points.begin(), kd_tree_points.end());
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Computes normals\n"); CGAL_TRACE(" Computes normals\n");
// iterate over input points, compute and output normal std::size_t nb_points = points.size();
// vectors (already normalized)
#ifndef CGAL_LINKED_WITH_TBB Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value), callback_wrapper (callback, nb_points);
"Parallel_tag is enabled but TBB is unavailable.");
#else CGAL::for_each<ConcurrencyTag>
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value) (points,
[&](value_type& vt)
{ {
Point_set_processing_3::internal::Parallel_callback if (callback_wrapper.interrupted())
parallel_callback (callback, kd_tree_points.size()); return false;
std::vector<Vector> normals (kd_tree_points.size (), put (normal_map, vt,
CGAL::NULL_VECTOR); CGAL::internal::jet_estimate_normal<SvdTraits>
CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree> (get(point_map, vt), neighbor_query, k, neighbor_radius, degree_fitting));
f (tree, k, neighbor_radius, ++ callback_wrapper.advancement();
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);
std::size_t i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i)
if (normals[i] != CGAL::NULL_VECTOR)
put (normal_map, *it, normals[i]);
parallel_callback.join(); return true;
} });
else
#endif
{
std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{
Vector normal = internal::jet_estimate_normal<Kernel,SvdTraits,Tree>(
get(point_map,*it),
tree, k, neighbor_radius, degree_fitting);
put(normal_map, *it, normal); // normal_map[it] = normal
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
}
}
callback_wrapper.join();
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE("End of jet_estimate_normals()\n"); CGAL_TRACE("End of jet_estimate_normals()\n");

View File

@ -17,9 +17,9 @@
#include <CGAL/disable_warnings.h> #include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h> #include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.h> #include <CGAL/for_each.h>
#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>
@ -31,13 +31,6 @@
#include <iterator> #include <iterator>
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
namespace CGAL { namespace CGAL {
@ -57,20 +50,20 @@ namespace internal {
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return computed point /// @return computed point
template <typename Kernel, template <typename SvdTraits,
typename SvdTraits, typename NeighborQuery
typename Tree
> >
typename Kernel::Point_3 typename NeighborQuery::Kernel::Point_3
jet_smooth_point( jet_smooth_point(
const typename Kernel::Point_3& query, ///< 3D point to project const typename NeighborQuery::Kernel::Point_3& query, ///< 3D point to project
Tree& tree, ///< KD-tree NeighborQuery& neighbor_query, ///< KD-tree
const unsigned int k, ///< number of neighbors. const unsigned int k, ///< number of neighbors.
typename Kernel::FT neighbor_radius, typename NeighborQuery::Kernel::FT neighbor_radius,
const unsigned int degree_fitting, const unsigned int degree_fitting,
const unsigned int degree_monge) const unsigned int degree_monge)
{ {
// basic geometric types // basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
// types for jet fitting // types for jet fitting
@ -80,8 +73,7 @@ jet_smooth_point(
typedef typename Monge_jet_fitting::Monge_form Monge_form; typedef typename Monge_jet_fitting::Monge_form Monge_form;
std::vector<Point> points; std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
(query, tree, k, neighbor_radius, points);
// performs jet fitting // performs jet fitting
Monge_jet_fitting monge_fit; Monge_jet_fitting monge_fit;
@ -92,50 +84,6 @@ jet_smooth_point(
return monge_form.origin(); return monge_form.origin();
} }
#ifdef CGAL_LINKED_WITH_TBB
template <typename Kernel, typename SvdTraits, typename Tree>
class Jet_smooth_pwns {
typedef typename Kernel::Point_3 Point;
const Tree& tree;
const unsigned int k;
const typename Kernel::FT neighbor_radius;
unsigned int degree_fitting;
unsigned int degree_monge;
const std::vector<Point>& input;
std::vector<Point>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Jet_smooth_pwns (Tree& tree, unsigned int k, typename Kernel::FT neighbor_radius,
std::vector<Point>& points,
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), neighbor_radius(neighbor_radius)
, degree_fitting (degree_fitting)
, degree_monge (degree_monge), input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ }
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
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,
neighbor_radius,
degree_fitting,
degree_monge);
++ advancement;
}
}
};
#endif // CGAL_LINKED_WITH_TBB
} /* namespace internal */ } /* namespace internal */
@ -204,6 +152,8 @@ jet_smooth_point_set(
using parameters::get_parameter; using parameters::get_parameter;
// basic geometric types // basic geometric types
typedef typename PointRange::iterator iterator;
typedef typename iterator::value_type value_type;
typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap; typedef typename CGAL::GetPointMap<PointRange, NamedParameters>::type PointMap;
typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel; typedef typename Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel;
typedef typename GetSvdTraits<NamedParameters>::type SvdTraits; typedef typename GetSvdTraits<NamedParameters>::type SvdTraits;
@ -220,12 +170,8 @@ jet_smooth_point_set(
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback), const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>()); std::function<bool(double)>());
typedef typename Kernel::Point_3 Point;
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// precondition: at least one element in the container. // precondition: at least one element in the container.
// to fix: should have at least three distinct points // to fix: should have at least three distinct points
@ -235,56 +181,37 @@ jet_smooth_point_set(
// precondition: at least 2 nearest neighbors // precondition: at least 2 nearest neighbors
CGAL_point_set_processing_precondition(k >= 2); CGAL_point_set_processing_precondition(k >= 2);
typename PointRange::iterator it;
// Instanciate a KD-tree search. // Instanciate a KD-tree search.
// Note: We have to convert each input iterator to Point_3. Neighbor_query neighbor_query (points, point_map);
std::vector<Point> kd_tree_points;
for(it = points.begin(); it != points.end(); it++)
kd_tree_points.push_back(get(point_map, *it));
Tree tree(kd_tree_points.begin(), kd_tree_points.end());
// Iterates over input points and mutates them. // Iterates over input points and mutates them.
// Implementation note: the cast to Point& allows to modify only the point's position. // Implementation note: the cast to Point& allows to modify only the point's position.
#ifndef CGAL_LINKED_WITH_TBB std::size_t nb_points = points.size();
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable.");
#else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{
Point_set_processing_3::internal::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<Point> mutated_points (kd_tree_points.size (), CGAL::ORIGIN); Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree> callback_wrapper (callback, nb_points);
f (tree, k, neighbor_radius, kd_tree_points, degree_fitting, degree_monge,
mutated_points,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
unsigned int i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i)
if (mutated_points[i] != CGAL::ORIGIN)
put(point_map, *it, mutated_points[i]);
parallel_callback.join(); CGAL::for_each<ConcurrencyTag>
(points,
[&](value_type vt)
{
if (callback_wrapper.interrupted())
return false;
} put (point_map, vt,
else CGAL::internal::jet_smooth_point<SvdTraits>
#endif (get (point_map, vt), neighbor_query,
{ k,
std::size_t nb = 0; neighbor_radius,
for(it = points.begin(); it != points.end(); it++, ++ nb) degree_fitting,
{ degree_monge));
const typename boost::property_traits<PointMap>::reference p = get(point_map, *it); ++ callback_wrapper.advancement();
put(point_map, *it ,
internal::jet_smooth_point<Kernel, SvdTraits>( return true;
p,tree,k,neighbor_radius,degree_fitting,degree_monge) ); });
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break; callback_wrapper.join();
}
}
} }

View File

@ -17,10 +17,7 @@
#include <CGAL/disable_warnings.h> #include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h> #include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.h>
#include <CGAL/Point_set_processing_3/internal/Search_traits_vertex_handle_3.h>
#include <CGAL/property_map.h> #include <CGAL/property_map.h>
#include <CGAL/Index_property_map.h> #include <CGAL/Index_property_map.h>
#include <CGAL/Memory_sizer.h> #include <CGAL/Memory_sizer.h>
@ -296,17 +293,16 @@ mst_find_source(
/// @tparam Kernel Geometric traits class. /// @tparam Kernel Geometric traits class.
/// ///
/// @return the Riemannian graph /// @return the Riemannian graph
template <typename ForwardIterator, template <typename PointRange,
typename PointMap, typename PointMap,
typename NormalMap, typename NormalMap,
typename IndexMap, typename IndexMap,
typename ConstrainedMap, typename ConstrainedMap,
typename Kernel typename Kernel
> >
Riemannian_graph<ForwardIterator> Riemannian_graph<typename PointRange::iterator>
create_riemannian_graph( create_riemannian_graph(
ForwardIterator first, ///< iterator over the first input point. PointRange& points, ///< input points
ForwardIterator beyond, ///< past-the-end iterator over the input points.
PointMap point_map, ///< property map: value_type of ForwardIterator -> Point_3 PointMap point_map, ///< property map: value_type of ForwardIterator -> Point_3
NormalMap normal_map, ///< property map: value_type of ForwardIterator -> Vector_3 NormalMap normal_map, ///< property map: value_type of ForwardIterator -> Vector_3
IndexMap index_map, ///< property map ForwardIterator -> index IndexMap index_map, ///< property map ForwardIterator -> index
@ -320,43 +316,23 @@ create_riemannian_graph(
typedef typename boost::property_traits<NormalMap>::reference Vector_ref; typedef typename boost::property_traits<NormalMap>::reference Vector_ref;
// Types for K nearest neighbors search structure // Types for K nearest neighbors search structure
typedef Point_vertex_handle_3<ForwardIterator> Point_vertex_handle_3; typedef typename PointRange::iterator ForwardIterator;
typedef internal::Search_traits_vertex_handle_3<ForwardIterator> Traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
typedef Euclidean_distance_vertex_handle_3<ForwardIterator> KDistance;
typedef Orthogonal_k_neighbor_search<Traits,KDistance> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// Riemannian_graph types // Riemannian_graph types
typedef internal::Riemannian_graph<ForwardIterator> Riemannian_graph; typedef internal::Riemannian_graph<ForwardIterator> Riemannian_graph;
typedef typename boost::property_map<Riemannian_graph, boost::edge_weight_t>::type Riemannian_graph_weight_map; typedef typename boost::property_map<Riemannian_graph, boost::edge_weight_t>::type Riemannian_graph_weight_map;
// Precondition: at least one element in the container.
CGAL_point_set_processing_precondition(first != beyond);
// Precondition: at least 2 nearest neighbors // Precondition: at least 2 nearest neighbors
CGAL_point_set_processing_precondition(k >= 2); CGAL_point_set_processing_precondition(k >= 2);
// Number of input points // Number of input points
const std::size_t num_input_points = distance(first, beyond); const std::size_t num_input_points = points.size();
std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Creates KD-tree\n"); CGAL_TRACE(" Creates KD-tree\n");
// Instanciate a KD-tree search. Neighbor_query neighbor_query (points, point_map);
// Notes: We have to wrap each input point by a Point_vertex_handle_3.
// The KD-tree is allocated dynamically to recover RAM as soon as possible.
std::vector<Point_vertex_handle_3> kd_tree_points; kd_tree_points.reserve(num_input_points);
for (ForwardIterator it = first; it != beyond; it++)
{
Point_ref point = get(point_map, *it);
Point_vertex_handle_3 point_wrapper(point.x(), point.y(), point.z(), it);
kd_tree_points.push_back(point_wrapper);
}
boost::shared_ptr<Tree> tree( new Tree(kd_tree_points.begin(), kd_tree_points.end()) );
// Recover RAM
kd_tree_points.clear();
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Creates Riemannian Graph\n"); CGAL_TRACE(" Creates Riemannian Graph\n");
@ -369,7 +345,7 @@ create_riemannian_graph(
Riemannian_graph riemannian_graph; Riemannian_graph riemannian_graph;
// //
// add vertices // add vertices
for (ForwardIterator it = first; it != beyond; it++) for (ForwardIterator it = points.begin(); it != points.end(); it++)
{ {
typename Riemannian_graph::vertex_descriptor v = add_vertex(riemannian_graph); typename Riemannian_graph::vertex_descriptor v = add_vertex(riemannian_graph);
CGAL_point_set_processing_assertion(v == get(index_map,it)); CGAL_point_set_processing_assertion(v == get(index_map,it));
@ -383,16 +359,14 @@ create_riemannian_graph(
// //
// add edges // add edges
Riemannian_graph_weight_map riemannian_graph_weight_map = get(boost::edge_weight, riemannian_graph); Riemannian_graph_weight_map riemannian_graph_weight_map = get(boost::edge_weight, riemannian_graph);
for (ForwardIterator it = first; it != beyond; it++) for (ForwardIterator it = points.begin(); it != points.end(); it++)
{ {
std::size_t it_index = get(index_map,it); std::size_t it_index = get(index_map,it);
Vector_ref it_normal_vector = get(normal_map,*it); Vector_ref it_normal_vector = get(normal_map,*it);
Point_ref point = get(point_map, *it); Point_ref point = get(point_map, *it);
Point_vertex_handle_3 point_wrapper(point.x(), point.y(), point.z(), it); std::vector<ForwardIterator> neighbor_points;
std::vector<Point_vertex_handle_3> neighbor_points; neighbor_query.get_iterators (point, k, neighbor_radius, std::back_inserter(neighbor_points));
CGAL::Point_set_processing_3::internal::neighbor_query
(point_wrapper, *tree, k, neighbor_radius, neighbor_points);
for (std::size_t i = 0; i < neighbor_points.size(); ++ i) for (std::size_t i = 0; i < neighbor_points.size(); ++ i)
{ {
@ -665,7 +639,7 @@ mst_orient_normals(
if (boost::is_same<ConstrainedMap, if (boost::is_same<ConstrainedMap,
typename CGAL::Point_set_processing_3::GetIsConstrainedMap<PointRange, NamedParameters>::NoMap>::value) typename CGAL::Point_set_processing_3::GetIsConstrainedMap<PointRange, NamedParameters>::NoMap>::value)
riemannian_graph = create_riemannian_graph(points.begin(), points.end(), riemannian_graph = create_riemannian_graph(points,
point_map, normal_map, index_map, point_map, normal_map, index_map,
Default_constrained_map<typename PointRange::iterator> Default_constrained_map<typename PointRange::iterator>
(mst_find_source(points.begin(), points.end(), (mst_find_source(points.begin(), points.end(),
@ -675,7 +649,7 @@ mst_orient_normals(
neighbor_radius, neighbor_radius,
kernel); kernel);
else else
riemannian_graph = create_riemannian_graph(points.begin(), points.end(), riemannian_graph = create_riemannian_graph(points,
point_map, normal_map, index_map, point_map, normal_map, index_map,
constrained_map, constrained_map,
k, k,

View File

@ -18,9 +18,9 @@
#include <CGAL/IO/trace.h> #include <CGAL/IO/trace.h>
#include <CGAL/Dimension.h> #include <CGAL/Dimension.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h> #include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.h> #include <CGAL/for_each.h>
#include <CGAL/linear_least_squares_fitting_3.h> #include <CGAL/linear_least_squares_fitting_3.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>
@ -33,13 +33,6 @@
#include <iterator> #include <iterator>
#include <list> #include <list>
#ifdef CGAL_LINKED_WITH_TBB
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
namespace CGAL { namespace CGAL {
@ -58,22 +51,20 @@ namespace internal {
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return Computed normal. Orientation is random. /// @return Computed normal. Orientation is random.
template < typename Kernel, template <typename NeighborQuery>
typename Tree typename NeighborQuery::Kernel::Vector_3
> pca_estimate_normal(const typename NeighborQuery::Kernel::Point_3& query, ///< point to compute the normal at
typename Kernel::Vector_3 const NeighborQuery& neighbor_query, ///< KD-tree
pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute the normal at
const Tree& tree, ///< KD-tree
unsigned int k, ///< number of neighbors unsigned int k, ///< number of neighbors
typename Kernel::FT neighbor_radius) typename NeighborQuery::Kernel::FT neighbor_radius)
{ {
// basic geometric types // basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Plane_3 Plane; typedef typename Kernel::Plane_3 Plane;
std::vector<Point> points; std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
(query, tree, k, neighbor_radius, points);
// performs plane fitting by point-based PCA // performs plane fitting by point-based PCA
Plane plane; Plane plane;
@ -83,48 +74,6 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
return plane.orthogonal_vector(); return plane.orthogonal_vector();
} }
#ifdef CGAL_LINKED_WITH_TBB
template <typename Kernel, typename Tree>
class PCA_estimate_normals {
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
const Tree& tree;
const unsigned int k;
const FT neighbor_radius;
const std::vector<Point>& input;
std::vector<Vector>& output;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
PCA_estimate_normals(Tree& tree, unsigned int k, FT neighbor_radius,
std::vector<Point>& points,
std::vector<Vector>& output,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted)
: tree(tree), k (k), neighbor_radius (neighbor_radius)
, input (points), output (output)
, advancement (advancement)
, interrupted (interrupted)
{ }
void operator()(const tbb::blocked_range<std::size_t>& r) const
{
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, neighbor_radius);
++ advancement;
}
}
};
#endif // CGAL_LINKED_WITH_TBB
} /* namespace internal */ } /* namespace internal */
/// \endcond /// \endcond
@ -206,15 +155,12 @@ pca_estimate_normals(
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback), const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>()); std::function<bool(double)>());
typedef typename Kernel::Point_3 Point;
// Input points types // Input points types
typedef typename boost::property_traits<NormalMap>::value_type Vector; typedef typename PointRange::iterator iterator;
typedef typename iterator::value_type value_type;
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// precondition: at least one element in the container. // precondition: at least one element in the container.
// to fix: should have at least three distinct points // to fix: should have at least three distinct points
@ -227,59 +173,33 @@ pca_estimate_normals(
std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); std::size_t memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Creates KD-tree\n"); CGAL_TRACE(" Creates KD-tree\n");
typename PointRange::iterator it; Neighbor_query neighbor_query (points, point_map);
// Instanciate a KD-tree search.
// Note: We have to convert each input iterator to Point_3.
std::vector<Point> kd_tree_points;
for(it = points.begin(); it != points.end(); it++)
kd_tree_points.push_back(get(point_map, *it));
Tree tree(kd_tree_points.begin(), kd_tree_points.end());
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Computes normals\n"); CGAL_TRACE(" Computes normals\n");
// iterate over input points, compute and output normal std::size_t nb_points = points.size();
// vectors (already normalized)
#ifndef CGAL_LINKED_WITH_TBB
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable.");
#else
if (boost::is_convertible<ConcurrencyTag,Parallel_tag>::value)
{
Point_set_processing_3::internal::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
std::vector<Vector> normals (kd_tree_points.size (), Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
CGAL::NULL_VECTOR); callback_wrapper (callback, nb_points);
CGAL::internal::PCA_estimate_normals<Kernel, Tree>
f (tree, k, neighbor_radius, kd_tree_points, normals,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
unsigned int i = 0;
for(it = points.begin(); it != points.end(); ++ it, ++ i)
if (normals[i] != CGAL::NULL_VECTOR)
put (normal_map, *it, normals[i]);
parallel_callback.join(); CGAL::for_each<ConcurrencyTag>
} (points,
else [&](value_type& vt)
#endif
{ {
std::size_t nb = 0; if (callback_wrapper.interrupted())
for(it = points.begin(); it != points.end(); it++, ++ nb) return false;
{
Vector normal = internal::pca_estimate_normal<Kernel,Tree>(
get(point_map,*it),
tree,
k, neighbor_radius);
put(normal_map, *it, normal); // normal_map[it] = normal put (normal_map, vt,
if (callback && !callback ((nb+1) / double(kd_tree_points.size()))) CGAL::internal::pca_estimate_normal
break; (get(point_map, vt), neighbor_query, k, neighbor_radius));
}
} ++ callback_wrapper.advancement();
return true;
});
callback_wrapper.join();
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20); memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE("End of pca_estimate_normals()\n"); CGAL_TRACE("End of pca_estimate_normals()\n");

View File

@ -16,9 +16,7 @@
#include <CGAL/disable_warnings.h> #include <CGAL/disable_warnings.h>
#include <CGAL/Search_traits_3.h> #include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Point_set_processing_3/internal/neighbor_query.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 <functional> #include <functional>
@ -49,22 +47,21 @@ namespace internal {
/// @tparam Tree KD-tree. /// @tparam Tree KD-tree.
/// ///
/// @return computed distance. /// @return computed distance.
template < typename Kernel, template <typename NeighborQuery>
typename Tree > typename NeighborQuery::Kernel::FT
typename Kernel::FT
compute_avg_knn_sq_distance_3( compute_avg_knn_sq_distance_3(
const typename Kernel::Point_3& query, ///< 3D point to project const typename NeighborQuery::Kernel::Point_3& query, ///< 3D point to project
Tree& tree, ///< KD-tree NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k, ///< number of neighbors unsigned int k, ///< number of neighbors
typename Kernel::FT neighbor_radius) typename NeighborQuery::Kernel::FT neighbor_radius)
{ {
// geometric types // geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
typedef typename Kernel::Point_3 Point; typedef typename Kernel::Point_3 Point;
std::vector<Point> points; std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
(query, tree, k, neighbor_radius, points);
// compute average squared distance // compute average squared distance
typename Kernel::Compute_squared_distance_3 sqd; typename Kernel::Compute_squared_distance_3 sqd;
@ -162,15 +159,14 @@ remove_outliers(
typedef typename Kernel::FT FT; typedef typename Kernel::FT FT;
// basic geometric types // basic geometric types
typedef typename Kernel::Point_3 Point; typedef typename PointRange::iterator iterator;
typedef typename iterator::value_type value_type;
// 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;
// types for K nearest neighbors search structure // types for K nearest neighbors search structure
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits; typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
// precondition: at least one element in the container. // precondition: at least one element in the container.
// to fix: should have at least three distinct points // to fix: should have at least three distinct points
@ -182,26 +178,22 @@ remove_outliers(
CGAL_point_set_processing_precondition(threshold_percent >= 0 && threshold_percent <= 100); CGAL_point_set_processing_precondition(threshold_percent >= 0 && threshold_percent <= 100);
typename PointRange::iterator it; Neighbor_query neighbor_query (points, point_map);
// Instanciate a KD-tree search. std::size_t nb_points = points.size();
// Note: We have to convert each input iterator to Point_3.
std::vector<Point> kd_tree_points;
for(it = points.begin(); it != points.end(); it++)
kd_tree_points.push_back( get(point_map, *it) );
Tree tree(kd_tree_points.begin(), kd_tree_points.end());
// 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;
std::size_t nb = 0; std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb) for(const value_type& vt : points)
{ {
FT sq_distance = internal::compute_avg_knn_sq_distance_3<Kernel>( FT sq_distance = internal::compute_avg_knn_sq_distance_3(
get(point_map,*it), get(point_map, vt),
tree, k, neighbor_radius); neighbor_query, k, neighbor_radius);
sorted_points.insert( std::make_pair(sq_distance, *it) ); sorted_points.insert( std::make_pair(sq_distance, vt) );
if (callback && !callback ((nb+1) / double(kd_tree_points.size()))) if (callback && !callback ((nb+1) / double(nb_points)))
return points.end(); return points.end();
++ nb;
} }
// Replaces [points.begin(), points.end()) range by the multimap content. // Replaces [points.begin(), points.end()) range by the multimap content.

View File

@ -32,12 +32,8 @@
#include <cmath> #include <cmath>
#include <ctime> #include <ctime>
#ifdef CGAL_LINKED_WITH_TBB #include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/Point_set_processing_3/internal/Parallel_callback.h> #include <CGAL/for_each.h>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
#include <CGAL/Simple_cartesian.h> #include <CGAL/Simple_cartesian.h>
#include <CGAL/Fuzzy_sphere.h> #include <CGAL/Fuzzy_sphere.h>
@ -329,67 +325,6 @@ compute_density_weight_for_sample_point(
/// \endcond /// \endcond
#ifdef CGAL_LINKED_WITH_TBB
/// \cond SKIP_IN_MANUAL
/// This is for parallelization of function: compute_denoise_projection()
template <typename Kernel, typename Tree, typename RandomAccessIterator>
class Sample_point_updater
{
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::FT FT;
std::vector<Point> &update_sample_points;
std::vector<Point> &sample_points;
const Tree &original_kd_tree;
const Tree &sample_kd_tree;
const typename Kernel::FT radius;
const std::vector<typename Kernel::FT> &original_densities;
const std::vector<typename Kernel::FT> &sample_densities;
cpp11::atomic<std::size_t>& advancement;
cpp11::atomic<bool>& interrupted;
public:
Sample_point_updater(
std::vector<Point> &out,
std::vector<Point> &in,
const Tree &_original_kd_tree,
const Tree &_sample_kd_tree,
const typename Kernel::FT _radius,
const std::vector<typename Kernel::FT> &_original_densities,
const std::vector<typename Kernel::FT> &_sample_densities,
cpp11::atomic<std::size_t>& advancement,
cpp11::atomic<bool>& interrupted):
update_sample_points(out),
sample_points(in),
original_kd_tree(_original_kd_tree),
sample_kd_tree(_sample_kd_tree),
radius(_radius),
original_densities(_original_densities),
sample_densities(_sample_densities),
advancement (advancement),
interrupted (interrupted) {}
void operator() ( const tbb::blocked_range<size_t>& r ) const
{
for (size_t i = r.begin(); i != r.end(); ++i)
{
if (interrupted)
break;
update_sample_points[i] = simplify_and_regularize_internal::
compute_update_sample_point<Kernel, Tree, RandomAccessIterator>(
sample_points[i],
original_kd_tree,
sample_kd_tree,
radius,
original_densities,
sample_densities);
++ advancement;
}
}
};
/// \endcond
#endif // CGAL_LINKED_WITH_TBB
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Public section // Public section
@ -529,7 +464,6 @@ wlop_simplify_and_regularize_point_set(
#endif #endif
} }
FT radius2 = radius * radius;
CGAL_point_set_processing_precondition(radius > 0); CGAL_point_set_processing_precondition(radius > 0);
// Initiate a KD-tree search for original points // Initiate a KD-tree search for original points
@ -588,79 +522,50 @@ wlop_simplify_and_regularize_point_set(
sample_density_weights.push_back(density); sample_density_weights.push_back(density);
} }
typedef boost::zip_iterator<boost::tuple<typename std::vector<Point>::iterator,
typename std::vector<Point>::iterator> > Zip_iterator;
typename std::vector<Point>::iterator update_iter = update_sample_points.begin(); Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
#ifndef CGAL_LINKED_WITH_TBB callback_wrapper (callback, iter_number * number_of_sample, iter_n * number_of_sample);
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable."); CGAL::for_each<ConcurrencyTag>
#else (CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (sample_points.begin(), update_sample_points.begin())),
//parallel boost::make_zip_iterator (boost::make_tuple (sample_points.end(), update_sample_points.end()))),
if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value) [&](const typename Zip_iterator::reference& t)
{ {
Point_set_processing_3::internal::Parallel_callback if (callback_wrapper.interrupted())
parallel_callback (callback, iter_number * number_of_sample, iter_n * number_of_sample); return false;
tbb::blocked_range<size_t> block(0, number_of_sample); get<1>(t) = simplify_and_regularize_internal::
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater( compute_update_sample_point<Kernel, Kd_Tree, typename PointRange::iterator>(
update_sample_points, get<0>(t),
sample_points,
original_kd_tree, original_kd_tree,
sample_kd_tree, sample_kd_tree,
radius2, radius,
original_density_weights, original_density_weights,
sample_density_weights, sample_density_weights);
parallel_callback.advancement(), ++ callback_wrapper.advancement();
parallel_callback.interrupted());
tbb::parallel_for(block, sample_updater); return true;
});
bool interrupted = parallel_callback.interrupted(); bool interrupted = callback_wrapper.interrupted();
// We interrupt by hand as counter only goes halfway and won't terminate by itself // We interrupt by hand as counter only goes halfway and won't terminate by itself
parallel_callback.interrupted() = true; callback_wrapper.interrupted() = true;
parallel_callback.join(); callback_wrapper.join();
// If interrupted during this step, nothing is computed, we return NaN // If interrupted during this step, nothing is computed, we return NaN
if (interrupted) if (interrupted)
return output; return output;
}else
#endif
{
//sequential
std::size_t nb = iter_n * number_of_sample;
for (sample_iter = sample_points.begin();
sample_iter != sample_points.end(); ++sample_iter, ++update_iter, ++ nb)
{
*update_iter = simplify_and_regularize_internal::
compute_update_sample_point<Kernel,
Kd_Tree,
typename PointRange::iterator>
(*sample_iter,
original_kd_tree,
sample_kd_tree,
radius2,
original_density_weights,
sample_density_weights);
if (callback && !callback ((nb+1) / double(iter_number * number_of_sample)))
return output;
}
}
sample_iter = sample_points.begin(); sample_iter = sample_points.begin();
for (update_iter = update_sample_points.begin(); for (std::size_t i = 0; i < sample_points.size(); ++ i)
update_iter != update_sample_points.end(); sample_points[i] = update_sample_points[i];
++update_iter, ++sample_iter)
{
*sample_iter = *update_iter;
}
} }
// final output // final output
for(sample_iter = sample_points.begin(); std::copy (sample_points.begin(), sample_points.end(), output);
sample_iter != sample_points.end(); ++sample_iter)
{
*output++ = *sample_iter;
}
return output; return output;
} }

View File

@ -106,13 +106,13 @@ struct Poisson_visitor {
struct Poisson_skip_vertices { struct Poisson_skip_vertices {
double ratio; double ratio;
Random& m_random; Poisson_skip_vertices(const double ratio = 0)
Poisson_skip_vertices(const double ratio, Random& random) : ratio(ratio) {}
: ratio(ratio), m_random(random) {}
template <typename Iterator> template <typename Iterator>
bool operator()(Iterator) const { bool operator()(Iterator it) const {
return m_random.get_double() < ratio; // make the result deterministic for each iterator
return Random((std::size_t)(&*it)).get_double() < ratio;
} }
}; };
@ -417,9 +417,7 @@ public:
typedef Filter_iterator<typename Triangulation::Input_point_iterator, typedef Filter_iterator<typename Triangulation::Input_point_iterator,
Poisson_skip_vertices> Some_points_iterator; Poisson_skip_vertices> Some_points_iterator;
//make it deterministic Poisson_skip_vertices skip(1.-approximation_ratio);
Random random(0);
Poisson_skip_vertices skip(1.-approximation_ratio,random);
CGAL_TRACE_STREAM << "SPECIAL PASS that uses an approximation of the result (approximation ratio: " CGAL_TRACE_STREAM << "SPECIAL PASS that uses an approximation of the result (approximation ratio: "
<< approximation_ratio << ")" << std::endl; << approximation_ratio << ")" << std::endl;

View File

@ -216,6 +216,22 @@ struct Identity_property_map
/// @} /// @}
}; };
/// \cond SKIP_IN_MANUAL
template <typename T>
struct Identity_property_map_no_lvalue
{
typedef T key_type; ///< typedef to `T`
typedef T value_type; ///< typedef to `T`
typedef T reference; ///< typedef to `T`
typedef boost::readable_property_map_tag category; ///< `boost::readable_property_map_tag`
typedef Identity_property_map_no_lvalue<T> Self;
friend reference get(const Self&, const key_type& k) {return k;}
};
/// \endcond
/// Free function to create a `Identity_property_map` property map. /// Free function to create a `Identity_property_map` property map.
/// ///
/// \relates Identity_property_map /// \relates Identity_property_map

View File

@ -0,0 +1,136 @@
// Copyright (c) 2020 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Simon Giraudot
#ifndef CGAL_FOR_EACH_H
#define CGAL_FOR_EACH_H
#include <CGAL/iterator.h>
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/scalable_allocator.h>
#endif // CGAL_LINKED_WITH_TBB
/*
CGAL::for_each<ConcurrencyTag>(Range, Function) does the following:
- if Sequential_tag is used, apply Function to all elements of Range
- if Parallel_tag is used:
* static assert that TBB is available
* if Range has random access iterators, use a TBB parallel_for
loop to apply Function to all elements of Range
* if Range doesn't have random access iterators, first copy the
iterators in a vector and then use a TBB parallel_for loop to
apply Function to all elements of Range
The loop is interrupted if `functor` returns false (it carries on
until the end otherwise).
*/
namespace CGAL {
namespace internal {
template <typename RangeRef, typename IteratorCategory>
void for_each (RangeRef range,
const std::function<bool(typename std::iterator_traits
<typename Range_iterator_type<RangeRef>::type>::reference)>& functor,
const Sequential_tag&,
IteratorCategory)
{
for (typename std::iterator_traits
<typename Range_iterator_type<RangeRef>::type>::reference r : range)
if (!functor(r))
break;
}
#ifdef CGAL_LINKED_WITH_TBB
template <typename RangeRef, typename IteratorCategory>
void for_each (RangeRef range,
const std::function<bool(typename std::iterator_traits
<typename Range_iterator_type<RangeRef>::type>::reference)>& functor,
const Parallel_tag&,
IteratorCategory)
{
std::size_t range_size = std::distance (range.begin(), range.end());
std::vector<typename Range_iterator_type<RangeRef>::type> iterators;
iterators.reserve (range_size);
for (typename Range_iterator_type<RangeRef>::type it = range.begin(); it != range.end(); ++ it)
iterators.push_back (it);
tbb::parallel_for (tbb::blocked_range<std::size_t>(0, range_size),
[&](const tbb::blocked_range<std::size_t>& r)
{
for (std::size_t i = r.begin(); i != r.end(); ++ i)
if (!functor (*(iterators[i])))
break;
});
}
template <typename RangeRef>
void for_each (RangeRef range,
const std::function<bool(typename std::iterator_traits
<typename Range_iterator_type<RangeRef>::type>::reference)>& functor,
const Parallel_tag&,
std::random_access_iterator_tag)
{
std::size_t range_size = std::distance (range.begin(), range.end());
tbb::parallel_for (tbb::blocked_range<std::size_t>(0, range_size),
[&](const tbb::blocked_range<std::size_t>& r)
{
for (std::size_t i = r.begin(); i != r.end(); ++ i)
if (!functor (*(range.begin() + i)))
break;
});
}
#endif
} // namespace internal
template <typename ConcurrencyTag, typename Range>
void for_each (const Range& range,
const std::function<bool(typename std::iterator_traits
<typename Range::const_iterator>::reference)>& functor)
{
#ifndef CGAL_LINKED_WITH_TBB
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable.");
#endif
internal::for_each<const Range&>
(range, functor,
ConcurrencyTag(),
typename std::iterator_traits<typename Range::const_iterator>::iterator_category());
}
template <typename ConcurrencyTag, typename Range>
void for_each (Range& range,
const std::function<bool(typename std::iterator_traits
<typename Range::iterator>::reference)>& functor)
{
#ifndef CGAL_LINKED_WITH_TBB
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable.");
#endif
internal::for_each<Range&>
(range, functor,
ConcurrencyTag(),
typename std::iterator_traits<typename Range::iterator>::iterator_category());
}
} // namespace CGAL
#endif // CGAL_FOR_EACH_H

View File

@ -1471,6 +1471,17 @@ dispatch_or_drop_output(O... o)
return Dispatch_or_drop_output_iterator<std::tuple<V...>, std::tuple<O...> >(o...); return Dispatch_or_drop_output_iterator<std::tuple<V...>, std::tuple<O...> >(o...);
} }
// Trick to select iterator or const_iterator depending on the range constness
template <typename RangeRef>
struct Range_iterator_type;
template <typename RangeRef>
struct Range_iterator_type<RangeRef&> { typedef typename RangeRef::iterator type; };
template <typename RangeRef>
struct Range_iterator_type<const RangeRef&> { typedef typename RangeRef::const_iterator type; };
} //namespace CGAL } //namespace CGAL
#include <CGAL/enable_warnings.h> #include <CGAL/enable_warnings.h>

View File

@ -42,6 +42,10 @@ if ( CGAL_FOUND )
create_single_source_cgal_program( "test_Uncertain.cpp" ) create_single_source_cgal_program( "test_Uncertain.cpp" )
create_single_source_cgal_program( "test_vector.cpp" ) create_single_source_cgal_program( "test_vector.cpp" )
create_single_source_cgal_program( "test_join_iterators.cpp" ) create_single_source_cgal_program( "test_join_iterators.cpp" )
create_single_source_cgal_program( "test_for_each.cpp" )
if(TBB_FOUND)
CGAL_target_use_TBB(test_for_each)
endif()
else() else()
message(STATUS "This program requires the CGAL library, and will not be compiled.") message(STATUS "This program requires the CGAL library, and will not be compiled.")

View File

@ -0,0 +1,48 @@
#include <CGAL/for_each.h>
#include <vector>
#include <list>
int main()
{
std::vector<int> vec { 0, 1, 2, 3, 4, 5 };
std::list<int> list { 0, 1, 2, 3, 4, 5 };
std::cerr << "Testing sequential random access" << std::endl;
CGAL::for_each<CGAL::Sequential_tag>
(vec, [](int& i) -> bool { i *= 2; return true; });
for (const int& i : vec)
std::cerr << i << " ";
std::cerr << std::endl;
#ifdef CGAL_LINKED_WITH_TBB
std::cerr << "Testing parallel random access" << std::endl;
CGAL::for_each<CGAL::Parallel_tag>
(vec, [](int& i) -> bool { i *= 2; return true; });
for (const int& i : vec)
std::cerr << i << " ";
std::cerr << std::endl;
#endif
std::cerr << "Testing sequential non-random access" << std::endl;
CGAL::for_each<CGAL::Sequential_tag>
(list, [](int& i) -> bool { i *= 2; return true; });
for (const int& i : list)
std::cerr << i << " ";
std::cerr << std::endl;
#ifdef CGAL_LINKED_WITH_TBB
std::cerr << "Testing parallel non-random access" << std::endl;
CGAL::for_each<CGAL::Parallel_tag>
(list, [](int& i) -> bool { i *= 2; return true; });
for (const int& i : list)
std::cerr << i << " ";
std::cerr << std::endl;
#endif
return 0;
}

View File

@ -105,6 +105,7 @@ namespace CGAL {
} }
Kd_tree_rectangle() Kd_tree_rectangle()
: max_span_coord_(-1)
{} {}
@ -138,6 +139,7 @@ namespace CGAL {
template <class Construct_cartesian_const_iterator_d,class PointPointerIter> // was PointIter template <class Construct_cartesian_const_iterator_d,class PointPointerIter> // was PointIter
Kd_tree_rectangle(int, PointPointerIter begin, PointPointerIter end,const Construct_cartesian_const_iterator_d& construct_it) Kd_tree_rectangle(int, PointPointerIter begin, PointPointerIter end,const Construct_cartesian_const_iterator_d& construct_it)
: max_span_coord_(-1)
{ {
update_from_point_pointers<Construct_cartesian_const_iterator_d>(begin,end,construct_it); update_from_point_pointers<Construct_cartesian_const_iterator_d>(begin,end,construct_it);
} }
@ -288,7 +290,7 @@ namespace CGAL {
} }
Kd_tree_rectangle() Kd_tree_rectangle()
: coords_(0), dim(0) : coords_(0), dim(0), max_span_coord_(-1)
{ {
} }
@ -323,7 +325,7 @@ namespace CGAL {
template <class Construct_cartesian_const_iterator_d,class PointPointerIter> // was PointIter template <class Construct_cartesian_const_iterator_d,class PointPointerIter> // was PointIter
Kd_tree_rectangle(int d, PointPointerIter begin, PointPointerIter end,const Construct_cartesian_const_iterator_d& construct_it) Kd_tree_rectangle(int d, PointPointerIter begin, PointPointerIter end,const Construct_cartesian_const_iterator_d& construct_it)
: coords_(new FT[2*d]), dim(d) : coords_(new FT[2*d]), dim(d), max_span_coord_(-1)
{ {
update_from_point_pointers<Construct_cartesian_const_iterator_d>(begin,end,construct_it); update_from_point_pointers<Construct_cartesian_const_iterator_d>(begin,end,construct_it);
} }

View File

@ -182,7 +182,11 @@ public:
} }
Dereference_type& Dereference_type&
dereference() const { return const_cast<Dereference_type&>((*point)[idx]); } dereference() const
{
// Point::operator[] takes an int as parameter...
return const_cast<Dereference_type&>((*point)[static_cast<int>(idx)]);
}
}; };