mirror of https://github.com/CGAL/cgal
Merge pull request #4552 from sgiraudot/PSP-No_copy_for_kdtree-GF
[Point Set Processing] Big factorization + cleanup
This commit is contained in:
commit
3bca04d1f9
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
{
|
||||
if(search_iterator == search.end())
|
||||
break; // premature ending
|
||||
|
||||
Pwn pwn = search_iterator->first;
|
||||
double dist2 = CGAL::squared_distance(query.position(), pwn.position());
|
||||
max_distance = (CGAL::max)(dist2, max_distance);
|
||||
++search_iterator;
|
||||
}
|
||||
neighbor_query.get_iterators
|
||||
(get(point_map, vt), k, (FT)(0.0),
|
||||
boost::make_function_output_iterator
|
||||
([&](const typename NeighborQuery::input_iterator& it)
|
||||
{
|
||||
double dist2 = CGAL::squared_distance (get(point_map, vt), get(point_map, *it));
|
||||
max_distance = (CGAL::max)(dist2, max_distance);
|
||||
}));
|
||||
|
||||
// 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::Parallel_callback
|
||||
parallel_callback (callback, 2 * nb_points);
|
||||
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
|
||||
callback_wrapper (callback, 2 * nb_points);
|
||||
|
||||
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);
|
||||
typedef boost::zip_iterator<boost::tuple<iterator, typename std::vector<iterators>::iterator> > Zip_iterator;
|
||||
|
||||
bool interrupted = parallel_callback.interrupted();
|
||||
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)
|
||||
{
|
||||
if (callback_wrapper.interrupted())
|
||||
return false;
|
||||
|
||||
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||
parallel_callback.interrupted() = true;
|
||||
parallel_callback.join();
|
||||
neighbor_query.get_iterators (get(point_map, get<0>(t)), k, neighbor_radius,
|
||||
std::back_inserter (get<1>(t)));
|
||||
|
||||
// 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();
|
||||
++ callback_wrapper.advancement();
|
||||
|
||||
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);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (callback && !callback ((nb+1) / double(2. * nb_points)))
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
}
|
||||
bool interrupted = callback_wrapper.interrupted();
|
||||
|
||||
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||
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();
|
||||
|
||||
#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)
|
||||
{
|
||||
Point_set_processing_3::internal::Parallel_callback
|
||||
parallel_callback (callback, 2 * nb_points, nb_points);
|
||||
callback_wrapper.reset (2 * nb_points, nb_points);
|
||||
|
||||
//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);
|
||||
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;
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
if (callback_wrapper.interrupted())
|
||||
return false;
|
||||
|
||||
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);
|
||||
|
||||
++ 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();
|
||||
|
||||
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,
|
||||
sharpness_angle);
|
||||
if (callback && !callback ((nb+1) / double(2. * nb_points)))
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
{
|
||||
if(search_iterator == search.end())
|
||||
break; // premature ending
|
||||
|
||||
Point p = search_iterator->first;
|
||||
sum_distances += std::sqrt(CGAL::squared_distance(query,p));
|
||||
search_iterator++;
|
||||
}
|
||||
unsigned int i = 0;
|
||||
neighbor_query.get_points
|
||||
(query, k, 0,
|
||||
boost::make_function_output_iterator
|
||||
([&](const Point& p)
|
||||
{
|
||||
sum_distances += std::sqrt(CGAL::squared_distance (query,p));
|
||||
++ 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,60 +171,46 @@ 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::Parallel_callback
|
||||
parallel_callback (callback, kd_tree_points.size());
|
||||
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
|
||||
callback_wrapper (callback, nb_points);
|
||||
|
||||
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);
|
||||
std::vector<FT> spacings (nb_points, -1);
|
||||
|
||||
for (unsigned int i = 0; i < spacings.size (); ++ i)
|
||||
if (spacings[i] >= 0.)
|
||||
{
|
||||
sum_spacings += spacings[i];
|
||||
++ nb;
|
||||
}
|
||||
typedef boost::zip_iterator<boost::tuple<iterator, typename std::vector<FT>::iterator> > Zip_iterator;
|
||||
|
||||
parallel_callback.join();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (callback_wrapper.interrupted())
|
||||
return false;
|
||||
|
||||
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.)
|
||||
{
|
||||
sum_spacings += spacings[i];
|
||||
++ nb;
|
||||
}
|
||||
callback_wrapper.join();
|
||||
|
||||
// return average spacing
|
||||
return sum_spacings / (FT)(nb);
|
||||
return sum_spacings / (FT)(nb);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
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::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]);
|
||||
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::jet_estimate_normal<Kernel,SvdTraits,Tree>(
|
||||
get(point_map,*it),
|
||||
tree, k, neighbor_radius, degree_fitting);
|
||||
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::jet_estimate_normal<SvdTraits>
|
||||
(get(point_map, vt), neighbor_query, k, neighbor_radius, degree_fitting));
|
||||
++ 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 jet_estimate_normals()\n");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
CGAL::for_each<ConcurrencyTag>
|
||||
(points,
|
||||
[&](value_type vt)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (callback_wrapper.interrupted())
|
||||
return false;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
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);
|
||||
CGAL::for_each<ConcurrencyTag>
|
||||
(points,
|
||||
[&](value_type& vt)
|
||||
{
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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::Parallel_callback
|
||||
parallel_callback (callback, iter_number * number_of_sample, iter_n * number_of_sample);
|
||||
Point_set_processing_3::internal::Callback_wrapper<ConcurrencyTag>
|
||||
callback_wrapper (callback, iter_number * number_of_sample, iter_n * number_of_sample);
|
||||
|
||||
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,
|
||||
original_kd_tree,
|
||||
sample_kd_tree,
|
||||
radius2,
|
||||
original_density_weights,
|
||||
sample_density_weights,
|
||||
parallel_callback.advancement(),
|
||||
parallel_callback.interrupted());
|
||||
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)
|
||||
{
|
||||
if (callback_wrapper.interrupted())
|
||||
return false;
|
||||
|
||||
tbb::parallel_for(block, sample_updater);
|
||||
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,
|
||||
radius,
|
||||
original_density_weights,
|
||||
sample_density_weights);
|
||||
++ callback_wrapper.advancement();
|
||||
|
||||
bool interrupted = parallel_callback.interrupted();
|
||||
return true;
|
||||
});
|
||||
|
||||
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||
parallel_callback.interrupted() = true;
|
||||
parallel_callback.join();
|
||||
bool interrupted = callback_wrapper.interrupted();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
// We interrupt by hand as counter only goes halfway and won't terminate by itself
|
||||
callback_wrapper.interrupted() = true;
|
||||
callback_wrapper.join();
|
||||
|
||||
// If interrupted during this step, nothing is computed, we return NaN
|
||||
if (interrupted)
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <boost/array.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
|
||||
/*!
|
||||
\file Poisson_reconstruction_function.h
|
||||
|
|
@ -104,18 +105,6 @@ 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) {}
|
||||
|
||||
template <typename Iterator>
|
||||
bool operator()(Iterator) const {
|
||||
return m_random.get_double() < ratio;
|
||||
}
|
||||
};
|
||||
|
||||
// Given f1 and f2, two sizing fields, that functor wrapper returns
|
||||
// max(f1, f2*f2)
|
||||
// The wrapper stores only pointers to the two functors.
|
||||
|
|
@ -415,11 +404,15 @@ public:
|
|||
// then the cell is considered as small enough, and the first sizing
|
||||
// field, more costly, is not evaluated.
|
||||
|
||||
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);
|
||||
double ratio = 1.-approximation_ratio;
|
||||
|
||||
std::vector<typename Triangulation::Input_point_iterator> some_points;
|
||||
for (typename Triangulation::Input_point_iterator
|
||||
it = m_tr->input_points_begin(); it != m_tr->input_points_end(); ++ it)
|
||||
if (random.get_double() >= ratio)
|
||||
some_points.push_back (it);
|
||||
|
||||
CGAL_TRACE_STREAM << "SPECIAL PASS that uses an approximation of the result (approximation ratio: "
|
||||
<< approximation_ratio << ")" << std::endl;
|
||||
|
|
@ -427,11 +420,8 @@ public:
|
|||
|
||||
CGAL::Timer sizing_field_timer; sizing_field_timer.start();
|
||||
Poisson_reconstruction_function<Geom_traits>
|
||||
coarse_poisson_function(Some_points_iterator(m_tr->input_points_end(),
|
||||
skip,
|
||||
m_tr->input_points_begin()),
|
||||
Some_points_iterator(m_tr->input_points_end(),
|
||||
skip),
|
||||
coarse_poisson_function(boost::make_indirect_iterator (some_points.begin()),
|
||||
boost::make_indirect_iterator (some_points.end()),
|
||||
Normal_of_point_with_normal_map<Geom_traits>() );
|
||||
coarse_poisson_function.compute_implicit_function(solver, Poisson_visitor(),
|
||||
0.);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
// 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 Fct, typename IteratorCategory>
|
||||
void for_each (RangeRef range,
|
||||
const Fct& 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, typename Fct>
|
||||
void for_each (RangeRef range,
|
||||
const Fct& 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
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue