Merge pull request #4362 from afabri/Box_intersection_d-accelerate-GF

PMP::self_intersections: Add Concurrency
This commit is contained in:
Laurent Rineau 2020-02-07 16:25:06 +01:00
commit 49a06e9201
26 changed files with 1261 additions and 813 deletions

View File

@ -242,6 +242,29 @@ void box_intersection_all_pairs_d(
cutoff parameters are recommended. See also
Section \ref secboxintersperformance .
\cgalHeading{Concurrency}
The first template parameter of the function enables to choose whether
the algorithm is to be run in parallel, if `CGAL::Parallel_tag` is specified
and %CGAL has been linked with the Intel TBB library, or sequentially,
if `CGAL::Sequential_tag` - the default value - is specified.
The parallelization of the algorithm is based on a divide-and-conquer
approach: the two ranges are split in a number of smaller ranges, and
all combinations of subranges are treated in parallel. It is thus
recommended to use ranges of pointers to bounding boxes, to keep
these copies light.
\warning The parallel mode comes with a small overhead due to the
duplication and splitting of the input ranges. It is an improvement
for almost all inputs, but not all. A configuration where the two ranges
are small and entirely disjoint might result in a slightly worse
runtime when using the parallel version. Users should benchmark both
versions to verify that their data does not fall in this (small)
set of inputs.
\warning When using the parallel mode, the callback function must
be threadsafe.
\cgalHeading{Example}
The box implementation provided with
@ -274,7 +297,8 @@ void box_intersection_all_pairs_d(
*/
template< class RandomAccessIterator1,
template< class ConcurrencyTag = CGAL::Sequential_tag,
class RandomAccessIterator1,
class RandomAccessIterator2,
class Callback >
void box_intersection_d(
@ -291,7 +315,8 @@ void box_intersection_d(
Invocation with custom box traits.
*/
template< class RandomAccessIterator1,
template< class ConcurrencyTag = CGAL::Sequential_tag,
class RandomAccessIterator1,
class RandomAccessIterator2,
class Callback, class BoxTraits >
void box_intersection_d(
@ -489,8 +514,11 @@ namespace CGAL {
\cgalHeading{Implementation}
See the implementation section of the `box_intersection_d()`
function.
See the implementation section of the `box_intersection_d()` function.
\cgalHeading{Concurrency}
See the concurrency section of the `box_intersection_d()` function.
\cgalHeading{Example}
@ -520,7 +548,8 @@ namespace CGAL {
`RandomAccessIterator`.
*/
template< class RandomAccessIterator, class Callback >
template< class ConcurrencyTag = CGAL::Sequential_tag,
class RandomAccessIterator, class Callback >
void box_self_intersection_d(
RandomAccessIterator begin, RandomAccessIterator end,
Callback callback,
@ -532,7 +561,8 @@ void box_self_intersection_d(
Invocation with custom box traits.
*/
template< class RandomAccessIterator,
template< class ConcurrencyTag = CGAL::Sequential_tag
class RandomAccessIterator,
class Callback, class BoxTraits >
void box_self_intersection_d(
RandomAccessIterator begin, RandomAccessIterator end,

View File

@ -16,34 +16,34 @@
#include <CGAL/license/Box_intersection_d.h>
#include <CGAL/basic.h>
#include <CGAL/Box_intersection_d/Box_d.h>
namespace CGAL {
namespace Box_intersection_d {
template<class NT_, int N, class Info_>
class Box_with_info_d : public Box_d< NT_, N, ID_FROM_BOX_ADDRESS> {
template<class NT_, int N, class Info_, class IdPolicy = ID_EXPLICIT>
class Box_with_info_d
: public Box_d< NT_, N, IdPolicy>
{
protected:
Info_ m_info;
public:
typedef Box_d< NT_, N, ID_FROM_BOX_ADDRESS> Base;
typedef NT_ NT;
typedef Info_ Info;
typedef Box_d< NT_, N, IdPolicy> Base;
typedef NT_ NT;
typedef Info_ Info;
Box_with_info_d() {}
Box_with_info_d( Info h) : m_info(h) {}
Box_with_info_d( bool complete, Info h): Base(complete), m_info(h) {}
Box_with_info_d(NT l[N], NT h[N], Info n) : Base( l, h), m_info(n) {}
Box_with_info_d( const Bbox_2& b, Info h) : Base( b), m_info(h) {}
Box_with_info_d( const Bbox_3& b, Info h) : Base( b), m_info(h) {}
Info info() const { return m_info; }
};
} // end namespace Box_intersection_d
} // namespace Box_intersection_d
} // namespace CGAL
} //namespace CGAL
#endif
#endif // CGAL_BOX_INTERSECTION_D_BOX_WITH_INFO_D_H

View File

@ -16,7 +16,6 @@
#include <CGAL/license/Box_intersection_d.h>
#include <CGAL/basic.h>
#include <CGAL/Box_intersection_d/box_limits.h>
@ -24,7 +23,6 @@
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <algorithm>
#include <iterator>
#include <functional>
@ -93,6 +91,8 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end,
bool in_order = true )
{
typedef typename Traits::Compare Compare;
// Putting a parallel sort here slows down the overall parallel algorithm
std::sort( p_begin, p_end, Compare( 0 ) );
std::sort( i_begin, i_end, Compare( 0 ) );
@ -323,7 +323,7 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end,
RandomAccessIter2 i_begin, RandomAccessIter2 i_end,
T lo, T hi,
Callback callback, Predicate_traits traits,
std::ptrdiff_t cutoff, int dim, bool in_order )
std::ptrdiff_t cutoff, int dim, bool in_order)
{
typedef typename Predicate_traits::Spanning Spanning;
typedef typename Predicate_traits::Lo_less Lo_less;

View File

@ -6,7 +6,7 @@
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
//
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>
// Andreas Meyer <ameyer@mpi-sb.mpg.de>
@ -25,12 +25,191 @@
#include <CGAL/Box_intersection_d/Box_traits_d.h>
#include <CGAL/Box_intersection_d/box_limits.h>
#include <CGAL/use.h>
#include <CGAL/tags.h>
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/task_group.h>
#endif
#include <iterator>
#include <vector>
////////////////////////////////////////////////////////////////////////////////////////////////
/// THE CALLBACK MUST BE THREADSAFE IF YOU ARE USING THE PARALLEL MODE
////////////////////////////////////////////////////////////////////////////////////////////////
namespace CGAL {
namespace internal {
// Generic call with custom predicate traits parameter.
template< class RandomAccessIter1, class RandomAccessIter2,
template< class ConcurrencyTag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class Traits >
void box_intersection_segment_tree_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback,
const Traits& traits,
const std::ptrdiff_t cutoff,
const bool in_order)
{
typedef typename Traits::NT NT;
CGAL_assertion(Traits::dimension() > 0);
const int dim = Traits::dimension() - 1;
const NT inf = Box_intersection_d::box_limits<NT>::inf();
const NT sup = Box_intersection_d::box_limits<NT>::sup();
#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 // CGAL_LINKED_WITH_TBB
if(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
{
// Here is an illustration for n=2.
//
// Doing a R1-R2 intersection with a 2-split is doing 4 subpairs in parallel
// a-c and b-d
// r1[0][0] --a-- r1[0][1] --b-- r1[0][2]
// r2[0][0] --c-- r2[0][1] --d-- r2[0][2]
//
// a-d and b-c
// r1[1][0] --a-- r1[1][1] --b-- r1[1][2]
// r2[1][0] --c-- r2[1][1] --d-- r2[1][2]
//
// Ranges must be duplicates since sorting is performed
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef typename std::iterator_traits<RandomAccessIter1>::difference_type diff_size;
typedef std::vector<val_t> val_container;
typedef typename val_container::iterator It;
static constexpr int n = 4;
const diff_size r1s = std::distance(begin1, end1);
const diff_size r2s = std::distance(begin2, end2);
val_container range_1_copies, range_2_copies;
range_1_copies.reserve(r1s * n);
range_2_copies.reserve(r2s * n);
const diff_size r1_step = r1s / n;
const diff_size r2_step = r2s / n;
for(int i=0; i<n; ++i)
{
range_1_copies.insert(range_1_copies.end(), begin1, end1);
range_2_copies.insert(range_2_copies.end(), begin2, end2);
}
// for example for n=2, there's 'begin', 'mid', and 'end' but we leave out 'end' for convenience
std::array<std::array<It, n>, n> range_1_iterators;
std::array<std::array<It, n>, n> range_2_iterators;
for(int i=0; i<n; ++i)
{
for(int j=0; j<n; ++j)
{
range_1_iterators[i][j] = range_1_copies.begin() + i * r1s + j * r1_step;
range_2_iterators[i][j] = range_2_copies.begin() + i * r2s + j * r2_step;
}
}
tbb::task_group g;
for(int i=0; i<n; ++i)
{
for(int j=0; j<n; ++j)
{
// 'j' vs 'j+i', meaning for each value of 'i' we're matching r1[i] with a shifted version of r2[i]
int r1_endi, r1_endj;
int r2_endi, r2_endj;
if(i == (n-1))
{
if(j == (n-1)) // both very last range and very last iterator
{
r1_endi = -1;
r1_endj = -1;
}
else
{
r1_endi = i;
r1_endj = j+1;
}
}
else // i != (n-1)
{
if(j == (n-1)) // end of that range, but not of the full container
{
r1_endi = i+1;
r1_endj = 0;
}
else
{
r1_endi = i;
r1_endj = j+1;
}
}
if(i == (n-1))
{
if(j+i == (n-1)) // both very last range and very last iterator
{
r2_endi = -1;
r2_endj = -1;
}
else
{
r2_endi = i;
r2_endj = (j+i+1)%n;
}
}
else // i != (n-1)
{
if(j+i == (n-1)) // end of that range, but not of the full container
{
r2_endi = i+1;
r2_endj = 0;
}
else
{
r2_endi = i;
r2_endj = (j+i+1)%n;
}
}
It r1_start = range_1_iterators[i][j];
It r1_end = (r1_endi == -1) ? range_1_copies.end() : range_1_iterators[r1_endi][r1_endj];
It r2_start = range_2_iterators[i][(j+i)%n];
It r2_end = (r2_endi == -1) ? range_2_copies.end() : range_2_iterators[r2_endi][r2_endj];
CGAL_assertion(range_1_copies.begin() <= r1_start && r1_start <= r1_end && r1_end <= range_1_copies.end());
CGAL_assertion(range_2_copies.begin() <= r2_start && r2_start <= r2_end && r2_end <= range_2_copies.end());
// Specify "copy by value" otherwise the values of iterators for next (i,j) iterations
// become shared with different lambdas being run in parallel, and things go wrong
g.run([=]{ Box_intersection_d::segment_tree( r1_start, r1_end, r2_start, r2_end,
inf, sup, callback, traits, cutoff, dim, in_order); });
}
}
g.wait();
}
else
#endif // CGAL_LINKED_WITH_TBB
{
Box_intersection_d::segment_tree(begin1, end1, begin2, end2, inf, sup, callback, traits, cutoff, dim, in_order);
}
}
} // namespace internal
// Generic call with custom predicate traits parameter.
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class BoxPredicateTraits >
void box_intersection_custom_predicates_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
@ -40,23 +219,15 @@ void box_intersection_custom_predicates_d(
std::ptrdiff_t cutoff = 10,
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE)
{
typedef BoxPredicateTraits Traits;
typedef typename Traits::NT NT;
CGAL_assertion( Traits::dimension() > 0 );
const int dim = Traits::dimension() - 1;
const NT inf = Box_intersection_d::box_limits<NT>::inf();
const NT sup = Box_intersection_d::box_limits<NT>::sup();
Box_intersection_d::segment_tree(begin1, end1, begin2, end2,
inf, sup, callback, traits, cutoff, dim, true);
if(setting == Box_intersection_d::BIPARTITE)
Box_intersection_d::segment_tree(begin2, end2, begin1, end1,
inf, sup, callback, traits, cutoff, dim, false);
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin1, end1, begin2, end2, callback, traits, cutoff, true);
if(setting == Box_intersection_d::BIPARTITE)
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin2, end2, begin1, end1, callback, traits, cutoff, false);
}
// Generic call with box traits parameter.
// - make all default parameters explicit overloads (workaround)
template< class RandomAccessIter1, class RandomAccessIter2,
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class BoxTraits >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
@ -67,18 +238,19 @@ void box_intersection_d(
Box_intersection_d::Topology topology,
Box_intersection_d::Setting setting)
{
if (topology == Box_intersection_d::CLOSED) {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
callback, Traits(), cutoff, setting);
} else {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
callback, Traits(), cutoff, setting);
}
if (topology == Box_intersection_d::CLOSED) {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
callback, Traits(), cutoff, setting);
} else {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
callback, Traits(), cutoff, setting);
}
}
template< class RandomAccessIter1, class RandomAccessIter2,
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class BoxTraits >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
@ -86,35 +258,39 @@ void box_intersection_d(
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff,
Box_intersection_d::Topology topology)
{
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
cutoff, topology, Box_intersection_d::BIPARTITE);
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
cutoff, topology, Box_intersection_d::BIPARTITE);
}
template< class RandomAccessIter1, class RandomAccessIter2,
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class BoxTraits >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff)
{
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
cutoff, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
cutoff, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
}
template< class RandomAccessIter1, class RandomAccessIter2,
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2,
class Callback, class BoxTraits >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback, BoxTraits box_traits)
{
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
10, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
10, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
}
// Specialized call with default box traits.
// - make all default parameters explicit overloads (workaround)
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2, class Callback >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
@ -122,53 +298,58 @@ void box_intersection_d(
Box_intersection_d::Topology topology,
Box_intersection_d::Setting setting)
{
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, topology, setting);
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, topology, setting);
}
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2, class Callback >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback, std::ptrdiff_t cutoff,
Box_intersection_d::Topology topology)
{
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, topology, Box_intersection_d::BIPARTITE);
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, topology, Box_intersection_d::BIPARTITE);
}
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2, class Callback >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback, std::ptrdiff_t cutoff)
{
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
cutoff, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
}
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter1, class RandomAccessIter2, class Callback >
void box_intersection_d(
RandomAccessIter1 begin1, RandomAccessIter1 end1,
RandomAccessIter2 begin2, RandomAccessIter2 end2,
Callback callback)
{
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
10, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
10, Box_intersection_d::CLOSED,
Box_intersection_d::BIPARTITE);
}
// Generic call with box traits parameter, specialized for self-intersection.
// - make all default parameters explicit overloads (workaround)
template< class RandomAccessIter, class Callback, class BoxTraits >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter, class Callback, class BoxTraits >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback,
@ -176,49 +357,52 @@ void box_self_intersection_d(
std::ptrdiff_t cutoff,
Box_intersection_d::Topology topology)
{
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
// is necessary because the 'std::partition' and range splits on the first range
// would be messed up by sorts on the second range otherwise.
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
std::vector< val_t> i( begin, end);
box_intersection_d( begin, end, i.begin(), i.end(),
callback, box_traits, cutoff, topology,
Box_intersection_d::COMPLETE);
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
// is necessary because the 'std::partition' and range splits on the first range
// would be messed up by sorts on the second range otherwise.
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
std::vector< val_t> i( begin, end);
box_intersection_d<ConcurrencyTag>( begin, end, i.begin(), i.end(),
callback, box_traits, cutoff, topology,
Box_intersection_d::COMPLETE);
}
template< class RandomAccessIter, class Callback, class BoxTraits >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter, class Callback, class BoxTraits >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback,
BoxTraits box_traits,
std::ptrdiff_t cutoff)
{
return box_self_intersection_d(begin, end, callback, box_traits, cutoff,
Box_intersection_d::CLOSED);
return box_self_intersection_d<ConcurrencyTag>(begin, end, callback, box_traits, cutoff,
Box_intersection_d::CLOSED);
}
template< class RandomAccessIter, class Callback, class BoxTraits >
template< class ConcurrencyTag = Sequential_tag,
class RandomAccessIter, class Callback, class BoxTraits >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback,
BoxTraits box_traits)
{
return box_self_intersection_d(begin, end, callback, box_traits, 10);
return box_self_intersection_d<ConcurrencyTag>(begin, end, callback, box_traits, 10);
}
// Specialized call with default box traits, specialized for self-intersection.
// - make all default parameters explicit overloads (workaround)
template< class RandomAccessIter, class Callback >
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback)
{
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_self_intersection_d(begin, end, callback, Box_traits());
box_self_intersection_d<ConcurrencyTag>(begin, end, callback, Box_traits());
}
template< class RandomAccessIter, class Callback >
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback,
@ -226,10 +410,10 @@ void box_self_intersection_d(
{
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_self_intersection_d(begin, end, callback, Box_traits(), cutoff);
box_self_intersection_d<ConcurrencyTag>(begin, end, callback, Box_traits(), cutoff);
}
template< class RandomAccessIter, class Callback >
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
void box_self_intersection_d(
RandomAccessIter begin, RandomAccessIter end,
Callback callback,
@ -238,28 +422,27 @@ void box_self_intersection_d(
{
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_self_intersection_d(begin, end, callback,
Box_traits(), cutoff, topology );
box_self_intersection_d<ConcurrencyTag>(begin, end, callback,
Box_traits(), cutoff, topology );
}
// Generic call for trivial all-pairs algorithm with box traits parameter.
// - make all default parameters explicit overloads (workaround)
template< class ForwardIter1, class ForwardIter2,
class Callback, class BoxTraits >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback, BoxTraits)
{
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
callback, Traits());
}
template< class ForwardIter1, class ForwardIter2,
class Callback, class BoxTraits >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback, BoxTraits,
@ -269,18 +452,18 @@ void box_intersection_all_pairs_d(
bool complete_case = (setting != Box_intersection_d::BIPARTITE);
if (topology == Box_intersection_d::CLOSED) {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
callback, Traits(), complete_case);
} else {
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
callback, Traits(), complete_case);
}
}
template< class ForwardIter1, class ForwardIter2,
class Callback, class BoxTraits >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback, BoxTraits traits,
@ -293,20 +476,20 @@ void box_intersection_all_pairs_d(
// Specialized call for trivial all-pairs algorithm with default box traits.
// - make all default parameters explicit overloads (workaround)
template< class ForwardIter1, class ForwardIter2, class Callback >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback)
{
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
callback, Box_traits(),
Box_intersection_d::CLOSED );
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
callback, Box_traits(),
Box_intersection_d::CLOSED );
}
template< class ForwardIter1, class ForwardIter2, class Callback >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback,
@ -314,12 +497,12 @@ void box_intersection_all_pairs_d(
{
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
callback, Box_traits(), topology);
}
template< class ForwardIter1, class ForwardIter2, class Callback >
void box_intersection_all_pairs_d(
void box_intersection_all_pairs_d(
ForwardIter1 begin1, ForwardIter1 end1,
ForwardIter2 begin2, ForwardIter2 end2,
Callback callback,
@ -328,7 +511,7 @@ void box_intersection_all_pairs_d(
{
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
callback, Box_traits(), topology, setting);
}
@ -336,7 +519,7 @@ void box_intersection_all_pairs_d(
// specialized for self-intersection test.
// - make all default parameters explicit overloads (workaround)
template< class ForwardIter, class Callback, class BoxTraits >
void box_self_intersection_all_pairs_d(
void box_self_intersection_all_pairs_d(
ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits /* traits */)
{
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
@ -344,7 +527,7 @@ void box_self_intersection_all_pairs_d(
}
template< class ForwardIter, class Callback, class BoxTraits >
void box_self_intersection_all_pairs_d(
void box_self_intersection_all_pairs_d(
ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits,
Box_intersection_d::Topology topology)
{
@ -361,17 +544,17 @@ void box_self_intersection_all_pairs_d(
// specialized for self-intersection test.
// - make all default parameters explicit overloads (workaround)
template< class ForwardIter, class Callback >
void box_self_intersection_all_pairs_d(
void box_self_intersection_all_pairs_d(
ForwardIter begin1, ForwardIter end1, Callback callback)
{
typedef typename std::iterator_traits<ForwardIter>::value_type val_t;
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(),
Box_intersection_d::CLOSED );
box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(),
Box_intersection_d::CLOSED );
}
template< class ForwardIter, class Callback >
void box_self_intersection_all_pairs_d(
void box_self_intersection_all_pairs_d(
ForwardIter begin1, ForwardIter end1, Callback callback,
Box_intersection_d::Topology topology)
{

View File

@ -5,20 +5,23 @@
cmake_minimum_required(VERSION 3.1...3.15)
project( Box_intersection_d_Tests )
find_package( CGAL QUIET )
find_package(CGAL QUIET)
find_package( TBB )
if ( CGAL_FOUND )
# create a target per cppfile
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach(cppfile ${cppfiles})
create_single_source_cgal_program( "${cppfile}" )
endforeach()
create_single_source_cgal_program( "automated_test.cpp" )
create_single_source_cgal_program( "benchmark_box_intersection.cpp" )
create_single_source_cgal_program( "random_set_test.cpp" )
create_single_source_cgal_program( "test_box_grid.cpp" )
if( TBB_FOUND )
CGAL_target_use_TBB( test_box_grid )
else()
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )
endif()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()

View File

@ -1,217 +1,297 @@
// file: test/Box_intersection_d/box_grid.C
// similar to examples/Box_intersection_d/box_grid.C but stricter in checking
// and more extensive in what is tested.
#include <CGAL/box_intersection_d.h>
#include <cassert>
#include <vector>
#include <algorithm>
#include <iterator>
typedef CGAL::Box_intersection_d::Box_d<int,2> Box;
#include <CGAL/box_intersection_d.h>
#include <CGAL/tags.h>
#include <algorithm>
#include <cassert>
#include <iterator>
#include <vector>
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/concurrent_vector.h>
#endif
typedef CGAL::Box_intersection_d::Box_d<int, 2> Box;
// coordinates for 9 boxes of a grid
int p[9*4] = { 0,0,1,1, 1,0,2,1, 2,0,3,1, // lower
0,1,1,2, 1,1,2,2, 2,1,3,2, // middle
0,2,1,3, 1,2,2,3, 2,2,3,3};// upper
// 9 boxes + 2 selected boxes as query; center and upper right
Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10),
Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22),
Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34),
Box( p+16, p+18), Box( p+32, p+34)};
const Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10),
Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22),
Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34),
Box( p+16, p+18), Box( p+32, p+34)};
Box boxes[11];
Box* query = boxes+9;
void init() {
for ( int i = 0; i < 11; ++i)
boxes[i] = init_boxes[i];
void init()
{
for ( int i = 0; i < 11; ++i)
boxes[i] = init_boxes[i];
}
void check_result( const char* text, std::vector<std::size_t>& result,
const std::size_t* check, std::size_t size) {
// sort, show, and check result
std::sort( result.begin(), result.end());
std::cout << text << ": got " << result.size() << " elements, expected "
<< size << " elements\n got : ";
std::copy( result.begin(), result.end(),
std::ostream_iterator<std::size_t>( std::cout, ","));
std::cout << "\n expected: ";
std::copy( check, check+size,
std::ostream_iterator<std::size_t>( std::cout, ","));
std::cout << '\n' << std::endl;
assert( result.size() == size
&& std::equal( check, check+size, result.begin()));
template <typename Vector>
void check_result( const char* text,
Vector& result,
const std::size_t* check,
std::size_t size)
{
// sort, show, and check result
std::sort( result.begin(), result.end());
std::cout << text << ": got " << result.size() << " elements, expected "
<< size << " elements\n got : ";
std::copy( result.begin(), result.end(),
std::ostream_iterator<std::size_t>( std::cout, ","));
std::cout << "\n expected: ";
std::copy( check, check+size,
std::ostream_iterator<std::size_t>( std::cout, ","));
std::cout << '\n' << std::endl;
assert( result.size() == size
&& std::equal( check, check+size, result.begin()));
}
// callback function object writing results to an output iterator
template <class OutputIterator>
struct Report {
OutputIterator it;
Report( OutputIterator i) : it(i) {} // store iterator in object
// We encode both id-numbers in a single number, a.id() + 100 * b.id(),
// and write that number to the output iterator.
void operator()( const Box& a, const Box& b) { *it++ = a.id()+100*b.id(); }
template <class Container>
struct Report
{
Container& c_;
Report(Container& c) : c_(c) {} // store iterator in object
// We encode both id-numbers in a single number, a.id() + 100 * b.id(),
// and write that number to the output iterator.
void operator()(const Box& a, const Box& b) { c_.push_back(a.id()+100*b.id()); }
void operator()(const Box* a, const Box* b) { c_.push_back(a->id()+100*b->id()); }
};
template <class Iter> // helper function to create the function object
Report<Iter> report( Iter it) { return Report<Iter>(it); }
template <class Container> // helper function to create the function object
Report<Container> report(Container& c) { return Report<Container>(c); }
// ---------------------------------------------------------------------
// box_intersection_d
// run the intersection algorithms and store results in a vector
// ---------------------------------------------------------------------
void test_box_intersection() {
// intersect 3x3 with 2 query boxes, closed boxes
init();
std::vector<std::size_t> result;
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
report( std::back_inserter( result)));
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
1004,1005,1007,1008};
check_result( "Box inters. 3x3, 2, closed", result, check1, 13);
void test_box_intersection()
{
#ifdef CGAL_LINKED_WITH_TBB
tbb::concurrent_vector<std::size_t> result;
#else
std::vector<std::size_t> result;
#endif
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff
init();
result.clear();
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
report( std::back_inserter( result)),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check2[2] = {904,1008};
check_result( "Box inters. 3x3, 2, half-open", result, check2, 2);
// Some degenerate cases
init();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, boxes, boxes,
report(result));
assert(result.empty());
// self intersect 3x2, closed boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+6,
report( std::back_inserter( result)));
std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405};
check_result( "Box self inters. 3x2, closed", result, check3, 11);
init();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, query, query + 1,
report(result));
assert(result.empty());
// self intersect 3x2, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+6,
report( std::back_inserter( result)),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check4[1] = {9999};
check_result( "Box self inters. 3x2, half-open", result, check4, 0);
init();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes + 3, query, query,
report(result));
assert(result.empty());
// self intersect 3x3+2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+11,
report( std::back_inserter( result)),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check5[2] = {409,810};
check_result( "Box self inters. 3x3+2, half-open", result, check5, 2);
// With pointers
init();
std::vector<const Box*> range_1 = {{ boxes, boxes+1, boxes+2, boxes+3, boxes+4, boxes+5,
boxes+6, boxes+7, boxes+8 }};
std::vector<const Box*> range_2 = {{ query, query+1 }};
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
// tests also mixed types for the two iterator ranges
init();
result.clear();
std::vector<Box> boxes2( boxes, boxes+11);
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
report( std::back_inserter( result)),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::COMPLETE);
check_result( "Box inters. 3x3+2, half-open", result, check5, 2);
// compare this with the bipartite case
// self intersect 3x3+2 query boxes, half-open boxes
// tests also mixed types for the two iterator ranges
init();
result.clear();
boxes2 = std::vector<Box>( boxes, boxes+11);
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
report( std::back_inserter( result)),
std::ptrdiff_t(20),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::BIPARTITE);
std::size_t check6[4] = {409,810,904,1008};
check_result( "Box inters. 3x3+2, half-open", result, check6, 4);
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.begin(),
range_2.begin(), range_2.end(),
report(result));
assert(result.empty());
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
range_2.begin(), range_2.begin(),
report(result));
assert(result.empty());
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
range_2.begin(), range_2.end(),
report(result));
std::size_t check0[13] = {900,901,902,903,904,905,906,907,908,
1004,1005,1007,1008};
check_result( "Box inters. 3x3 (ptr), 2, closed", result, check0, 13);
// intersect 3x3 with 2 query boxes, closed boxes
init();
result.clear();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes+9, query, query+1, report(result));
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908};
check_result( "Box inters. 3x3, 2, closed", result, check1, 9);
// intersect 3x3 with 2 query boxes, closed boxes
init();
result.clear();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes+9, query, query+2, report(result));
std::size_t check1bis[13] = {900,901,902,903,904,905,906,907,908,
1004,1005,1007,1008};
check_result( "Box inters. 3x3, 2, closed", result, check1bis, 13);
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff
init();
result.clear();
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
report(result),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check2[2] = {904,1008};
check_result( "Box inters. 3x3, 2, half-open", result, check2, 2);
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff (reversed)
init();
result.clear();
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>( query, query+2, boxes, boxes+9,
report(result),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check2bis[2] = {409,810};
check_result( "Box inters. 3x3 (reversed), 2, half-open", result, check2bis, 2);
// self intersect 3x2, closed boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+6,
report(result));
std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405};
check_result( "Box self inters. 3x2, closed", result, check3, 11);
// self intersect 3x2, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+6,
report(result),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check4[1] = {9999};
check_result( "Box self inters. 3x2, half-open", result, check4, 0);
// self intersect 3x3+2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_d( boxes, boxes+11,
report(result),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check5[2] = {409,810};
check_result( "Box self inters. 3x3+2, half-open", result, check5, 2);
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
// tests also mixed types for the two iterator ranges
init();
result.clear();
std::vector<Box> boxes2( boxes, boxes+11);
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
report(result),
std::ptrdiff_t(1),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::COMPLETE);
check_result( "Box inters. 3x3+2, half-open", result, check5, 2);
// compare this with the bipartite case
// self intersect 3x3+2 query boxes, half-open boxes
// tests also mixed types for the two iterator ranges
init();
result.clear();
boxes2 = std::vector<Box>( boxes, boxes+11);
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
report(result),
std::ptrdiff_t(20),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::BIPARTITE);
std::size_t check6[4] = {409,810,904,1008};
check_result( "Box inters. 3x3+2, half-open", result, check6, 4);
}
// ---------------------------------------------------------------------
// box_intersection_all_pairs_d
// run the intersection algorithms and store results in a vector
// ---------------------------------------------------------------------
void test_box_intersection_all_pairs() {
// intersect 3x3 with 2 query boxes, closed boxes
init();
std::vector<std::size_t> result;
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
report( std::back_inserter( result)));
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
1004,1005,1007,1008};
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
void test_box_intersection_all_pairs()
{
// intersect 3x3 with 2 query boxes, closed boxes
init();
std::vector<std::size_t> result;
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
report(result));
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
1004,1005,1007,1008};
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
// intersect 3x3 with 2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
report( std::back_inserter( result)),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check2[2] = {904,1008};
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
// intersect 3x3 with 2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
report(result),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check2[2] = {904,1008};
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
// self intersect 3x2, closed boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
report( std::back_inserter( result)));
std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504};
check_result( "All-pairs self inters. 3x2, closed", result, check3, 11);
// self intersect 3x2, closed boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
report(result));
std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504};
check_result( "All-pairs self inters. 3x2, closed", result, check3, 11);
// self intersect 3x2, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
report( std::back_inserter( result)),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check4[1] = {9999};
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
// self intersect 3x2, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
report(result),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check4[1] = {9999};
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
// self intersect 3x3+2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
report( std::back_inserter( result)),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check5[2] = {904,1008};
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
// self intersect 3x3+2 query boxes, half-open boxes
init();
result.clear();
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
report(result),
CGAL::Box_intersection_d::HALF_OPEN);
std::size_t check5[2] = {904,1008};
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
// tests also mixed types for the two iterator ranges
init();
result.clear();
std::vector<Box> boxes2( boxes, boxes+11);
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
boxes2.begin(), boxes2.end(),
report( std::back_inserter( result)),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::COMPLETE);
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
// compare this with the bipartite case
// self intersect 3x3+2 query boxes, half-open boxes
// tests also mixed types for the two iterator ranges
init();
result.clear();
boxes2 = std::vector<Box>( boxes, boxes+11);
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
boxes2.begin(), boxes2.end(),
report( std::back_inserter( result)),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::BIPARTITE);
std::size_t check6[4] = {409,810,904,1008};
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
// tests also mixed types for the two iterator ranges
init();
result.clear();
std::vector<Box> boxes2( boxes, boxes+11);
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
boxes2.begin(), boxes2.end(),
report(result),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::COMPLETE);
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
// compare this with the bipartite case
// self intersect 3x3+2 query boxes, half-open boxes
// tests also mixed types for the two iterator ranges
init();
result.clear();
boxes2 = std::vector<Box>( boxes, boxes+11);
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
boxes2.begin(), boxes2.end(),
report(result),
CGAL::Box_intersection_d::HALF_OPEN,
CGAL::Box_intersection_d::BIPARTITE);
std::size_t check6[4] = {409,810,904,1008};
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
}
int main()
{
test_box_intersection();
test_box_intersection_all_pairs();
int main() {
test_box_intersection();
test_box_intersection_all_pairs();
return 0;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2011 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) : Andreas Fabri, Laurent Rineau
#ifndef CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H
#define CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H
namespace CGAL {
namespace internal {
namespace Static_filters_predicates {
template < typename K_base, typename SFK >
class Coplanar_3
: public K_base::Coplanar_3
{
typedef typename K_base::Point_3 Point_3;
typedef typename K_base::Coplanar_3 Base;
typedef typename SFK::Orientation_3 Orientation_3;
public:
typedef typename Base::result_type result_type;
result_type
operator()(const Point_3& p,const Point_3& q, const Point_3& r, const Point_3& s) const
{
return Orientation_3()(p,q,r,s) == COPLANAR;
}
}; // end class Coplanar_3
} // end namespace Static_filters_predicates
} // end namespace internal
} // end namespace CGAL
#endif // CGAL_INTERNAL_STATIC_FILTERS_COPLANAR_3_H

View File

@ -41,7 +41,6 @@
#endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
# include <CGAL/internal/Static_filters/Equal_3.h>
# include <CGAL/internal/Static_filters/Equal_2.h>
@ -65,6 +64,7 @@
# include <CGAL/internal/Static_filters/Do_intersect_2.h>
#endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS
#include <CGAL/internal/Static_filters/Coplanar_3.h>
#include <CGAL/internal/Static_filters/Compare_y_at_x_2.h>
#include <CGAL/internal/Static_filters/Side_of_oriented_circle_2.h>
#include <CGAL/internal/Static_filters/Side_of_oriented_sphere_3.h>
@ -121,6 +121,7 @@ public:
typedef Static_filters_predicates::Side_of_oriented_circle_2<K_base> Side_of_oriented_circle_2;
typedef Static_filters_predicates::Side_of_oriented_sphere_3<K_base> Side_of_oriented_sphere_3;
typedef Static_filters_predicates::Compare_squared_radius_3<K_base> Compare_squared_radius_3;
typedef Static_filters_predicates::Coplanar_3<K_base,Self> Coplanar_3;
typedef Static_filters_predicates::Compare_weighted_squared_radius_3<K_base> Compare_weighted_squared_radius_3;
typedef Static_filters_predicates::Power_side_of_oriented_power_sphere_3<K_base> Power_side_of_oriented_power_sphere_3;
@ -138,28 +139,28 @@ public:
{ return Collinear_3(); }
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
Equal_2
Equal_2
equal_2_object() const
{ return Equal_2(); }
Equal_3
Equal_3
equal_3_object() const
{ return Equal_3(); }
#endif // NOT CGAL_NO_EQUAL_3_STATIC_FILTERS
#ifndef CGAL_NO_COMPARE_X_2_STATIC_FILTERS
Compare_x_2
Compare_x_2
compare_x_2_object() const
{ return Compare_x_2(); }
Compare_y_2
Compare_y_2
compare_y_2_object() const
{ return Compare_y_2(); }
#endif // NOT CGAL_NO_COMPARE_Y_2_STATIC_FILTERS
#ifndef CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
Is_degenerate_3
Is_degenerate_3
is_degenerate_3_object() const
{ return Is_degenerate_3(); }
#endif // NOT CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
@ -182,7 +183,12 @@ Compare_y_2
compare_squared_radius_3_object() const
{ return Compare_squared_radius_3(); }
Power_side_of_oriented_power_sphere_3 power_side_of_oriented_power_sphere_3_object() const
Coplanar_3
coplanar_3_object() const
{ return Coplanar_3(); }
Power_side_of_oriented_power_sphere_3
power_side_of_oriented_power_sphere_3_object() const
{ return Power_side_of_oriented_power_sphere_3();}
Compare_weighted_squared_radius_3

View File

@ -18,6 +18,9 @@ Release date: June 2020
- **Breaking change**: the internal search tree is now lazily constructed. To disable it, one must call
the new function `do_not_accelerate_distance_queries()` before the first distance query.
### Intersecting Sequences of dD Iso-oriented Boxes
- Added parallel versions of the functions `CGAL::box_intersection_d()` and `CGAL::box_self_intersection_d()`.
### Polygon Mesh Processing
- Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`,
@ -28,6 +31,8 @@ Release date: June 2020
components that would be removed with the specified threshold, but without actually removing them.
- The function `CGAL::Polygon_mesh_processing::stitch_borders()` now returns the number
of halfedge pairs that were stitched.
- Added parallel versions of the functions `CGAL::Polygon_mesh_processing::does_self_intersect()`
and `CGAL::Polygon_mesh_processing::self_intersections()`.
### 2D Triangulations
- To fix an inconsistency between code and documentation and to clarify which types of intersections

View File

@ -488,7 +488,7 @@ CGAL_Kernel_pred_RT(Coplanar_orientation_3,
coplanar_orientation_3_object)
CGAL_Kernel_pred_RT(Coplanar_side_of_bounded_circle_3,
coplanar_side_of_bounded_circle_3_object)
CGAL_Kernel_pred(Coplanar_3,
CGAL_Kernel_pred_RT(Coplanar_3,
coplanar_3_object)
CGAL_Kernel_pred(Counterclockwise_in_between_2,
counterclockwise_in_between_2_object)

View File

@ -109,6 +109,7 @@ endif(OpenMesh_FOUND)
find_package( TBB )
if( TBB_FOUND )
CGAL_target_use_TBB(self_intersections_example)
CGAL_target_use_TBB(hausdorff_distance_remeshing_example)
else()
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )

View File

@ -2,12 +2,15 @@
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
#include <CGAL/Real_timer.h>
#include <CGAL/tags.h>
#include <iostream>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
namespace PMP = CGAL::Polygon_mesh_processing;
@ -20,20 +23,25 @@ int main(int argc, char* argv[])
if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh))
{
std::cerr << "Not a valid input file." << std::endl;
return 1;
return EXIT_FAILURE;
}
bool intersecting = PMP::does_self_intersect(mesh,
PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)));
std::cout << "Using parallel mode? " << std::is_same<CGAL::Parallel_if_available_tag, CGAL::Parallel_tag>::value << std::endl;
std::cout
<< (intersecting ? "There are self-intersections." : "There is no self-intersection.")
<< std::endl;
CGAL::Real_timer timer;
timer.start();
bool intersecting = PMP::does_self_intersect<CGAL::Parallel_if_available_tag>(mesh, CGAL::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)));
std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl;
std::cout << "Elapsed time (does self intersect): " << timer.time() << std::endl;
timer.reset();
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
PMP::self_intersections(mesh, std::back_inserter(intersected_tris));
PMP::self_intersections<CGAL::Parallel_if_available_tag>(faces(mesh), mesh, std::back_inserter(intersected_tris));
std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl;
return 0;
std::cout << "Elapsed time (self intersections): " << timer.time() << std::endl;
return EXIT_SUCCESS;
}

View File

@ -26,7 +26,6 @@
#include <CGAL/Filtered_predicate.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
#include <CGAL/Aff_transformation_3.h>
#include <boost/mpl/if.hpp>

View File

@ -15,7 +15,7 @@
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
#include <CGAL/property_map.h>
#include <CGAL/enum.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
@ -38,7 +38,9 @@ protected:
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
public:
Collect_face_bbox_per_edge_bbox(
@ -80,9 +82,12 @@ protected:
typedef boost::graph_traits<TriangleMesh> Graph_traits;
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
typedef typename boost::property_traits<VertexPointMap>::reference Point;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
public:
Collect_face_bbox_per_edge_bbox_with_coplanar_handling(
const TriangleMesh& tm_faces,
@ -162,7 +167,10 @@ protected:
typedef typename Graph_traits::face_descriptor face_descriptor;
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
typedef typename boost::property_traits<VertexPointMap>::reference Point;
bool is_edge_target_incident_to_face(halfedge_descriptor hd,

View File

@ -18,7 +18,6 @@
#include <boost/graph/graph_traits.hpp>
#include <CGAL/box_intersection_d.h>
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/Intersection_type.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_of_coplanar_triangles_3.h>
@ -156,7 +155,8 @@ class Intersection_of_triangle_meshes
typedef typename graph_traits::halfedge_descriptor halfedge_descriptor;
typedef typename graph_traits::vertex_descriptor vertex_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
typedef boost::unordered_set<face_descriptor> Face_set;
typedef boost::unordered_map<edge_descriptor, Face_set> Edge_to_faces;
@ -250,10 +250,11 @@ class Intersection_of_triangle_meshes
if (callback_si.self_intersections_found())
throw Self_intersection_exception();
}
else
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
callback, cutoff );
else {
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
callback, cutoff );
}
}
// for autorefinement

View File

@ -110,7 +110,8 @@ void collect_close_stitchable_boundary_edges(PM& pm,
typedef boost::unordered_map<halfedge_descriptor, int> Halfedge_multiplicity;
typedef std::vector<std::pair<halfedge_descriptor, halfedge_descriptor> > Halfedge_pairs;
typedef typename Box_intersection_d::Box_with_info_d<double, 3, edge_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, edge_descriptor, Box_policy> Box;
typedef Union_find<vertex_descriptor> UF_vertices;
typedef std::map<vertex_descriptor, typename UF_vertices::handle> Handle_map;
@ -141,7 +142,6 @@ void collect_close_stitchable_boundary_edges(PM& pm,
for(Box& b : boxes)
box_ptrs.push_back(&b);
Halfedge_multiplicity multiplicity;
Halfedge_pairs matching_hedges;

View File

@ -17,20 +17,27 @@
#include <CGAL/disable_warnings.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <boost/mpl/if.hpp>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <CGAL/box_intersection_d.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <boost/function_output_iterator.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/if.hpp>
#include <exception>
#include <iterator>
#include <utility>
#include <vector>
namespace CGAL {
namespace Polygon_mesh_processing{
namespace internal {
@ -401,8 +408,10 @@ compute_face_face_intersection(const FaceRange& face_range1,
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor, Box_policy> Box;
CGAL::Bbox_3 b1 = CGAL::Polygon_mesh_processing::bbox(tm1, np1),
b2 = CGAL::Polygon_mesh_processing::bbox(tm2, np2);
@ -414,12 +423,8 @@ compute_face_face_intersection(const FaceRange& face_range1,
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range1), boost::end(face_range1) )
);
boxes2.reserve(
std::distance( boost::begin(face_range2), boost::end(face_range2) )
);
boxes1.reserve(std::distance(boost::begin(face_range1), boost::end(face_range1)));
boxes2.reserve(std::distance(boost::begin(face_range2), boost::end(face_range2)));
typedef typename GetVertexPointMap<TM, NamedParameters1>::const_type VertexPointMap1;
typedef typename GetVertexPointMap<TM, NamedParameters2>::const_type VertexPointMap2;
@ -433,6 +438,7 @@ compute_face_face_intersection(const FaceRange& face_range1,
typename boost::property_traits<VertexPointMap1>::value_type,
typename boost::property_traits<VertexPointMap2>::value_type
>::value) );
for(face_descriptor f : face_range1)
{
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm1), f));
@ -449,7 +455,6 @@ compute_face_face_intersection(const FaceRange& face_range1,
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
typedef typename GetGeomTraits<TM, NamedParameters1>::type GeomTraits;
GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits), GeomTraits());
@ -459,10 +464,7 @@ compute_face_face_intersection(const FaceRange& face_range1,
Box,
OutputIterator,
VertexPointMap1,
VertexPointMap2> Intersect_faces(tm1, tm2,
out,
vpmap1, vpmap2,
gt);
VertexPointMap2> Intersect_faces(tm1, tm2, out, vpmap1, vpmap2, gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
@ -541,21 +543,16 @@ compute_face_polyline_intersection( const FaceRange& face_range,
typename boost::range_value<Polyline>::type>::value));
std::vector<face_descriptor> faces;
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
faces.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t, Box_policy> Box;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range), boost::end(face_range) )
);
boxes2.reserve(
std::distance( boost::begin(polyline), boost::end(polyline) ) - 1
);
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
boxes2.reserve(std::distance(boost::begin(polyline), boost::end(polyline)) - 1);
for(face_descriptor f : face_range)
{
@ -571,7 +568,6 @@ compute_face_polyline_intersection( const FaceRange& face_range,
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
@ -587,12 +583,7 @@ compute_face_polyline_intersection( const FaceRange& face_range,
OutputIterator,
Polyline,
VertexPointMap>
Intersect_face_polyline(tm,
faces,
polyline,
out,
vpmap,
gt);
Intersect_face_polyline(tm, faces, polyline, out, vpmap, gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
@ -672,34 +663,32 @@ compute_face_polylines_intersection(const FaceRange& face_range,
get_const_property_map(boost::vertex_point, tm));
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
typedef typename boost::range_value<PolylineRange>::type Polyline;
CGAL_static_assertion(
(boost::is_same<Point,
typename boost::range_value<Polyline>::type>::value));
CGAL_static_assertion((boost::is_same<Point, typename boost::range_value<Polyline>::type>::value));
std::vector<face_descriptor> faces;
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t>, Box_policy> Box;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range), boost::end(face_range) )
);
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
std::size_t polylines_size = 0;
for(Polyline poly : polyline_range)
{
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
}
boxes2.reserve( polylines_size );
boxes2.reserve(polylines_size);
for(face_descriptor f : face_range)
{
faces.push_back(f);
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), std::make_pair(0, faces.size()-1)));
}
std::size_t range_size = std::distance( boost::begin(polyline_range), boost::end(polyline_range) );
for(std::size_t j = 0; j < range_size; ++j)
{
@ -730,12 +719,7 @@ compute_face_polylines_intersection(const FaceRange& face_range,
PolylineRange,
OutputIterator,
VertexPointMap>
Intersect_face_polyline(tm,
faces,
polyline_range,
out,
vpmap,
gt);
Intersect_face_polyline(tm, faces, polyline_range, out, vpmap, gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
@ -773,18 +757,15 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
OutputIterator out,
const Kernel& K)
{
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t, Box_policy> Box;
typedef typename Kernel::Point_3 Point;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(polyline1), boost::end(polyline1) ) - 1
);
boxes2.reserve(
std::distance( boost::begin(polyline2), boost::end(polyline2) ) - 1
);
boxes1.reserve(std::distance(boost::begin(polyline1), boost::end(polyline1)) - 1);
boxes2.reserve(std::distance(boost::begin(polyline2), boost::end(polyline2)) - 1);
for(std::size_t i =0; i< polyline1.size()-1; ++i)
{
@ -813,10 +794,7 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
Kernel,
Box,
OutputIterator>
intersect_polylines(polyline1,
polyline2,
out,
K);
intersect_polylines(polyline1, polyline2, out, K);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
@ -856,7 +834,9 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
const Kernel& K)
{
//info.first is the index of the polyline in the range, info.second is the index of the point in the polyline
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t>, Box_policy> Box;
typedef typename Kernel::Point_3 Point;
typedef typename boost::range_value<PolylineRange>::type Polyline;
@ -871,6 +851,7 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
b1 += CGAL::bbox_3(poly.begin(), poly.end());
}
boxes1.reserve( polylines_size );
polylines_size = 0;
for(Polyline poly : polylines2)
{
@ -878,9 +859,10 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
b2 += CGAL::bbox_3(poly.begin(), poly.end());
}
boxes2.reserve(polylines_size);
if(!CGAL::do_overlap(b1,b2))
return out;
std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) );
for(std::size_t j = 0; j < range_size; ++j)
{
@ -915,15 +897,11 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
// compute intersections filtered out by boxes
internal::Intersect_polyline_ranges<PolylineRange,
Kernel,
Box,
OutputIterator>
intersect_polylines(polylines1,
polylines2,
out,
K);
intersect_polylines(polylines1, polylines2, out, K);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
@ -1595,7 +1573,9 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
bool report_overlap = choose_parameter(get_parameter(np, internal_np::overlap_test),false);
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, TriangleMeshIterator> Mesh_box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, TriangleMeshIterator, Box_policy> Mesh_box;
std::vector<Mesh_box> boxes;
boxes.reserve(std::distance(range.begin(), range.end()));
@ -1604,21 +1584,18 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
boxes.push_back( Mesh_box(Polygon_mesh_processing::bbox(*it), it) );
}
std::vector<Mesh_box*> boxes_ptr(
boost::make_counting_iterator(&boxes[0]),
boost::make_counting_iterator(&boxes[0]+boxes.size()));
std::vector<Mesh_box*> boxes_ptr(boost::make_counting_iterator(&boxes[0]),
boost::make_counting_iterator(&boxes[0]+boxes.size()));
typedef typename boost::range_value<NamedParametersRange>::type NP_rng;
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
typedef typename GetGeomTraits<TriangleMesh, NamedParameters, NP_rng>::type GT;
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
//get all the pairs of meshes intersecting (no strict inclusion test)
std::ptrdiff_t cutoff = 2000;
internal::Mesh_callback<TriangleMeshRange, GT, OutputIterator, NamedParametersRange> callback(range, out, report_overlap, gt, nps);
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
callback, cutoff);
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), callback, cutoff);
return callback.m_iterator;
}
@ -1634,7 +1611,7 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
template <class TriangleMeshRange, class OutputIterator>
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
OutputIterator out)
OutputIterator out)
{
return intersecting_meshes(range, out, parameters::all_default());
}
@ -1827,9 +1804,10 @@ surface_self_intersection(const TriangleMesh& tm,
CGAL::Polygon_mesh_processing::parameters::all_default()
);
}
} //end of namespace experimental
} } //end of namespace CGAL::Polygon_mesh_processing
} //end of namespace experimental
} //end of namespace Polygon_mesh_processing
} //end of namespace CGAL
#include <CGAL/enable_warnings.h>

View File

@ -21,215 +21,378 @@
#include <CGAL/disable_warnings.h>
#include <CGAL/box_intersection_d.h>
#include <CGAL/intersections.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Kernel/global_functions_3.h>
#include <vector>
#include <exception>
#include <boost/range.hpp>
#include <boost/function_output_iterator.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/graph/graph_traits.hpp>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/algorithm.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/boost/graph/properties.h>
#include <CGAL/box_intersection_d.h>
#include <CGAL/exceptions.h>
#include <CGAL/intersections.h>
#include <CGAL/iterator.h>
#include <CGAL/Kernel/global_functions_3.h>
#include <CGAL/Random.h>
#include <CGAL/use.h>
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/concurrent_vector.h>
#endif
#include <boost/function_output_iterator.hpp>
#include <exception>
#include <sstream>
#include <type_traits>
#include <vector>
#ifdef DOXYGEN_RUNNING
#define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters
#define CGAL_PMP_NP_CLASS NamedParameters
#endif
namespace CGAL {
namespace Polygon_mesh_processing {
namespace internal {
template <class TM,//TriangleMesh
class Kernel,
class Box,
class OutputIterator,
class VertexPointMap>
struct Intersect_facets
{
// wrapper to check whether anything is inserted to output iterator
struct Output_iterator_with_bool
{
Output_iterator_with_bool(OutputIterator* out, bool* intersected)
: m_iterator(out), m_intersected(intersected) { }
template<class T>
void operator()(const T& t) {
*m_intersected = true;
*(*m_iterator)++ = t;
// Checks for 'real' intersections, i.e. not simply a shared vertex or edge
template <class GT, class TM, class VPM>
bool do_faces_intersect(typename boost::graph_traits<TM>::halfedge_descriptor h,
typename boost::graph_traits<TM>::halfedge_descriptor g,
const TM& tmesh,
const VPM vpmap,
const typename GT::Construct_segment_3& construct_segment,
const typename GT::Construct_triangle_3& construct_triangle,
const typename GT::Do_intersect_3& do_intersect)
{
typedef typename boost::graph_traits<TM>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename GT::Segment_3 Segment;
typedef typename GT::Triangle_3 Triangle;
CGAL_assertion(!is_border(h, tmesh));
CGAL_assertion(!is_border(g, tmesh));
vertex_descriptor hv[3], gv[3];
hv[0] = target(h, tmesh);
hv[1] = target(next(h, tmesh), tmesh);
hv[2] = source(h, tmesh);
gv[0] = target(g, tmesh);
gv[1] = target(next(g, tmesh), tmesh);
gv[2] = source(g, tmesh);
// check for shared edge
for(unsigned int i=0; i<3; ++i)
{
halfedge_descriptor opp_h = opposite(h, tmesh);
if(face(opp_h, tmesh) == face(g, tmesh))
{
// there is an intersection if the four points are coplanar and the triangles overlap
if(CGAL::coplanar(get(vpmap, hv[i]),
get(vpmap, hv[(i+1)%3]),
get(vpmap, hv[(i+2)%3]),
get(vpmap, target(next(opp_h, tmesh), tmesh))) &&
CGAL::coplanar_orientation(get(vpmap, hv[(i+2)%3]),
get(vpmap, hv[i]),
get(vpmap, hv[(i+1)%3]),
get(vpmap, target(next(opp_h, tmesh), tmesh)))
== CGAL::POSITIVE)
{
return true;
}
else
{
// there is a shared edge but no intersection
return false;
}
}
OutputIterator* m_iterator;
bool* m_intersected;
};
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Triangle_3 Triangle;
h = next(h, tmesh);
}
// check for shared vertex --> maybe intersection, maybe not
int i(0), j(0);
bool shared = false;
for(; i<3 && (! shared); ++i)
{
for(j=0; j<3 && (! shared); ++j)
{
if(hv[i] == gv[j])
{
shared = true;
break;
}
}
if(shared)
break;
}
if(shared)
{
// found shared vertex:
CGAL_assertion(hv[i] == gv[j]);
// geometric check if the opposite segments intersect the triangles
const Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2]));
const Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2]));
const Segment s1 = construct_segment(get(vpmap, hv[(i+1)%3]), get(vpmap, hv[(i+2)%3]));
const Segment s2 = construct_segment(get(vpmap, gv[(j+1)%3]), get(vpmap, gv[(j+2)%3]));
if(do_intersect(t1, s2))
return true;
else if(do_intersect(t2, s1))
return true;
return false;
}
// check for geometric intersection
const Triangle th = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2]));
const Triangle tg = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2]));
if(do_intersect(th, tg))
return true;
return false;
};
template <class Box, class TM, class VPM, class GT,
class OutputIterator>
struct Strict_intersect_faces // "strict" as in "not sharing a subface"
{
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::property_map<TM, boost::vertex_point_t>::const_type Ppmap;
// members
mutable OutputIterator m_iterator;
const TM& m_tmesh;
const VertexPointMap m_vpmap;
mutable OutputIterator m_iterator;
mutable bool m_intersected;
mutable boost::function_output_iterator<Output_iterator_with_bool> m_iterator_wrapper;
const VPM m_vpmap;
typename GT::Construct_segment_3 m_construct_segment;
typename GT::Construct_triangle_3 m_construct_triangle;
typename GT::Do_intersect_3 m_do_intersect;
typename Kernel::Construct_segment_3 segment_functor;
typename Kernel::Construct_triangle_3 triangle_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_facets(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel)
Strict_intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it)
:
m_tmesh(tmesh),
m_vpmap(vpmap),
m_iterator(it),
m_intersected(false),
m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)),
segment_functor(kernel.construct_segment_3_object()),
triangle_functor(kernel.construct_triangle_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
m_iterator(it),
m_tmesh(tmesh),
m_vpmap(vpmap),
m_construct_segment(gt.construct_segment_3_object()),
m_construct_triangle(gt.construct_triangle_3_object()),
m_do_intersect(gt.do_intersect_3_object())
{}
void operator()(const Box* b, const Box* c) const
{
halfedge_descriptor h = halfedge(b->info(), m_tmesh);
halfedge_descriptor opp_h;
const halfedge_descriptor h = halfedge(b->info(), m_tmesh);
const halfedge_descriptor g = halfedge(c->info(), m_tmesh);
// check for shared egde
for(unsigned int i=0; i<3; ++i){
opp_h = opposite(h, m_tmesh);
if(face(opp_h, m_tmesh) == c->info()){
// there is an intersection if the four points are coplanar and
// the triangles overlap
if(CGAL::coplanar(get(m_vpmap, target(h, m_tmesh)),
get(m_vpmap, target(next(h, m_tmesh), m_tmesh)),
get(m_vpmap, source(h, m_tmesh)),
get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) &&
CGAL::coplanar_orientation(get(m_vpmap, source(h, m_tmesh)),
get(m_vpmap, target(h, m_tmesh)),
get(m_vpmap, target(next(h, m_tmesh), m_tmesh)),
get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)))
== CGAL::POSITIVE){
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
return;
} else { // there is a shared edge but no intersection
return;
}
}
h = next(h, m_tmesh);
}
// check for shared vertex --> maybe intersection, maybe not
halfedge_descriptor g = halfedge(c->info(),m_tmesh);
halfedge_descriptor v;
if(target(h,m_tmesh) == target(g,m_tmesh))
v = g;
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
v = next(g,m_tmesh);
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
v = next(next(g,m_tmesh),m_tmesh);
if(v == halfedge_descriptor()){
h = next(h,m_tmesh);
if(target(h,m_tmesh) == target(g,m_tmesh))
v = g;
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
v = next(g,m_tmesh);
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
v = next(next(g,m_tmesh),m_tmesh);
if(v == halfedge_descriptor()){
h = next(h,m_tmesh);
if(target(h,m_tmesh) == target(g,m_tmesh))
v = g;
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
v = next(g,m_tmesh);
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
v = next(next(g,m_tmesh),m_tmesh);
}
}
if(v != halfedge_descriptor()){
// found shared vertex:
CGAL_assertion(target(h,m_tmesh) == target(v,m_tmesh));
// geometric check if the opposite segments intersect the triangles
Triangle t1 = triangle_functor( get(m_vpmap,target(h,m_tmesh)),
get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
Triangle t2 = triangle_functor( get(m_vpmap, target(v,m_tmesh)),
get(m_vpmap, target(next(v,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh)));
Segment s1 = segment_functor( get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
Segment s2 = segment_functor( get(m_vpmap, target(next(v,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh)));
if(do_intersect_3_functor(t1,s2)){
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
} else if(do_intersect_3_functor(t2,s1)){
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
}
return;
}
// check for geometric intersection
Triangle t1 = triangle_functor( get(m_vpmap, target(h,m_tmesh)),
get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
Triangle t2 = triangle_functor( get(m_vpmap, target(g,m_tmesh)),
get(m_vpmap, target(next(g,m_tmesh),m_tmesh)),
get(m_vpmap, target(next(next(g,m_tmesh),m_tmesh),m_tmesh)));
if(do_intersect_3_functor(t1, t2)){
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
}
} // end operator ()
}; // end struct Intersect_facets
struct Throw_at_output {
class Throw_at_output_exception: public std::exception
{ };
template<class T>
void operator()(const T& /* t */) const {
throw Throw_at_output_exception();
if(do_faces_intersect<GT>(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect))
*m_iterator++ = std::make_pair(b->info(), c->info());
}
};
}// namespace internal
template <class ConcurrencyTag,
class TriangleMesh,
class FaceRange,
class FacePairOutputIterator,
class NamedParameters>
FacePairOutputIterator
self_intersections_impl(const FaceRange& face_range,
const TriangleMesh& tmesh,
FacePairOutputIterator out,
const bool throw_on_SI,
const NamedParameters& np)
{
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
namespace Polygon_mesh_processing {
using CGAL::parameters::choose_parameter;
using CGAL::parameters::get_parameter;
#ifndef DOXYGEN_RUNNING
template <class TriangleMesh
, class FaceRange
, class OutputIterator
, class NamedParameters
>
OutputIterator
self_intersections( const FaceRange& face_range,
const TriangleMesh& tmesh,
OutputIterator out,
const NamedParameters& np);
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor, Box_policy> Box;
typedef typename GetGeomTraits<TM, NamedParameters>::type GT;
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VPM;
VPM vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tmesh));
const unsigned int seed = choose_parameter(get_parameter(np, internal_np::random_seed), 0);
CGAL_USE(seed); // used in the random shuffle of the range, which is only done to balance tasks in parallel
const std::ptrdiff_t cutoff = 2000;
// make one box per face
std::vector<Box> boxes;
boxes.reserve(std::distance(std::begin(face_range), std::end(face_range)));
// This loop is very cheap, so there is hardly anything to gain from parallelizing it
for(face_descriptor f : face_range)
{
halfedge_descriptor h = halfedge(f, tmesh);
typename boost::property_traits<VPM>::reference
p = get(vpmap, target(h,tmesh)),
q = get(vpmap, target(next(h, tmesh), tmesh)),
r = get(vpmap, target(prev(h, tmesh), tmesh));
// tiny fixme: if f is degenerate, we might still have a real intersection between f
// and another face f', but right now we are not creating a box for f and thus not returning those
if(collinear(p, q, r))
{
if(throw_on_SI)
throw CGAL::internal::Throw_at_output_exception();
else
*out++= std::make_pair(f, f);
}
else
{
boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f));
}
}
// generate box pointers
std::vector<const Box*> box_ptr;
box_ptr.reserve(boxes.size());
for(Box& b : boxes)
box_ptr.push_back(&b);
// In case we are throwing, like in `does_self_intersect()`, we keep the geometric test to throw ASAP.
// This is obviously not optimal if there are no or few self-intersections: it would be a greater speed-up
// to do the same as for `self_intersections()`. However, doing like `self_intersections()` would
// be a major slow-down over sequential code if there are a lot of self-intersections...
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> Throwing_output_iterator;
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, Throwing_output_iterator> Throwing_filter;
Throwing_filter throwing_filter(tmesh, vpmap, gt, Throwing_output_iterator());
#if !defined(CGAL_LINKED_WITH_TBB)
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value),
"Parallel_tag is enabled but TBB is unavailable.");
#else
if(std::is_convertible<ConcurrencyTag, Parallel_tag>::value)
{
// We are going to split the range into a number of smaller ranges. To handle
// smaller trees of roughly the same size, we first apply a random shuffle to the range
CGAL::Random rng(seed);
CGAL::cpp98::random_shuffle(box_ptr.begin(), box_ptr.end(), rng);
// Write in a concurrent vector all pairs that intersect
typedef tbb::concurrent_vector<std::pair<face_descriptor, face_descriptor> > Face_pairs;
typedef std::back_insert_iterator<Face_pairs> Face_pairs_back_inserter;
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, Face_pairs_back_inserter> Intersecting_faces_filter;
Face_pairs face_pairs;
Intersecting_faces_filter callback(tmesh, vpmap, gt, std::back_inserter(face_pairs));
if(throw_on_SI)
CGAL::box_self_intersection_d<ConcurrencyTag>(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff);
else
CGAL::box_self_intersection_d<ConcurrencyTag>(box_ptr.begin(), box_ptr.end(), callback, cutoff);
// Sequentially write into the output iterator
for(std::size_t i=0; i<face_pairs.size(); ++i)
*out ++= face_pairs[i];
return out;
}
#endif
// Sequential version of the code
// Compute self-intersections filtered out by boxes
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, FacePairOutputIterator> Intersecting_faces_filter;
Intersecting_faces_filter intersect_faces(tmesh, vpmap, gt, out);
if(throw_on_SI)
CGAL::box_self_intersection_d<CGAL::Sequential_tag>(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff);
else
CGAL::box_self_intersection_d<CGAL::Sequential_tag>(box_ptr.begin(), box_ptr.end(), intersect_faces, cutoff);
return intersect_faces.m_iterator;
}
} // namespace internal
/*!
* \ingroup PMP_intersection_grp
* collects intersections between a subset of faces of a triangulated surface mesh.
* Two faces are said to intersect if the corresponding triangles intersect
* and the intersection is not an edge nor a vertex incident to both faces.
*
* This function depends on the package \ref PkgBoxIntersectionD
*
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
* @tparam FaceRange a model of `ConstRange` with value type `boost::graph_traits<TriangleMesh>::%face_descriptor`.
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
* @param face_range the range of faces to check for self-intersection.
* @param tmesh the triangulated surface mesh to be checked
* @param out output iterator to be filled with all pairs of non-adjacent faces that intersect
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*/
template < class ConcurrencyTag = Sequential_tag,
class TriangleMesh,
class FaceRange,
class FacePairOutputIterator,
class NamedParameters>
FacePairOutputIterator
self_intersections(const FaceRange& face_range,
const TriangleMesh& tmesh,
FacePairOutputIterator out,
const NamedParameters& np)
{
return internal::self_intersections_impl<ConcurrencyTag>(face_range, tmesh, out, false /*don't throw*/, np);
}
/// \cond SKIP_IN_MANUAL
template <class ConcurrencyTag = Sequential_tag,
class TriangleMesh,
class FaceRange,
class FacePairOutputIterator>
FacePairOutputIterator
self_intersections(const FaceRange& face_range,
const TriangleMesh& tmesh,
FacePairOutputIterator out)
{
return self_intersections<ConcurrencyTag>(face_range, tmesh, out, CGAL::parameters::all_default());
}
/// \endcond
/**
* \ingroup PMP_intersection_grp
* detects and records self-intersections of a triangulated surface mesh.
* collects intersections between all the faces of a triangulated surface mesh.
* Two faces are said to intersect if the corresponding triangles intersect
* and the intersection is not an edge nor a vertex incident to both faces.
*
* This function depends on the package \ref PkgBoxIntersectionD
*
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam OutputIterator a model of `OutputIterator` holding objects of type
* @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
@ -249,181 +412,35 @@ self_intersections( const FaceRange& face_range,
*
* @return `out`
*/
template <class TriangleMesh
, class OutputIterator
#ifdef DOXYGEN_RUNNING
, class NamedParameters
#else //avoid ambiguity with self_intersections(faces, tmesh, out)
, class P, class T, class R
#endif
>
OutputIterator
self_intersections(const TriangleMesh& tmesh
, OutputIterator out
#ifdef DOXYGEN_RUNNING
, const NamedParameters& np)
#else
, const Named_function_parameters<P,T,R>& np)
#endif
template <class ConcurrencyTag = Sequential_tag,
class TriangleMesh,
class FacePairOutputIterator,
class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
FacePairOutputIterator
self_intersections(const TriangleMesh& tmesh,
FacePairOutputIterator out,
const CGAL_PMP_NP_CLASS& np)
{
return self_intersections(faces(tmesh), tmesh, out, np);
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, np);
}
/// \cond SKIP_IN_MANUAL
template <class TriangleMesh, class OutputIterator>
OutputIterator
self_intersections(const TriangleMesh& tmesh, OutputIterator out)
template <class ConcurrencyTag = Sequential_tag, class TriangleMesh, class FacePairOutputIterator>
FacePairOutputIterator
self_intersections(const TriangleMesh& tmesh, FacePairOutputIterator out)
{
return self_intersections(tmesh, out,
CGAL::Polygon_mesh_processing::parameters::all_default());
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, parameters::all_default());
}
/// \endcond
/*!
* \ingroup PMP_intersection_grp
* Same as above but the self-intersections reported
* are only limited to the faces in `face_range`.
*
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
* model of `Range`.
* Its iterator type is `RandomAccessIterator`.
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
* @param face_range the range of faces to check for self-intersection.
* @param tmesh the triangulated surface mesh to be checked
* @param out output iterator to be filled with all pairs of non-adjacent faces that intersect
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*/
template <class TriangleMesh
, class FaceRange
, class OutputIterator
, class NamedParameters
>
OutputIterator
self_intersections( const FaceRange& face_range,
const TriangleMesh& tmesh,
OutputIterator out,
const NamedParameters& np)
{
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor> Box;
// make one box per facet
std::vector<Box> boxes;
boxes.reserve(
std::distance( boost::begin(face_range), boost::end(face_range) )
);
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VertexPointMap;
VertexPointMap vpmap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tmesh));
for(face_descriptor f : face_range)
{
typename boost::property_traits<VertexPointMap>::reference
p = get(vpmap, target(halfedge(f,tmesh),tmesh)),
q = get(vpmap, target(next(halfedge(f, tmesh), tmesh), tmesh)),
r = get(vpmap, target(next(next(halfedge(f, tmesh), tmesh), tmesh), tmesh));
if ( collinear(p, q, r) )
*out++= std::make_pair(f,f);
else
boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f));
}
// generate box pointers
std::vector<const Box*> box_ptr;
box_ptr.reserve(num_faces(tmesh));
for(Box& b : boxes)
box_ptr.push_back(&b);
// compute self-intersections filtered out by boxes
typedef typename GetGeomTraits<TM, NamedParameters>::type GeomTraits;
CGAL::internal::Intersect_facets<TM,GeomTraits,Box,OutputIterator,VertexPointMap>
intersect_facets(tmesh, out, vpmap,
parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits()));
std::ptrdiff_t cutoff = 2000;
CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff);
return intersect_facets.m_iterator;
}
/// \cond SKIP_IN_MANUAL
template <class TriangleMesh
, class FaceRange
, class OutputIterator
>
OutputIterator self_intersections(const FaceRange& face_range,
const TriangleMesh& tmesh,
OutputIterator out)
{
return self_intersections(face_range, tmesh, out,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
/// \endcond
/**
* \ingroup PMP_intersection_grp
* tests if a triangulated surface mesh self-intersects.
* This function depends on the package \ref PkgBoxIntersectionD
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
* @param tmesh the triangulated surface mesh to be tested
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*
* @return true if `tmesh` self-intersects
*/
template <class TriangleMesh
, class CGAL_PMP_NP_TEMPLATE_PARAMETERS
>
bool does_self_intersect(const TriangleMesh& tmesh
, const CGAL_PMP_NP_CLASS& np)
{
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
try
{
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> OutputIterator;
self_intersections(tmesh, OutputIterator(), np);
}
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
{ return true; }
return false;
}
/**
* \ingroup PMP_intersection_grp
* tests if a set of faces of a triangulated surface mesh self-intersects.
* This function depends on the package \ref PkgBoxIntersectionD
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
* @tparam FaceRange a range of `face_descriptor`
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
@ -439,12 +456,12 @@ bool does_self_intersect(const TriangleMesh& tmesh
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `SelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*
* @return true if the faces in `face_range` self-intersect
* @return `true` if the faces in `face_range` self-intersect
*/
template <class FaceRange,
template <class ConcurrencyTag = Sequential_tag,
class FaceRange,
class TriangleMesh,
class NamedParameters
>
class NamedParameters>
bool does_self_intersect(const FaceRange& face_range,
const TriangleMesh& tmesh,
const NamedParameters& np)
@ -453,35 +470,65 @@ bool does_self_intersect(const FaceRange& face_range,
try
{
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> OutputIterator;
self_intersections(face_range, tmesh, OutputIterator(), np);
CGAL::Emptyset_iterator unused_out;
internal::self_intersections_impl<ConcurrencyTag>(face_range, tmesh, unused_out, true /*throw*/, np);
}
catch(CGAL::internal::Throw_at_output_exception&)
{
return true;
}
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
{ return true; }
return false;
}
/// \cond SKIP_IN_MANUAL
template <class TriangleMesh>
bool does_self_intersect(const TriangleMesh& tmesh)
/**
* \ingroup PMP_intersection_grp
* tests if a triangulated surface mesh self-intersects.
* This function depends on the package \ref PkgBoxIntersectionD
* @pre `CGAL::is_triangle_mesh(tmesh)`
*
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
*
* @param tmesh the triangulated surface mesh to be tested
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*
* @return `true` if `tmesh` self-intersects
*/
template <class ConcurrencyTag = Sequential_tag,
class TriangleMesh,
class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
bool does_self_intersect(const TriangleMesh& tmesh,
const CGAL_PMP_NP_CLASS& np)
{
return does_self_intersect(tmesh,
CGAL::Polygon_mesh_processing::parameters::all_default());
return does_self_intersect<ConcurrencyTag>(faces(tmesh), tmesh, np);
}
template <class FaceRange, class TriangleMesh>
/// \cond SKIP_IN_MANUAL
template <class ConcurrencyTag = Sequential_tag, class TriangleMesh>
bool does_self_intersect(const TriangleMesh& tmesh)
{
return does_self_intersect<ConcurrencyTag>(faces(tmesh), tmesh, CGAL::parameters::all_default());
}
template <class ConcurrencyTag = Sequential_tag, class FaceRange, class TriangleMesh>
bool does_self_intersect(const FaceRange& face_range,
const TriangleMesh& tmesh)
{
return does_self_intersect(face_range, tmesh,
CGAL::Polygon_mesh_processing::parameters::all_default());
return does_self_intersect<ConcurrencyTag>(face_range, tmesh, CGAL::parameters::all_default());
}
/// \endcond
}// end namespace Polygon_mesh_processing
}// namespace Polygon_mesh_processing
}// namespace CGAL
#include <CGAL/enable_warnings.h>

