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()),
boost::make_transform_iterator (m_samples.end(),
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;
}

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/number_type_config.h>
#include <CGAL/Search_traits_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/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/point_set_processing_assertions.h>
#include <CGAL/Point_with_normal_3.h>
#include <CGAL/squared_distance_3.h>
#include <functional>
#include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <boost/iterator/zip_iterator.hpp>
#include <iterator>
#include <set>
#include <algorithm>
@ -38,23 +39,6 @@
#include <CGAL/Memory_sizer.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
namespace CGAL {
@ -66,47 +50,6 @@ namespace CGAL {
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
/// according to their KNN neighborhood points
///
@ -117,12 +60,14 @@ public:
///
/// @return
template <typename Kernel>
CGAL::Point_with_normal_3<Kernel>
template <typename Kernel, typename PointRange,
typename PointMap, typename VectorMap>
std::pair<typename Kernel::Point_3, typename Kernel::Vector_3>
compute_denoise_projection(
const CGAL::Point_with_normal_3<Kernel>& query, ///< 3D point to project
const std::vector<CGAL::Point_with_normal_3<Kernel>,
CGAL_PSP3_DEFAULT_ALLOCATOR<CGAL::Point_with_normal_3<Kernel> > >& neighbor_pwns, //
const typename PointRange::iterator::value_type& vt,
PointMap point_map,
VectorMap normal_map,
const std::vector<typename PointRange::iterator>& neighbor_pwns,
typename Kernel::FT radius, ///< accept neighborhood radius
typename Kernel::FT sharpness_angle ///< control sharpness(0-90)
)
@ -133,7 +78,6 @@ compute_denoise_projection(
// basic geometric types
typedef typename Kernel::FT FT;
typedef CGAL::Point_with_normal_3<Kernel> Pwn;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::Point_3 Point;
@ -148,23 +92,21 @@ compute_denoise_projection(
FT cos_sigma = cos(sharpness_angle * CGAL_PI / 180.0);
FT sharpness_bandwidth = std::pow((CGAL::max)(1e-8, 1 - cos_sigma), 2);
typename std::vector<Pwn,CGAL_PSP3_DEFAULT_ALLOCATOR<Pwn> >::const_iterator
pwn_iter = neighbor_pwns.begin();
for (; pwn_iter != neighbor_pwns.end(); ++pwn_iter)
for (typename PointRange::iterator it : neighbor_pwns)
{
const Point& np = pwn_iter->position();
const Vector& nn = pwn_iter->normal();
const Point& np = get(point_map, *it);
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)
{
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);
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;
normal_sum = normal_sum + nn * weight;
}
@ -173,10 +115,10 @@ compute_denoise_projection(
Vector update_normal = normal_sum / project_weight_sum;
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);
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.
@ -187,41 +129,30 @@ compute_denoise_projection(
/// @tparam Tree KD-tree.
///
/// @return max spacing.
template < typename Kernel,
typename Tree >
typename Kernel::FT
template <typename NeighborQuery>
typename NeighborQuery::Kernel::FT
compute_max_spacing(
const CGAL::Point_with_normal_3<Kernel>& query, ///< 3D point
Tree& tree, ///< KD-tree
const typename NeighborQuery::value_type& vt,
typename NeighborQuery::Point_map point_map,
NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k) ///< number of neighbors
{
// basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
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
// output first). search may be aborted when k is greater
// 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;
unsigned int i;
for(i = 0; i < (k+1) ; ++i)
neighbor_query.get_iterators
(get(point_map, vt), k, (FT)(0.0),
boost::make_function_output_iterator
([&](const typename NeighborQuery::input_iterator& it)
{
if(search_iterator == search.end())
break; // premature ending
Pwn pwn = search_iterator->first;
double dist2 = CGAL::squared_distance(query.position(), pwn.position());
double dist2 = CGAL::squared_distance (get(point_map, vt), get(point_map, *it));
max_distance = (CGAL::max)(dist2, max_distance);
++search_iterator;
}
}));
// output max spacing
return std::sqrt(max_distance);
@ -231,102 +162,6 @@ compute_max_spacing(
/// \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
@ -400,16 +235,18 @@ bilateral_smooth_point_set(
using parameters::get_parameter;
// 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 Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap;
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,
typename Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::NoMap>::value),
"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;
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);
// types for K nearest neighbors search structure
typedef bilateral_smooth_point_set_internal::
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;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
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));
FT neighbor_radius = choose_parameter(get_parameter(np, internal_np::neighbor_radius), FT(0));
// copy points and normals
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();
std::size_t nb_points = points.size();
#ifdef CGAL_PSP3_VERBOSE
std::cout << "Initialization and compute max spacing: " << std::endl;
#endif
// initiate a KD-tree search for points
std::vector<Kd_tree_element,
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());
Neighbor_query neighbor_query (points, point_map);
// Guess spacing
#ifdef CGAL_PSP3_VERBOSE
CGAL::Real_timer task_timer;
@ -464,10 +278,10 @@ bilateral_smooth_point_set(
#endif
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::
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);
}
@ -486,49 +300,40 @@ bilateral_smooth_point_set(
task_timer.start();
#endif
// 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);
#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::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, 2 * nb_points);
typedef boost::zip_iterator<boost::tuple<iterator, typename std::vector<iterators>::iterator> > Zip_iterator;
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
parallel_callback (callback, 2 * nb_points);
if (callback_wrapper.interrupted())
return false;
Compute_pwns_neighbors<Kernel, Tree> f(k, neighbor_radius, tree, pwns, pwns_neighbors,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, nb_points), f);
neighbor_query.get_iterators (get(point_map, get<0>(t)), k, neighbor_radius,
std::back_inserter (get<1>(t)));
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
parallel_callback.interrupted() = true;
parallel_callback.join();
callback_wrapper.interrupted() = true;
callback_wrapper.join();
// If interrupted during this step, nothing is computed, we return NaN
if (interrupted)
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
task_timer.stop();
@ -541,53 +346,45 @@ bilateral_smooth_point_set(
task_timer.start();
#endif
// 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
if(boost::is_convertible<ConcurrencyTag, CGAL::Parallel_tag>::value)
callback_wrapper.reset (2 * nb_points, nb_points);
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
parallel_callback (callback, 2 * nb_points, nb_points);
if (callback_wrapper.interrupted())
return false;
//tbb::task_scheduler_init init(4);
tbb::blocked_range<size_t> block(0, nb_points);
Pwn_updater<Kernel> pwn_updater(sharpness_angle,
guess_neighbor_radius,
&pwns,
&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,
get<2>(t) = bilateral_smooth_point_set_internal::
compute_denoise_projection<Kernel, PointRange>
(get<0>(t),
point_map, normal_map,
get<1>(t),
guess_neighbor_radius,
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();
}
}
#ifdef CGAL_PSP3_VERBOSE
task_timer.stop();
memory = CGAL::Memory_sizer().virtual_size();
@ -596,13 +393,13 @@ bilateral_smooth_point_set(
#endif
// save results
FT sum_move_error = 0;
typename PointRange::iterator it = points.begin();
for(unsigned int i = 0 ; it != points.end(); ++it, ++i)
std::size_t nb = 0;
for (value_type& vt : points)
{
typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
sum_move_error += CGAL::squared_distance(p, update_pwns[i].position());
put (point_map, *it, update_pwns[i].position());
put (normal_map, *it, update_pwns[i].normal());
sum_move_error += CGAL::squared_distance(get(point_map, vt), update_pwns[nb].first);
put (point_map, vt, update_pwns[nb].first);
put (normal_map, vt, update_pwns[nb].second);
++ nb;
}
return sum_move_error / nb_points;

View File

@ -18,7 +18,9 @@
#include <CGAL/Search_traits_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/point_set_processing_assertions.h>
#include <CGAL/assertions.h>
@ -27,15 +29,12 @@
#include <CGAL/boost/graph/Named_function_parameters.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <boost/iterator/zip_iterator.hpp>
#include <iterator>
#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
#define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters
@ -60,81 +59,37 @@ namespace internal {
/// @tparam Tree KD-tree.
///
/// @return average spacing (scalar).
template < typename Kernel,
typename Tree >
typename Kernel::FT
compute_average_spacing(const typename Kernel::Point_3& query, ///< 3D point whose spacing we want to compute
const Tree& tree, ///< KD-tree
template <typename NeighborQuery>
typename NeighborQuery::Kernel::FT
compute_average_spacing(const typename NeighborQuery::Kernel::Point_3& query, ///< 3D point whose spacing we want to compute
const NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k) ///< number of neighbors
{
// basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::FT FT;
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
// output first). search may be aborted when k is greater
// than number of input points
Neighbor_search search(tree,query,k+1);
Search_iterator search_iterator = search.begin();
FT sum_distances = (FT)0.0;
unsigned int i;
for(i=0;i<(k+1);i++)
unsigned int i = 0;
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));
search_iterator++;
}
++ i;
}));
// output average spacing
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 */
/// \endcond
@ -195,20 +150,17 @@ compute_average_spacing(
using parameters::get_parameter;
// basic geometric types
typedef typename PointRange::const_iterator iterator;
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 Kernel::Point_3 Point;
PointMap point_map = choose_parameter<PointMap>(get_parameter(np, internal_np::point_map));
PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map), PointMap());
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>());
// types for K nearest neighbors search structure
typedef typename Kernel::FT FT;
typedef Search_traits_3<Kernel> Tree_traits;
typedef Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, const PointRange&, PointMap> Neighbor_query;
// precondition: at least one element in the container.
// to fix: should have at least three distinct points
@ -219,32 +171,35 @@ compute_average_spacing(
CGAL_point_set_processing_precondition(k >= 2);
// Instanciate a KD-tree search.
// Note: We have to convert each input iterator to Point_3.
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());
Neighbor_query neighbor_query (points, point_map);
// iterate over input points, compute and output normal
// vectors (already normalized)
FT sum_spacings = (FT)0.0;
std::size_t nb = 0;
std::size_t nb_points = std::distance(points.begin(), points.end());
#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::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, nb_points);
std::vector<FT> spacings (nb_points, -1);
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
parallel_callback (callback, kd_tree_points.size());
if (callback_wrapper.interrupted())
return false;
std::vector<FT> spacings (kd_tree_points.size (), -1);
CGAL::internal::Compute_average_spacings<Kernel, Tree>
f (tree, k, kd_tree_points, spacings,
parallel_callback.advancement(),
parallel_callback.interrupted());
tbb::parallel_for(tbb::blocked_range<size_t>(0, kd_tree_points.size ()), f);
get<1>(t) = CGAL::internal::compute_average_spacing<Neighbor_query>
(get(point_map, get<0>(t)), neighbor_query, k);
++ callback_wrapper.advancement();
return true;
});
for (unsigned int i = 0; i < spacings.size (); ++ i)
if (spacings[i] >= 0.)
@ -252,24 +207,7 @@ compute_average_spacing(
sum_spacings += spacings[i];
++ nb;
}
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;
}
}
}
callback_wrapper.join();
// return average spacing
return sum_spacings / (FT)(nb);

View File

@ -17,9 +17,9 @@
#include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_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/Neighbor_query.h>
#include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/for_each.h>
#include <CGAL/Monge_via_jet_fitting.h>
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
@ -32,13 +32,6 @@
#include <iterator>
#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 {
@ -58,18 +51,16 @@ namespace internal {
/// @tparam Tree KD-tree.
///
/// @return Computed normal. Orientation is random.
template < typename Kernel,
typename SvdTraits,
typename Tree
>
typename Kernel::Vector_3
jet_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute the normal at
Tree& tree, ///< KD-tree
template <typename SvdTraits, typename NeighborQuery>
typename NeighborQuery::Kernel::Vector_3
jet_estimate_normal(const typename NeighborQuery::Point_3& query, ///< point to compute the normal at
const NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k, ///< number of neighbors
typename Kernel::FT neighbor_radius,
typename NeighborQuery::FT neighbor_radius,
unsigned int degree_fitting)
{
// basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point;
// 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;
std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query
(query, tree, k, neighbor_radius, points);
neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
// performs jet fitting
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();
}
#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 */
/// \endcond
@ -202,6 +149,8 @@ jet_estimate_normals(
CGAL_TRACE("Calls jet_estimate_normals()\n");
// 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 Point_set_processing_3::GetNormalMap<PointRange, NamedParameters>::type NormalMap;
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),
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
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
// precondition: at least one element in the container.
// 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);
CGAL_TRACE(" Creates KD-tree\n");
typename PointRange::iterator it;
// 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());
Neighbor_query neighbor_query (points, point_map);
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Computes normals\n");
// iterate over input points, compute and output normal
// 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)
std::size_t nb_points = points.size();
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, nb_points);
CGAL::for_each<ConcurrencyTag>
(points,
[&](value_type& vt)
{
Point_set_processing_3::internal::Parallel_callback
parallel_callback (callback, kd_tree_points.size());
if (callback_wrapper.interrupted())
return false;
std::vector<Vector> normals (kd_tree_points.size (),
CGAL::NULL_VECTOR);
CGAL::internal::Jet_estimate_normals<Kernel, SvdTraits, Tree>
f (tree, k, neighbor_radius,
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]);
put (normal_map, vt,
CGAL::internal::jet_estimate_normal<SvdTraits>
(get(point_map, vt), neighbor_query, k, neighbor_radius, degree_fitting));
++ callback_wrapper.advancement();
parallel_callback.join();
}
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;
}
}
return true;
});
callback_wrapper.join();
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE("End of jet_estimate_normals()\n");

View File

@ -17,9 +17,9 @@
#include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_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/Neighbor_query.h>
#include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/for_each.h>
#include <CGAL/Monge_via_jet_fitting.h>
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
@ -31,13 +31,6 @@
#include <iterator>
#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 {
@ -57,20 +50,20 @@ namespace internal {
/// @tparam Tree KD-tree.
///
/// @return computed point
template <typename Kernel,
typename SvdTraits,
typename Tree
template <typename SvdTraits,
typename NeighborQuery
>
typename Kernel::Point_3
typename NeighborQuery::Kernel::Point_3
jet_smooth_point(
const typename Kernel::Point_3& query, ///< 3D point to project
Tree& tree, ///< KD-tree
const typename NeighborQuery::Kernel::Point_3& query, ///< 3D point to project
NeighborQuery& neighbor_query, ///< KD-tree
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_monge)
{
// basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point;
// types for jet fitting
@ -80,8 +73,7 @@ jet_smooth_point(
typedef typename Monge_jet_fitting::Monge_form Monge_form;
std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query
(query, tree, k, neighbor_radius, points);
neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
// performs jet fitting
Monge_jet_fitting monge_fit;
@ -92,50 +84,6 @@ jet_smooth_point(
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 */
@ -204,6 +152,8 @@ jet_smooth_point_set(
using parameters::get_parameter;
// 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 Point_set_processing_3::GetK<PointRange, NamedParameters>::Kernel Kernel;
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),
std::function<bool(double)>());
typedef typename Kernel::Point_3 Point;
// types for K nearest neighbors search structure
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
// precondition: at least one element in the container.
// to fix: should have at least three distinct points
@ -235,56 +181,37 @@ jet_smooth_point_set(
// precondition: at least 2 nearest neighbors
CGAL_point_set_processing_precondition(k >= 2);
typename PointRange::iterator it;
// 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());
Neighbor_query neighbor_query (points, point_map);
// Iterates over input points and mutates them.
// Implementation note: the cast to Point& allows to modify only the point's position.
#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::size_t nb_points = points.size();
std::vector<Point> mutated_points (kd_tree_points.size (), CGAL::ORIGIN);
CGAL::internal::Jet_smooth_pwns<Kernel, SvdTraits, Tree>
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]);
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, nb_points);
parallel_callback.join();
CGAL::for_each<ConcurrencyTag>
(points,
[&](value_type vt)
{
if (callback_wrapper.interrupted())
return false;
}
else
#endif
{
std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{
const typename boost::property_traits<PointMap>::reference p = get(point_map, *it);
put(point_map, *it ,
internal::jet_smooth_point<Kernel, SvdTraits>(
p,tree,k,neighbor_radius,degree_fitting,degree_monge) );
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
}
}
put (point_map, vt,
CGAL::internal::jet_smooth_point<SvdTraits>
(get (point_map, vt), neighbor_query,
k,
neighbor_radius,
degree_fitting,
degree_monge));
++ callback_wrapper.advancement();
return true;
});
callback_wrapper.join();
}