View File

@ -101,6 +101,7 @@ endif()
if( TBB_FOUND )
CGAL_target_use_TBB(test_pmp_distance)
CGAL_target_use_TBB(self_intersection_surface_mesh_test)
else()
message( STATUS "NOTICE: Intel TBB was not found. test_pmp_distance will use sequential code." )
endif()

View File

@ -1,22 +1,25 @@
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
#include <CGAL/tags.h>
#include <CGAL/Timer.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic;
typedef CGAL::Exact_predicates_exact_constructions_kernel Epec;
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK;
namespace PMP = ::CGAL::Polygon_mesh_processing;
namespace CP = ::CGAL::parameters;
template <typename K>
int
test_self_intersections(const char* filename, const bool expected)
int test_self_intersections(const char* filename,
const bool expected)
{
typedef CGAL::Surface_mesh<typename K::Point_3> Mesh;
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
@ -35,18 +38,36 @@ test_self_intersections(const char* filename, const bool expected)
timer.start();
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
CGAL::Polygon_mesh_processing::self_intersections(
m,
std::back_inserter(intersected_tris),
CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m)));
if(std::is_same<K, EPECK>::value) // EPECK isn't threadsafe
{
PMP::self_intersections<CGAL::Sequential_tag>(
m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m)));
}
else
{
PMP::self_intersections<CGAL::Parallel_if_available_tag>(
m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m)));
}
bool intersecting_1 = !intersected_tris.empty();
std::cout << "self_intersections test took " << timer.time() << " sec." << std::endl;
std::cout << intersected_tris.size() << " pairs of triangles are intersecting." << std::endl;
timer.reset();
bool intersecting_2 = CGAL::Polygon_mesh_processing::does_self_intersect(m,
CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m)));
bool intersecting_2;
if(std::is_same<K, EPECK>::value) // EPECK isn't threadsafe
{
intersecting_2 = PMP::does_self_intersect<CGAL::Sequential_tag>(
m, CP::vertex_index_map(get(CGAL::vertex_point, m)));
}
else
{
intersecting_2 = PMP::does_self_intersect<CGAL::Parallel_if_available_tag>(
m, CP::vertex_index_map(get(CGAL::vertex_point, m)));
}
std::cout << "does_self_intersect test took " << timer.time() << " sec." << std::endl;
std::cout << (intersecting_2 ? "There is a self-intersection." :
@ -77,11 +98,11 @@ int main(int argc, char** argv)
assert(!ss.fail()); // make sure that argv[2] is either 'true' or 'false'
}
std::cout << "First test (Epic):" << std::endl;
int r = test_self_intersections<Epic>(filename, expected);
std::cout << "First test (EPICK):" << std::endl;
int r = test_self_intersections<EPICK>(filename, expected);
std::cout << "First test (Epec):" << std::endl;
r += test_self_intersections<Epec>(filename, expected);
std::cout << "First test (EPECK):" << std::endl;
r += test_self_intersections<EPECK>(filename, expected);
// Second test ---------------------------------------------------------------
expected = true;
@ -93,11 +114,11 @@ int main(int argc, char** argv)
assert(!ss.fail());
}
std::cout << "Second test (Epic):" << std::endl;
r += test_self_intersections<Epic>(filename, expected);
std::cout << "Second test (EPICK):" << std::endl;
r += test_self_intersections<EPICK>(filename, expected);
std::cout << "Second test (Epec):" << std::endl;
r += test_self_intersections<Epec>(filename, expected);
std::cout << "Second test (EPECK):" << std::endl;
r += test_self_intersections<EPECK>(filename, expected);
// Third test ----------------------------------------------------------------
expected = true;
@ -109,11 +130,11 @@ int main(int argc, char** argv)
assert(!ss.fail());
}
std::cout << "Third test (Epic):" << std::endl;
r += test_self_intersections<Epic>(filename, expected);
std::cout << "Third test (EPICK):" << std::endl;
r += test_self_intersections<EPICK>(filename, expected);
std::cout << "Third test (Epec):" << std::endl;
r += test_self_intersections<Epec>(filename, expected);
std::cout << "Third test (EPECK):" << std::endl;
r += test_self_intersections<EPECK>(filename, expected);
// Fourth test ----------------------------------------------------------------
expected = true;
@ -125,11 +146,11 @@ int main(int argc, char** argv)
assert(!ss.fail());
}
std::cout << "Fourth test (Epic):" << std::endl;
r += test_self_intersections<Epic>(filename, expected);
std::cout << "Fourth test (EPICK):" << std::endl;
r += test_self_intersections<EPICK>(filename, expected);
std::cout << "Fourth test (Epec):" << std::endl;
r += test_self_intersections<Epec>(filename, expected);
std::cout << "Fourth test (EPECK):" << std::endl;
r += test_self_intersections<EPECK>(filename, expected);
return r;
}