View File

@ -17,10 +17,7 @@
#include <CGAL/disable_warnings.h>
#include <CGAL/IO/trace.h>
#include <CGAL/Search_traits_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/Search_traits_vertex_handle_3.h>
#include <CGAL/Point_set_processing_3/internal/Neighbor_query.h>
#include <CGAL/property_map.h>
#include <CGAL/Index_property_map.h>
#include <CGAL/Memory_sizer.h>
@ -296,17 +293,16 @@ mst_find_source(
/// @tparam Kernel Geometric traits class.
///
/// @return the Riemannian graph
template <typename ForwardIterator,
template <typename PointRange,
typename PointMap,
typename NormalMap,
typename IndexMap,
typename ConstrainedMap,
typename Kernel
>
Riemannian_graph<ForwardIterator>
Riemannian_graph<typename PointRange::iterator>
create_riemannian_graph(
ForwardIterator first, ///< iterator over the first input point.
ForwardIterator beyond, ///< past-the-end iterator over the input points.
PointRange& points, ///< input points
PointMap point_map, ///< property map: value_type of ForwardIterator -> Point_3
NormalMap normal_map, ///< property map: value_type of ForwardIterator -> Vector_3
IndexMap index_map, ///< property map ForwardIterator -> index
@ -320,43 +316,23 @@ create_riemannian_graph(
typedef typename boost::property_traits<NormalMap>::reference Vector_ref;
// Types for K nearest neighbors search structure
typedef Point_vertex_handle_3<ForwardIterator> Point_vertex_handle_3;
typedef internal::Search_traits_vertex_handle_3<ForwardIterator> Traits;
typedef Euclidean_distance_vertex_handle_3<ForwardIterator> KDistance;
typedef Orthogonal_k_neighbor_search<Traits,KDistance> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
typedef typename PointRange::iterator ForwardIterator;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
// Riemannian_graph types
typedef internal::Riemannian_graph<ForwardIterator> Riemannian_graph;
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
CGAL_point_set_processing_precondition(k >= 2);
// 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);
CGAL_TRACE(" Creates KD-tree\n");
// Instanciate a KD-tree search.
// 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();
Neighbor_query neighbor_query (points, point_map);
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Creates Riemannian Graph\n");
@ -369,7 +345,7 @@ create_riemannian_graph(
Riemannian_graph riemannian_graph;
//
// 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);
CGAL_point_set_processing_assertion(v == get(index_map,it));
@ -383,16 +359,14 @@ create_riemannian_graph(
//
// add edges
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);
Vector_ref it_normal_vector = get(normal_map,*it);
Point_ref point = get(point_map, *it);
Point_vertex_handle_3 point_wrapper(point.x(), point.y(), point.z(), it);
std::vector<Point_vertex_handle_3> neighbor_points;
CGAL::Point_set_processing_3::internal::neighbor_query
(point_wrapper, *tree, k, neighbor_radius, neighbor_points);
std::vector<ForwardIterator> neighbor_points;
neighbor_query.get_iterators (point, k, neighbor_radius, std::back_inserter(neighbor_points));
for (std::size_t i = 0; i < neighbor_points.size(); ++ i)
{
@ -665,7 +639,7 @@ mst_orient_normals(
if (boost::is_same<ConstrainedMap,
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,
Default_constrained_map<typename PointRange::iterator>
(mst_find_source(points.begin(), points.end(),
@ -675,7 +649,7 @@ mst_orient_normals(
neighbor_radius,
kernel);
else
riemannian_graph = create_riemannian_graph(points.begin(), points.end(),
riemannian_graph = create_riemannian_graph(points,
point_map, normal_map, index_map,
constrained_map,
k,

View File

@ -18,9 +18,9 @@
#include <CGAL/IO/trace.h>
#include <CGAL/Dimension.h>
#include <CGAL/Search_traits_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/Neighbor_query.h>
#include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/for_each.h>
#include <CGAL/linear_least_squares_fitting_3.h>
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
@ -33,13 +33,6 @@
#include <iterator>
#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 {
@ -58,22 +51,20 @@ namespace internal {
/// @tparam Tree KD-tree.
///
/// @return Computed normal. Orientation is random.
template < typename Kernel,
typename Tree
>
typename Kernel::Vector_3
pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute the normal at
const Tree& tree, ///< KD-tree
template <typename NeighborQuery>
typename NeighborQuery::Kernel::Vector_3
pca_estimate_normal(const typename NeighborQuery::Kernel::Point_3& query, ///< point to compute the normal at
const NeighborQuery& neighbor_query, ///< KD-tree
unsigned int k, ///< number of neighbors
typename Kernel::FT neighbor_radius)
typename NeighborQuery::Kernel::FT neighbor_radius)
{
// basic geometric types
typedef typename NeighborQuery::Kernel Kernel;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Plane_3 Plane;
std::vector<Point> points;
CGAL::Point_set_processing_3::internal::neighbor_query
(query, tree, k, neighbor_radius, points);
neighbor_query.get_points (query, k, neighbor_radius, std::back_inserter(points));
// performs plane fitting by point-based PCA
Plane plane;
@ -83,48 +74,6 @@ pca_estimate_normal(const typename Kernel::Point_3& query, ///< point to compute
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 */
/// \endcond
@ -206,15 +155,12 @@ pca_estimate_normals(
const std::function<bool(double)>& callback = choose_parameter(get_parameter(np, internal_np::callback),
std::function<bool(double)>());
typedef typename Kernel::Point_3 Point;
// 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
typedef typename CGAL::Search_traits_3<Kernel> Tree_traits;
typedef typename CGAL::Orthogonal_k_neighbor_search<Tree_traits> Neighbor_search;
typedef typename Neighbor_search::Tree Tree;
typedef Point_set_processing_3::internal::Neighbor_query<Kernel, PointRange&, PointMap> Neighbor_query;
// precondition: at least one element in the container.
// 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);
CGAL_TRACE(" Creates KD-tree\n");
typename PointRange::iterator it;
// 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());
Neighbor_query neighbor_query (points, point_map);
memory = CGAL::Memory_sizer().virtual_size(); CGAL_TRACE(" %ld Mb allocated\n", memory>>20);
CGAL_TRACE(" Computes normals\n");
// iterate over input points, compute and output normal
// 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::size_t nb_points = points.size();
std::vector<Vector> normals (kd_tree_points.size (),
CGAL::NULL_VECTOR);
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]);
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, nb_points);
parallel_callback.join();
}
else
#endif
CGAL::for_each<ConcurrencyTag>
(points,
[&](value_type& vt)
{
std::size_t nb = 0;
for(it = points.begin(); it != points.end(); it++, ++ nb)
{
Vector normal = internal::pca_estimate_normal<Kernel,Tree>(
get(point_map,*it),
tree,
k, neighbor_radius);
if (callback_wrapper.interrupted())
return false;
put(normal_map, *it, normal); // normal_map[it] = normal
if (callback && !callback ((nb+1) / double(kd_tree_points.size())))
break;
}
}
put (normal_map, vt,
CGAL::internal::pca_estimate_normal
(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);
CGAL_TRACE("End of pca_estimate_normals()\n");

View File

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

View File

@ -32,12 +32,8 @@
#include <cmath>
#include <ctime>
#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
#include <CGAL/Point_set_processing_3/internal/Callback_wrapper.h>
#include <CGAL/for_each.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Fuzzy_sphere.h>
@ -329,67 +325,6 @@ compute_density_weight_for_sample_point(
/// \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
@ -529,7 +464,6 @@ wlop_simplify_and_regularize_point_set(
#endif
}
FT radius2 = radius * radius;
CGAL_point_set_processing_precondition(radius > 0);
// Initiate a KD-tree search for original points
@ -588,79 +522,50 @@ wlop_simplify_and_regularize_point_set(
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();
#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
//parallel
if (boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
callback_wrapper (callback, iter_number * number_of_sample, iter_n * number_of_sample);
CGAL::for_each<ConcurrencyTag>
(CGAL::make_range (boost::make_zip_iterator (boost::make_tuple (sample_points.begin(), update_sample_points.begin())),
boost::make_zip_iterator (boost::make_tuple (sample_points.end(), update_sample_points.end()))),
[&](const typename Zip_iterator::reference& t)
{
Point_set_processing_3::internal::Parallel_callback
parallel_callback (callback, iter_number * number_of_sample, iter_n * number_of_sample);
if (callback_wrapper.interrupted())
return false;
tbb::blocked_range<size_t> block(0, number_of_sample);
Sample_point_updater<Kernel, Kd_Tree, typename PointRange::iterator> sample_updater(
update_sample_points,
sample_points,
get<1>(t) = simplify_and_regularize_internal::
compute_update_sample_point<Kernel, Kd_Tree, typename PointRange::iterator>(
get<0>(t),
original_kd_tree,
sample_kd_tree,
radius2,
radius,
original_density_weights,
sample_density_weights,
parallel_callback.advancement(),
parallel_callback.interrupted());
sample_density_weights);
++ callback_wrapper.advancement();
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
parallel_callback.interrupted() = true;
parallel_callback.join();
callback_wrapper.interrupted() = true;
callback_wrapper.join();
// If interrupted during this step, nothing is computed, we return NaN
if (interrupted)
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();
for (update_iter = update_sample_points.begin();
update_iter != update_sample_points.end();
++update_iter, ++sample_iter)
{
*sample_iter = *update_iter;
}
for (std::size_t i = 0; i < sample_points.size(); ++ i)
sample_points[i] = update_sample_points[i];
}
// final output
for(sample_iter = sample_points.begin();
sample_iter != sample_points.end(); ++sample_iter)
{
*output++ = *sample_iter;
}
std::copy (sample_points.begin(), sample_points.end(), output);
return output;
}

View File

@ -106,13 +106,13 @@ struct Poisson_visitor {
struct Poisson_skip_vertices {
double ratio;
Random& m_random;
Poisson_skip_vertices(const double ratio, Random& random)
: ratio(ratio), m_random(random) {}
Poisson_skip_vertices(const double ratio = 0)
: ratio(ratio) {}
template <typename Iterator>
bool operator()(Iterator) const {
return m_random.get_double() < ratio;
bool operator()(Iterator it) const {
// 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,
Poisson_skip_vertices> Some_points_iterator;
//make it deterministic
Random random(0);
Poisson_skip_vertices skip(1.-approximation_ratio,random);
Poisson_skip_vertices skip(1.-approximation_ratio);
CGAL_TRACE_STREAM << "SPECIAL PASS that uses an approximation of the result (approximation ratio: "
<< 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.
///
/// \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...);
}
// 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
#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_vector.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()
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()
: max_span_coord_(-1)
{}
@ -138,6 +139,7 @@ namespace CGAL {
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)
: max_span_coord_(-1)
{
update_from_point_pointers<Construct_cartesian_const_iterator_d>(begin,end,construct_it);
}
@ -288,7 +290,7 @@ namespace CGAL {
}
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
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);
}

View File

@ -182,7 +182,11 @@ public:
}
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)]);
}
};