View File

@ -251,7 +251,10 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND)
add_item(scene_edit_box_item Plugins/PCA/Scene_edit_box_item.cpp )
add_item(scene_image_item Scene_image_item.cpp)
add_item(scene_surface_mesh_item Scene_surface_mesh_item.cpp)
if(TBB_FOUND)
CGAL_target_use_TBB(scene_surface_mesh_item)
endif()
# special
add_item(scene_item_decorator Scene_polyhedron_item_decorator.cpp )
@ -262,6 +265,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND)
add_item(scene_selection_item Scene_polyhedron_selection_item.cpp)
target_link_libraries(scene_selection_item PUBLIC scene_item_decorator scene_k_ring_selection)
if(TBB_FOUND)
CGAL_target_use_TBB(scene_selection_item)
endif()
add_item(scene_shortest_path_item Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp)
target_link_libraries(scene_shortest_path_item PUBLIC scene_item_decorator scene_surface_mesh_item scene_polylines_item)

View File

@ -9,13 +9,16 @@
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
#include <CGAL/Three/Three.h>
#include <fstream>
#include <CGAL/exceptions.h>
#include <CGAL/IO/File_scanner_OFF.h>
#include <CGAL/IO/OBJ_reader.h>
#include <QMessageBox>
#include <QApplication>
#include <iostream>
#include <fstream>
using namespace CGAL::Three;
class Polyhedron_demo_off_plugin :
public QObject,
@ -186,7 +189,7 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) {
try{
CGAL::Polygon_mesh_processing::non_manifold_vertices(*surface_mesh, OutputIterator());
}
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
catch( CGAL::internal::Throw_at_output_exception& )
{
QApplication::restoreOverrideCursor();

View File

@ -2497,7 +2497,7 @@ QString Scene_polyhedron_selection_item::computeStats(int type)
return QString("n/a");
if(is_triangle_mesh(*d->poly)){
bool self_intersect
= CGAL::Polygon_mesh_processing::does_self_intersect(*(d->poly));
= CGAL::Polygon_mesh_processing::does_self_intersect<CGAL::Parallel_if_available_tag>(*(d->poly));
if (self_intersect)
return QString("Yes");
else

View File

@ -33,6 +33,7 @@
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include "triangulate_primitive.h"
#include <CGAL/exceptions.h>
#include <CGAL/IO/File_writer_wavefront.h>
#include <CGAL/IO/generic_copy_OFF.h>
#include <CGAL/IO/OBJ_reader.h>
@ -1581,7 +1582,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
try{
CGAL::Polygon_mesh_processing::non_manifold_vertices(*d->smesh_, OutputIterator());
}
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
catch( CGAL::internal::Throw_at_output_exception& )
{
d->has_nm_vertices = true;
}
@ -1659,7 +1660,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
{
//todo : add a test about cache validity
if(is_triangle_mesh(*d->smesh_))
d->self_intersect = CGAL::Polygon_mesh_processing::does_self_intersect(*(d->smesh_));
d->self_intersect = CGAL::Polygon_mesh_processing::does_self_intersect<CGAL::Parallel_if_available_tag>(*(d->smesh_));
if (d->self_intersect)
return QString("Yes");
else if(is_triangle_mesh(*d->smesh_))

View File

@ -185,7 +185,19 @@ public:
"warning condition failed") {}
};
namespace internal {
// The following classes are useful to create output iterators (with the help
// of boost::function_output_iterator) that will throw as soon as something is being written.
class Throw_at_output_exception : public std::exception { };
struct Throw_at_output
{
template<class T>
void operator()(const T& /* t */) const { throw Throw_at_output_exception(); }
};
} // namespace internal
} //namespace CGAL
#endif // CGAL_EXCEPTIONS_H

View File

@ -113,7 +113,8 @@ class Intersect_facets
typename Kernel::Construct_triangle_2 triangle_functor;
typename Kernel::Do_intersect_2 do_intersect_2_functor;
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor, Box_policy> Box;
const TriangleMesh& mesh;
const VertexUVMap uvmap;
@ -250,7 +251,8 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
typedef typename Kernel::FT NT;
typedef typename Kernel::Point_2 Point_2;
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor> Box;
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor, Box_policy> Box;
// Create the corresponding vector of bounding boxes
std::vector<Box> boxes;
@ -283,8 +285,7 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
unsigned int counter = 0;
Intersect_facets<TriangleMesh, VertexUVMap> intersect_facets(mesh, uvmap, counter);
std::ptrdiff_t cutoff = 2000;
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
intersect_facets, cutoff);
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), intersect_facets, cutoff);
return (counter == 0);
}