mirror of https://github.com/CGAL/cgal
Merge pull request #4362 from afabri/Box_intersection_d-accelerate-GF
PMP::self_intersections: Add Concurrency
This commit is contained in:
commit
49a06e9201
|
|
@ -242,6 +242,29 @@ void box_intersection_all_pairs_d(
|
||||||
cutoff parameters are recommended. See also
|
cutoff parameters are recommended. See also
|
||||||
Section \ref secboxintersperformance .
|
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}
|
\cgalHeading{Example}
|
||||||
|
|
||||||
The box implementation provided with
|
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 RandomAccessIterator2,
|
||||||
class Callback >
|
class Callback >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
|
|
@ -291,7 +315,8 @@ void box_intersection_d(
|
||||||
Invocation with custom box traits.
|
Invocation with custom box traits.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
template< class RandomAccessIterator1,
|
template< class ConcurrencyTag = CGAL::Sequential_tag,
|
||||||
|
class RandomAccessIterator1,
|
||||||
class RandomAccessIterator2,
|
class RandomAccessIterator2,
|
||||||
class Callback, class BoxTraits >
|
class Callback, class BoxTraits >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
|
|
@ -489,8 +514,11 @@ namespace CGAL {
|
||||||
|
|
||||||
\cgalHeading{Implementation}
|
\cgalHeading{Implementation}
|
||||||
|
|
||||||
See the implementation section of the `box_intersection_d()`
|
See the implementation section of the `box_intersection_d()` function.
|
||||||
function.
|
|
||||||
|
\cgalHeading{Concurrency}
|
||||||
|
|
||||||
|
See the concurrency section of the `box_intersection_d()` function.
|
||||||
|
|
||||||
\cgalHeading{Example}
|
\cgalHeading{Example}
|
||||||
|
|
||||||
|
|
@ -520,7 +548,8 @@ namespace CGAL {
|
||||||
`RandomAccessIterator`.
|
`RandomAccessIterator`.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
template< class RandomAccessIterator, class Callback >
|
template< class ConcurrencyTag = CGAL::Sequential_tag,
|
||||||
|
class RandomAccessIterator, class Callback >
|
||||||
void box_self_intersection_d(
|
void box_self_intersection_d(
|
||||||
RandomAccessIterator begin, RandomAccessIterator end,
|
RandomAccessIterator begin, RandomAccessIterator end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
|
|
@ -532,7 +561,8 @@ void box_self_intersection_d(
|
||||||
|
|
||||||
Invocation with custom box traits.
|
Invocation with custom box traits.
|
||||||
*/
|
*/
|
||||||
template< class RandomAccessIterator,
|
template< class ConcurrencyTag = CGAL::Sequential_tag
|
||||||
|
class RandomAccessIterator,
|
||||||
class Callback, class BoxTraits >
|
class Callback, class BoxTraits >
|
||||||
void box_self_intersection_d(
|
void box_self_intersection_d(
|
||||||
RandomAccessIterator begin, RandomAccessIterator end,
|
RandomAccessIterator begin, RandomAccessIterator end,
|
||||||
|
|
|
||||||
|
|
@ -16,34 +16,34 @@
|
||||||
|
|
||||||
#include <CGAL/license/Box_intersection_d.h>
|
#include <CGAL/license/Box_intersection_d.h>
|
||||||
|
|
||||||
|
|
||||||
#include <CGAL/basic.h>
|
#include <CGAL/basic.h>
|
||||||
#include <CGAL/Box_intersection_d/Box_d.h>
|
#include <CGAL/Box_intersection_d/Box_d.h>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
namespace Box_intersection_d {
|
namespace Box_intersection_d {
|
||||||
|
|
||||||
template<class NT_, int N, class Info_>
|
template<class NT_, int N, class Info_, class IdPolicy = ID_EXPLICIT>
|
||||||
class Box_with_info_d : public Box_d< NT_, N, ID_FROM_BOX_ADDRESS> {
|
class Box_with_info_d
|
||||||
|
: public Box_d< NT_, N, IdPolicy>
|
||||||
|
{
|
||||||
protected:
|
protected:
|
||||||
Info_ m_info;
|
Info_ m_info;
|
||||||
public:
|
public:
|
||||||
typedef Box_d< NT_, N, ID_FROM_BOX_ADDRESS> Base;
|
typedef Box_d< NT_, N, IdPolicy> Base;
|
||||||
typedef NT_ NT;
|
typedef NT_ NT;
|
||||||
typedef Info_ Info;
|
typedef Info_ Info;
|
||||||
|
|
||||||
Box_with_info_d() {}
|
Box_with_info_d() {}
|
||||||
Box_with_info_d( Info h) : m_info(h) {}
|
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( 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(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_2& b, Info h) : Base( b), m_info(h) {}
|
||||||
Box_with_info_d( const Bbox_3& 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; }
|
Info info() const { return m_info; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace Box_intersection_d
|
} // namespace Box_intersection_d
|
||||||
|
} // namespace CGAL
|
||||||
|
|
||||||
|
#endif // CGAL_BOX_INTERSECTION_D_BOX_WITH_INFO_D_H
|
||||||
} //namespace CGAL
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include <CGAL/license/Box_intersection_d.h>
|
#include <CGAL/license/Box_intersection_d.h>
|
||||||
|
|
||||||
|
|
||||||
#include <CGAL/basic.h>
|
#include <CGAL/basic.h>
|
||||||
#include <CGAL/Box_intersection_d/box_limits.h>
|
#include <CGAL/Box_intersection_d/box_limits.h>
|
||||||
|
|
||||||
|
|
@ -24,7 +23,6 @@
|
||||||
#include <boost/random/uniform_int.hpp>
|
#include <boost/random/uniform_int.hpp>
|
||||||
#include <boost/random/variate_generator.hpp>
|
#include <boost/random/variate_generator.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
@ -93,6 +91,8 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end,
|
||||||
bool in_order = true )
|
bool in_order = true )
|
||||||
{
|
{
|
||||||
typedef typename Traits::Compare Compare;
|
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( p_begin, p_end, Compare( 0 ) );
|
||||||
std::sort( i_begin, i_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,
|
RandomAccessIter2 i_begin, RandomAccessIter2 i_end,
|
||||||
T lo, T hi,
|
T lo, T hi,
|
||||||
Callback callback, Predicate_traits traits,
|
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::Spanning Spanning;
|
||||||
typedef typename Predicate_traits::Lo_less Lo_less;
|
typedef typename Predicate_traits::Lo_less Lo_less;
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,191 @@
|
||||||
#include <CGAL/Box_intersection_d/Box_traits_d.h>
|
#include <CGAL/Box_intersection_d/Box_traits_d.h>
|
||||||
#include <CGAL/Box_intersection_d/box_limits.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>
|
#include <vector>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// THE CALLBACK MUST BE THREADSAFE IF YOU ARE USING THE PARALLEL MODE
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
// Generic call with custom predicate traits parameter.
|
// 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 >
|
class Callback, class BoxPredicateTraits >
|
||||||
void box_intersection_custom_predicates_d(
|
void box_intersection_custom_predicates_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
|
|
@ -40,23 +219,15 @@ void box_intersection_custom_predicates_d(
|
||||||
std::ptrdiff_t cutoff = 10,
|
std::ptrdiff_t cutoff = 10,
|
||||||
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE)
|
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE)
|
||||||
{
|
{
|
||||||
typedef BoxPredicateTraits Traits;
|
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin1, end1, begin2, end2, callback, traits, cutoff, true);
|
||||||
typedef typename Traits::NT NT;
|
if(setting == Box_intersection_d::BIPARTITE)
|
||||||
CGAL_assertion( Traits::dimension() > 0 );
|
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin2, end2, begin1, end1, callback, traits, cutoff, false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generic call with box traits parameter.
|
// Generic call with box traits parameter.
|
||||||
// - make all default parameters explicit overloads (workaround)
|
// - 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 >
|
class Callback, class BoxTraits >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
|
|
@ -67,18 +238,19 @@ void box_intersection_d(
|
||||||
Box_intersection_d::Topology topology,
|
Box_intersection_d::Topology topology,
|
||||||
Box_intersection_d::Setting setting)
|
Box_intersection_d::Setting setting)
|
||||||
{
|
{
|
||||||
if (topology == Box_intersection_d::CLOSED) {
|
if (topology == Box_intersection_d::CLOSED) {
|
||||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||||
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
|
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
|
||||||
callback, Traits(), cutoff, setting);
|
callback, Traits(), cutoff, setting);
|
||||||
} else {
|
} else {
|
||||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
|
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
|
||||||
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
|
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
|
||||||
callback, Traits(), cutoff, setting);
|
callback, Traits(), cutoff, setting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
template< class ConcurrencyTag = Sequential_tag,
|
||||||
|
class RandomAccessIter1, class RandomAccessIter2,
|
||||||
class Callback, class BoxTraits >
|
class Callback, class BoxTraits >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
|
|
@ -86,35 +258,39 @@ void box_intersection_d(
|
||||||
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff,
|
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff,
|
||||||
Box_intersection_d::Topology topology)
|
Box_intersection_d::Topology topology)
|
||||||
{
|
{
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||||
cutoff, topology, Box_intersection_d::BIPARTITE);
|
cutoff, topology, Box_intersection_d::BIPARTITE);
|
||||||
}
|
}
|
||||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
template< class ConcurrencyTag = Sequential_tag,
|
||||||
|
class RandomAccessIter1, class RandomAccessIter2,
|
||||||
class Callback, class BoxTraits >
|
class Callback, class BoxTraits >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff)
|
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff)
|
||||||
{
|
{
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||||
cutoff, Box_intersection_d::CLOSED,
|
cutoff, Box_intersection_d::CLOSED,
|
||||||
Box_intersection_d::BIPARTITE);
|
Box_intersection_d::BIPARTITE);
|
||||||
}
|
}
|
||||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
|
||||||
|
template< class ConcurrencyTag = Sequential_tag,
|
||||||
|
class RandomAccessIter1, class RandomAccessIter2,
|
||||||
class Callback, class BoxTraits >
|
class Callback, class BoxTraits >
|
||||||
void box_intersection_d(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
Callback callback, BoxTraits box_traits)
|
Callback callback, BoxTraits box_traits)
|
||||||
{
|
{
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||||
10, Box_intersection_d::CLOSED,
|
10, Box_intersection_d::CLOSED,
|
||||||
Box_intersection_d::BIPARTITE);
|
Box_intersection_d::BIPARTITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialized call with default box traits.
|
// Specialized call with default box traits.
|
||||||
// - make all default parameters explicit overloads (workaround)
|
// - 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(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
|
|
@ -122,53 +298,58 @@ void box_intersection_d(
|
||||||
Box_intersection_d::Topology topology,
|
Box_intersection_d::Topology topology,
|
||||||
Box_intersection_d::Setting setting)
|
Box_intersection_d::Setting setting)
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
|
||||||
cutoff, topology, setting);
|
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(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
Callback callback, std::ptrdiff_t cutoff,
|
Callback callback, std::ptrdiff_t cutoff,
|
||||||
Box_intersection_d::Topology topology)
|
Box_intersection_d::Topology topology)
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
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);
|
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(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
Callback callback, std::ptrdiff_t cutoff)
|
Callback callback, std::ptrdiff_t cutoff)
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||||
cutoff, Box_intersection_d::CLOSED,
|
cutoff, Box_intersection_d::CLOSED,
|
||||||
Box_intersection_d::BIPARTITE);
|
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(
|
void box_intersection_d(
|
||||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||||
Callback callback)
|
Callback callback)
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||||
10, Box_intersection_d::CLOSED,
|
10, Box_intersection_d::CLOSED,
|
||||||
Box_intersection_d::BIPARTITE);
|
Box_intersection_d::BIPARTITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generic call with box traits parameter, specialized for self-intersection.
|
// Generic call with box traits parameter, specialized for self-intersection.
|
||||||
// - make all default parameters explicit overloads (workaround)
|
// - 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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
|
|
@ -176,49 +357,52 @@ void box_self_intersection_d(
|
||||||
std::ptrdiff_t cutoff,
|
std::ptrdiff_t cutoff,
|
||||||
Box_intersection_d::Topology topology)
|
Box_intersection_d::Topology topology)
|
||||||
{
|
{
|
||||||
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
|
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
|
||||||
// is necessary because the 'std::partition' and range splits on the first range
|
// is necessary because the 'std::partition' and range splits on the first range
|
||||||
// would be messed up by sorts on the second range otherwise.
|
// would be messed up by sorts on the second range otherwise.
|
||||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||||
std::vector< val_t> i( begin, end);
|
std::vector< val_t> i( begin, end);
|
||||||
box_intersection_d( begin, end, i.begin(), i.end(),
|
|
||||||
callback, box_traits, cutoff, topology,
|
box_intersection_d<ConcurrencyTag>( begin, end, i.begin(), i.end(),
|
||||||
Box_intersection_d::COMPLETE);
|
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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
BoxTraits box_traits,
|
BoxTraits box_traits,
|
||||||
std::ptrdiff_t cutoff)
|
std::ptrdiff_t cutoff)
|
||||||
{
|
{
|
||||||
return box_self_intersection_d(begin, end, callback, box_traits, cutoff,
|
return box_self_intersection_d<ConcurrencyTag>(begin, end, callback, box_traits, cutoff,
|
||||||
Box_intersection_d::CLOSED);
|
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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
BoxTraits box_traits)
|
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.
|
// Specialized call with default box traits, specialized for self-intersection.
|
||||||
// - make all default parameters explicit overloads (workaround)
|
// - 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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback)
|
Callback callback)
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
|
|
@ -226,10 +410,10 @@ void box_self_intersection_d(
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
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(
|
void box_self_intersection_d(
|
||||||
RandomAccessIter begin, RandomAccessIter end,
|
RandomAccessIter begin, RandomAccessIter end,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
|
|
@ -238,11 +422,10 @@ void box_self_intersection_d(
|
||||||
{
|
{
|
||||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||||
box_self_intersection_d(begin, end, callback,
|
box_self_intersection_d<ConcurrencyTag>(begin, end, callback,
|
||||||
Box_traits(), cutoff, topology );
|
Box_traits(), cutoff, topology );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generic call for trivial all-pairs algorithm with box traits parameter.
|
// Generic call for trivial all-pairs algorithm with box traits parameter.
|
||||||
// - make all default parameters explicit overloads (workaround)
|
// - make all default parameters explicit overloads (workaround)
|
||||||
template< class ForwardIter1, class ForwardIter2,
|
template< class ForwardIter1, class ForwardIter2,
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,23 @@
|
||||||
cmake_minimum_required(VERSION 3.1...3.15)
|
cmake_minimum_required(VERSION 3.1...3.15)
|
||||||
project( Box_intersection_d_Tests )
|
project( Box_intersection_d_Tests )
|
||||||
|
|
||||||
|
find_package( CGAL QUIET )
|
||||||
|
|
||||||
find_package(CGAL QUIET)
|
find_package( TBB )
|
||||||
|
|
||||||
if ( CGAL_FOUND )
|
if ( CGAL_FOUND )
|
||||||
|
|
||||||
# create a target per cppfile
|
create_single_source_cgal_program( "automated_test.cpp" )
|
||||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
create_single_source_cgal_program( "benchmark_box_intersection.cpp" )
|
||||||
foreach(cppfile ${cppfiles})
|
create_single_source_cgal_program( "random_set_test.cpp" )
|
||||||
create_single_source_cgal_program( "${cppfile}" )
|
create_single_source_cgal_program( "test_box_grid.cpp" )
|
||||||
endforeach()
|
|
||||||
|
|
||||||
|
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()
|
else()
|
||||||
|
|
||||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,217 +1,297 @@
|
||||||
// file: test/Box_intersection_d/box_grid.C
|
// file: test/Box_intersection_d/box_grid.C
|
||||||
// similar to examples/Box_intersection_d/box_grid.C but stricter in checking
|
// similar to examples/Box_intersection_d/box_grid.C but stricter in checking
|
||||||
// and more extensive in what is tested.
|
// 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
|
// coordinates for 9 boxes of a grid
|
||||||
int p[9*4] = { 0,0,1,1, 1,0,2,1, 2,0,3,1, // lower
|
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,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
|
0,2,1,3, 1,2,2,3, 2,2,3,3};// upper
|
||||||
// 9 boxes + 2 selected boxes as query; center and upper right
|
// 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),
|
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+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+24, p+26), Box( p+28, p+30), Box( p+32, p+34),
|
||||||
Box( p+16, p+18), Box( p+32, p+34)};
|
Box( p+16, p+18), Box( p+32, p+34)};
|
||||||
Box boxes[11];
|
Box boxes[11];
|
||||||
Box* query = boxes+9;
|
Box* query = boxes+9;
|
||||||
|
|
||||||
void init() {
|
void init()
|
||||||
for ( int i = 0; i < 11; ++i)
|
{
|
||||||
boxes[i] = init_boxes[i];
|
for ( int i = 0; i < 11; ++i)
|
||||||
|
boxes[i] = init_boxes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_result( const char* text, std::vector<std::size_t>& result,
|
template <typename Vector>
|
||||||
const std::size_t* check, std::size_t size) {
|
void check_result( const char* text,
|
||||||
// sort, show, and check result
|
Vector& result,
|
||||||
std::sort( result.begin(), result.end());
|
const std::size_t* check,
|
||||||
std::cout << text << ": got " << result.size() << " elements, expected "
|
std::size_t size)
|
||||||
<< size << " elements\n got : ";
|
{
|
||||||
std::copy( result.begin(), result.end(),
|
// sort, show, and check result
|
||||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
std::sort( result.begin(), result.end());
|
||||||
std::cout << "\n expected: ";
|
std::cout << text << ": got " << result.size() << " elements, expected "
|
||||||
std::copy( check, check+size,
|
<< size << " elements\n got : ";
|
||||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
std::copy( result.begin(), result.end(),
|
||||||
std::cout << '\n' << std::endl;
|
std::ostream_iterator<std::size_t>( std::cout, ","));
|
||||||
assert( result.size() == size
|
std::cout << "\n expected: ";
|
||||||
&& std::equal( check, check+size, result.begin()));
|
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
|
// callback function object writing results to an output iterator
|
||||||
template <class OutputIterator>
|
template <class Container>
|
||||||
struct Report {
|
struct Report
|
||||||
OutputIterator it;
|
{
|
||||||
Report( OutputIterator i) : it(i) {} // store iterator in object
|
Container& c_;
|
||||||
// We encode both id-numbers in a single number, a.id() + 100 * b.id(),
|
|
||||||
// and write that number to the output iterator.
|
Report(Container& c) : c_(c) {} // store iterator in object
|
||||||
void operator()( const Box& a, const Box& b) { *it++ = a.id()+100*b.id(); }
|
// 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
|
// box_intersection_d
|
||||||
// run the intersection algorithms and store results in a vector
|
// run the intersection algorithms and store results in a vector
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
void test_box_intersection() {
|
void test_box_intersection()
|
||||||
// intersect 3x3 with 2 query boxes, closed boxes
|
{
|
||||||
init();
|
#ifdef CGAL_LINKED_WITH_TBB
|
||||||
std::vector<std::size_t> result;
|
tbb::concurrent_vector<std::size_t> result;
|
||||||
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
|
#else
|
||||||
report( std::back_inserter( result)));
|
std::vector<std::size_t> result;
|
||||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
#endif
|
||||||
1004,1005,1007,1008};
|
|
||||||
check_result( "Box inters. 3x3, 2, closed", result, check1, 13);
|
|
||||||
|
|
||||||
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff
|
// Some degenerate cases
|
||||||
init();
|
init();
|
||||||
result.clear();
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, boxes, boxes,
|
||||||
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
|
report(result));
|
||||||
report( std::back_inserter( result)),
|
assert(result.empty());
|
||||||
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);
|
|
||||||
|
|
||||||
// self intersect 3x2, closed boxes
|
init();
|
||||||
init();
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, query, query + 1,
|
||||||
result.clear();
|
report(result));
|
||||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
assert(result.empty());
|
||||||
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);
|
|
||||||
|
|
||||||
// self intersect 3x2, half-open boxes
|
init();
|
||||||
init();
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes + 3, query, query,
|
||||||
result.clear();
|
report(result));
|
||||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
assert(result.empty());
|
||||||
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);
|
|
||||||
|
|
||||||
// self intersect 3x3+2 query boxes, half-open boxes
|
// With pointers
|
||||||
init();
|
init();
|
||||||
result.clear();
|
std::vector<const Box*> range_1 = {{ boxes, boxes+1, boxes+2, boxes+3, boxes+4, boxes+5,
|
||||||
CGAL::box_self_intersection_d( boxes, boxes+11,
|
boxes+6, boxes+7, boxes+8 }};
|
||||||
report( std::back_inserter( result)),
|
std::vector<const Box*> range_2 = {{ query, query+1 }};
|
||||||
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.
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.begin(),
|
||||||
// tests also mixed types for the two iterator ranges
|
range_2.begin(), range_2.end(),
|
||||||
init();
|
report(result));
|
||||||
result.clear();
|
assert(result.empty());
|
||||||
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
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
|
||||||
// self intersect 3x3+2 query boxes, half-open boxes
|
range_2.begin(), range_2.begin(),
|
||||||
// tests also mixed types for the two iterator ranges
|
report(result));
|
||||||
init();
|
assert(result.empty());
|
||||||
result.clear();
|
|
||||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
|
||||||
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
|
range_2.begin(), range_2.end(),
|
||||||
report( std::back_inserter( result)),
|
report(result));
|
||||||
std::ptrdiff_t(20),
|
std::size_t check0[13] = {900,901,902,903,904,905,906,907,908,
|
||||||
CGAL::Box_intersection_d::HALF_OPEN,
|
1004,1005,1007,1008};
|
||||||
CGAL::Box_intersection_d::BIPARTITE);
|
check_result( "Box inters. 3x3 (ptr), 2, closed", result, check0, 13);
|
||||||
std::size_t check6[4] = {409,810,904,1008};
|
|
||||||
check_result( "Box inters. 3x3+2, half-open", result, check6, 4);
|
// 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
|
// box_intersection_all_pairs_d
|
||||||
// run the intersection algorithms and store results in a vector
|
// run the intersection algorithms and store results in a vector
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
void test_box_intersection_all_pairs() {
|
void test_box_intersection_all_pairs()
|
||||||
// intersect 3x3 with 2 query boxes, closed boxes
|
{
|
||||||
init();
|
// intersect 3x3 with 2 query boxes, closed boxes
|
||||||
std::vector<std::size_t> result;
|
init();
|
||||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
std::vector<std::size_t> result;
|
||||||
report( std::back_inserter( result)));
|
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
report(result));
|
||||||
1004,1005,1007,1008};
|
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
||||||
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
|
1004,1005,1007,1008};
|
||||||
|
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
|
||||||
|
|
||||||
// intersect 3x3 with 2 query boxes, half-open boxes
|
// intersect 3x3 with 2 query boxes, half-open boxes
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||||
report( std::back_inserter( result)),
|
report(result),
|
||||||
CGAL::Box_intersection_d::HALF_OPEN);
|
CGAL::Box_intersection_d::HALF_OPEN);
|
||||||
std::size_t check2[2] = {904,1008};
|
std::size_t check2[2] = {904,1008};
|
||||||
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
|
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
|
||||||
|
|
||||||
// self intersect 3x2, closed boxes
|
// self intersect 3x2, closed boxes
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||||
report( std::back_inserter( result)));
|
report(result));
|
||||||
std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504};
|
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);
|
check_result( "All-pairs self inters. 3x2, closed", result, check3, 11);
|
||||||
|
|
||||||
// self intersect 3x2, half-open boxes
|
// self intersect 3x2, half-open boxes
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||||
report( std::back_inserter( result)),
|
report(result),
|
||||||
CGAL::Box_intersection_d::HALF_OPEN);
|
CGAL::Box_intersection_d::HALF_OPEN);
|
||||||
std::size_t check4[1] = {9999};
|
std::size_t check4[1] = {9999};
|
||||||
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
|
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
|
||||||
|
|
||||||
// self intersect 3x3+2 query boxes, half-open boxes
|
// self intersect 3x3+2 query boxes, half-open boxes
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
|
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
|
||||||
report( std::back_inserter( result)),
|
report(result),
|
||||||
CGAL::Box_intersection_d::HALF_OPEN);
|
CGAL::Box_intersection_d::HALF_OPEN);
|
||||||
std::size_t check5[2] = {904,1008};
|
std::size_t check5[2] = {904,1008};
|
||||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
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.
|
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
|
||||||
// tests also mixed types for the two iterator ranges
|
// tests also mixed types for the two iterator ranges
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
std::vector<Box> boxes2( boxes, boxes+11);
|
std::vector<Box> boxes2( boxes, boxes+11);
|
||||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||||
boxes2.begin(), boxes2.end(),
|
boxes2.begin(), boxes2.end(),
|
||||||
report( std::back_inserter( result)),
|
report(result),
|
||||||
CGAL::Box_intersection_d::HALF_OPEN,
|
CGAL::Box_intersection_d::HALF_OPEN,
|
||||||
CGAL::Box_intersection_d::COMPLETE);
|
CGAL::Box_intersection_d::COMPLETE);
|
||||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
||||||
|
|
||||||
// compare this with the bipartite case
|
// compare this with the bipartite case
|
||||||
// self intersect 3x3+2 query boxes, half-open boxes
|
// self intersect 3x3+2 query boxes, half-open boxes
|
||||||
// tests also mixed types for the two iterator ranges
|
// tests also mixed types for the two iterator ranges
|
||||||
init();
|
init();
|
||||||
result.clear();
|
result.clear();
|
||||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
boxes2 = std::vector<Box>( boxes, boxes+11);
|
||||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||||
boxes2.begin(), boxes2.end(),
|
boxes2.begin(), boxes2.end(),
|
||||||
report( std::back_inserter( result)),
|
report(result),
|
||||||
CGAL::Box_intersection_d::HALF_OPEN,
|
CGAL::Box_intersection_d::HALF_OPEN,
|
||||||
CGAL::Box_intersection_d::BIPARTITE);
|
CGAL::Box_intersection_d::BIPARTITE);
|
||||||
std::size_t check6[4] = {409,810,904,1008};
|
std::size_t check6[4] = {409,810,904,1008};
|
||||||
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
|
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
test_box_intersection();
|
||||||
|
test_box_intersection_all_pairs();
|
||||||
|
|
||||||
int main() {
|
return EXIT_SUCCESS;
|
||||||
test_box_intersection();
|
|
||||||
test_box_intersection_all_pairs();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -41,7 +41,6 @@
|
||||||
|
|
||||||
#endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011
|
#endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011
|
||||||
|
|
||||||
|
|
||||||
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||||
# include <CGAL/internal/Static_filters/Equal_3.h>
|
# include <CGAL/internal/Static_filters/Equal_3.h>
|
||||||
# include <CGAL/internal/Static_filters/Equal_2.h>
|
# include <CGAL/internal/Static_filters/Equal_2.h>
|
||||||
|
|
@ -65,6 +64,7 @@
|
||||||
# include <CGAL/internal/Static_filters/Do_intersect_2.h>
|
# include <CGAL/internal/Static_filters/Do_intersect_2.h>
|
||||||
#endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS
|
#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/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_circle_2.h>
|
||||||
#include <CGAL/internal/Static_filters/Side_of_oriented_sphere_3.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_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::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::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::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;
|
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(); }
|
{ return Collinear_3(); }
|
||||||
|
|
||||||
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||||
Equal_2
|
Equal_2
|
||||||
equal_2_object() const
|
equal_2_object() const
|
||||||
{ return Equal_2(); }
|
{ return Equal_2(); }
|
||||||
|
|
||||||
Equal_3
|
Equal_3
|
||||||
equal_3_object() const
|
equal_3_object() const
|
||||||
{ return Equal_3(); }
|
{ return Equal_3(); }
|
||||||
#endif // NOT CGAL_NO_EQUAL_3_STATIC_FILTERS
|
#endif // NOT CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||||
|
|
||||||
#ifndef CGAL_NO_COMPARE_X_2_STATIC_FILTERS
|
#ifndef CGAL_NO_COMPARE_X_2_STATIC_FILTERS
|
||||||
Compare_x_2
|
Compare_x_2
|
||||||
compare_x_2_object() const
|
compare_x_2_object() const
|
||||||
{ return Compare_x_2(); }
|
{ return Compare_x_2(); }
|
||||||
|
|
||||||
Compare_y_2
|
Compare_y_2
|
||||||
compare_y_2_object() const
|
compare_y_2_object() const
|
||||||
{ return Compare_y_2(); }
|
{ return Compare_y_2(); }
|
||||||
|
|
||||||
#endif // NOT CGAL_NO_COMPARE_Y_2_STATIC_FILTERS
|
#endif // NOT CGAL_NO_COMPARE_Y_2_STATIC_FILTERS
|
||||||
|
|
||||||
#ifndef CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
#ifndef CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
||||||
Is_degenerate_3
|
Is_degenerate_3
|
||||||
is_degenerate_3_object() const
|
is_degenerate_3_object() const
|
||||||
{ return Is_degenerate_3(); }
|
{ return Is_degenerate_3(); }
|
||||||
#endif // NOT CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
#endif // NOT CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
||||||
|
|
@ -182,7 +183,12 @@ Compare_y_2
|
||||||
compare_squared_radius_3_object() const
|
compare_squared_radius_3_object() const
|
||||||
{ return Compare_squared_radius_3(); }
|
{ 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();}
|
{ return Power_side_of_oriented_power_sphere_3();}
|
||||||
|
|
||||||
Compare_weighted_squared_radius_3
|
Compare_weighted_squared_radius_3
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ Release date: June 2020
|
||||||
- **Breaking change**: the internal search tree is now lazily constructed. To disable it, one must call
|
- **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.
|
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
|
### Polygon Mesh Processing
|
||||||
|
|
||||||
- Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`,
|
- 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.
|
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
|
- The function `CGAL::Polygon_mesh_processing::stitch_borders()` now returns the number
|
||||||
of halfedge pairs that were stitched.
|
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
|
### 2D Triangulations
|
||||||
- To fix an inconsistency between code and documentation and to clarify which types of intersections
|
- To fix an inconsistency between code and documentation and to clarify which types of intersections
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,7 @@ CGAL_Kernel_pred_RT(Coplanar_orientation_3,
|
||||||
coplanar_orientation_3_object)
|
coplanar_orientation_3_object)
|
||||||
CGAL_Kernel_pred_RT(Coplanar_side_of_bounded_circle_3,
|
CGAL_Kernel_pred_RT(Coplanar_side_of_bounded_circle_3,
|
||||||
coplanar_side_of_bounded_circle_3_object)
|
coplanar_side_of_bounded_circle_3_object)
|
||||||
CGAL_Kernel_pred(Coplanar_3,
|
CGAL_Kernel_pred_RT(Coplanar_3,
|
||||||
coplanar_3_object)
|
coplanar_3_object)
|
||||||
CGAL_Kernel_pred(Counterclockwise_in_between_2,
|
CGAL_Kernel_pred(Counterclockwise_in_between_2,
|
||||||
counterclockwise_in_between_2_object)
|
counterclockwise_in_between_2_object)
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ endif(OpenMesh_FOUND)
|
||||||
|
|
||||||
find_package( TBB )
|
find_package( TBB )
|
||||||
if( TBB_FOUND )
|
if( TBB_FOUND )
|
||||||
|
CGAL_target_use_TBB(self_intersections_example)
|
||||||
CGAL_target_use_TBB(hausdorff_distance_remeshing_example)
|
CGAL_target_use_TBB(hausdorff_distance_remeshing_example)
|
||||||
else()
|
else()
|
||||||
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )
|
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
|
|
||||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||||
|
#include <CGAL/Real_timer.h>
|
||||||
|
#include <CGAL/tags.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||||
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||||
|
|
||||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
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))
|
if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh))
|
||||||
{
|
{
|
||||||
std::cerr << "Not a valid input file." << std::endl;
|
std::cerr << "Not a valid input file." << std::endl;
|
||||||
return 1;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool intersecting = PMP::does_self_intersect(mesh,
|
std::cout << "Using parallel mode? " << std::is_same<CGAL::Parallel_if_available_tag, CGAL::Parallel_tag>::value << std::endl;
|
||||||
PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)));
|
|
||||||
|
|
||||||
std::cout
|
CGAL::Real_timer timer;
|
||||||
<< (intersecting ? "There are self-intersections." : "There is no self-intersection.")
|
timer.start();
|
||||||
<< std::endl;
|
|
||||||
|
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;
|
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
#include <CGAL/Filtered_predicate.h>
|
#include <CGAL/Filtered_predicate.h>
|
||||||
#include <CGAL/Simple_cartesian.h>
|
#include <CGAL/Simple_cartesian.h>
|
||||||
|
|
||||||
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
|
|
||||||
#include <CGAL/Aff_transformation_3.h>
|
#include <CGAL/Aff_transformation_3.h>
|
||||||
#include <boost/mpl/if.hpp>
|
#include <boost/mpl/if.hpp>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
|
#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/property_map.h>
|
||||||
#include <CGAL/enum.h>
|
#include <CGAL/enum.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||||
|
|
@ -38,7 +38,9 @@ protected:
|
||||||
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
||||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||||
typedef typename Graph_traits::halfedge_descriptor halfedge_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:
|
public:
|
||||||
Collect_face_bbox_per_edge_bbox(
|
Collect_face_bbox_per_edge_bbox(
|
||||||
|
|
@ -80,9 +82,12 @@ protected:
|
||||||
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
||||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||||
typedef typename Graph_traits::halfedge_descriptor halfedge_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 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:
|
public:
|
||||||
Collect_face_bbox_per_edge_bbox_with_coplanar_handling(
|
Collect_face_bbox_per_edge_bbox_with_coplanar_handling(
|
||||||
const TriangleMesh& tm_faces,
|
const TriangleMesh& tm_faces,
|
||||||
|
|
@ -162,7 +167,10 @@ protected:
|
||||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||||
typedef typename Graph_traits::vertex_descriptor vertex_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;
|
typedef typename boost::property_traits<VertexPointMap>::reference Point;
|
||||||
|
|
||||||
bool is_edge_target_incident_to_face(halfedge_descriptor hd,
|
bool is_edge_target_incident_to_face(halfedge_descriptor hd,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include <boost/graph/graph_traits.hpp>
|
#include <boost/graph/graph_traits.hpp>
|
||||||
#include <CGAL/box_intersection_d.h>
|
#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_callbacks.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/Intersection_type.h>
|
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/Intersection_type.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_of_coplanar_triangles_3.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::halfedge_descriptor halfedge_descriptor;
|
||||||
typedef typename graph_traits::vertex_descriptor vertex_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_set<face_descriptor> Face_set;
|
||||||
typedef boost::unordered_map<edge_descriptor, Face_set> Edge_to_faces;
|
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())
|
if (callback_si.self_intersections_found())
|
||||||
throw Self_intersection_exception();
|
throw Self_intersection_exception();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
|
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
|
||||||
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
|
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
|
||||||
callback, cutoff );
|
callback, cutoff );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for autorefinement
|
// for autorefinement
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,8 @@ void collect_close_stitchable_boundary_edges(PM& pm,
|
||||||
typedef boost::unordered_map<halfedge_descriptor, int> Halfedge_multiplicity;
|
typedef boost::unordered_map<halfedge_descriptor, int> Halfedge_multiplicity;
|
||||||
typedef std::vector<std::pair<halfedge_descriptor, halfedge_descriptor> > Halfedge_pairs;
|
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 Union_find<vertex_descriptor> UF_vertices;
|
||||||
typedef std::map<vertex_descriptor, typename UF_vertices::handle> Handle_map;
|
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)
|
for(Box& b : boxes)
|
||||||
box_ptrs.push_back(&b);
|
box_ptrs.push_back(&b);
|
||||||
|
|
||||||
|
|
||||||
Halfedge_multiplicity multiplicity;
|
Halfedge_multiplicity multiplicity;
|
||||||
Halfedge_pairs matching_hedges;
|
Halfedge_pairs matching_hedges;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,20 +17,27 @@
|
||||||
|
|
||||||
#include <CGAL/disable_warnings.h>
|
#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_face_graph_triangle_primitive.h>
|
||||||
#include <CGAL/AABB_traits.h>
|
#include <CGAL/AABB_traits.h>
|
||||||
#include <CGAL/AABB_tree.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 <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 CGAL {
|
||||||
namespace Polygon_mesh_processing{
|
namespace Polygon_mesh_processing{
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
@ -401,7 +408,9 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
||||||
|
|
||||||
typedef TriangleMesh TM;
|
typedef TriangleMesh TM;
|
||||||
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
|
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),
|
CGAL::Bbox_3 b1 = CGAL::Polygon_mesh_processing::bbox(tm1, np1),
|
||||||
b2 = CGAL::Polygon_mesh_processing::bbox(tm2, np2);
|
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
|
// make one box per facet
|
||||||
std::vector<Box> boxes1;
|
std::vector<Box> boxes1;
|
||||||
std::vector<Box> boxes2;
|
std::vector<Box> boxes2;
|
||||||
boxes1.reserve(
|
boxes1.reserve(std::distance(boost::begin(face_range1), boost::end(face_range1)));
|
||||||
std::distance( boost::begin(face_range1), boost::end(face_range1) )
|
boxes2.reserve(std::distance(boost::begin(face_range2), boost::end(face_range2)));
|
||||||
);
|
|
||||||
boxes2.reserve(
|
|
||||||
std::distance( boost::begin(face_range2), boost::end(face_range2) )
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef typename GetVertexPointMap<TM, NamedParameters1>::const_type VertexPointMap1;
|
typedef typename GetVertexPointMap<TM, NamedParameters1>::const_type VertexPointMap1;
|
||||||
typedef typename GetVertexPointMap<TM, NamedParameters2>::const_type VertexPointMap2;
|
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<VertexPointMap1>::value_type,
|
||||||
typename boost::property_traits<VertexPointMap2>::value_type
|
typename boost::property_traits<VertexPointMap2>::value_type
|
||||||
>::value) );
|
>::value) );
|
||||||
|
|
||||||
for(face_descriptor f : face_range1)
|
for(face_descriptor f : face_range1)
|
||||||
{
|
{
|
||||||
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm1), f));
|
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]),
|
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
|
||||||
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
|
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
|
||||||
|
|
||||||
|
|
||||||
// compute intersections filtered out by boxes
|
// compute intersections filtered out by boxes
|
||||||
typedef typename GetGeomTraits<TM, NamedParameters1>::type GeomTraits;
|
typedef typename GetGeomTraits<TM, NamedParameters1>::type GeomTraits;
|
||||||
GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits), 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,
|
Box,
|
||||||
OutputIterator,
|
OutputIterator,
|
||||||
VertexPointMap1,
|
VertexPointMap1,
|
||||||
VertexPointMap2> Intersect_faces(tm1, tm2,
|
VertexPointMap2> Intersect_faces(tm1, tm2, out, vpmap1, vpmap2, gt);
|
||||||
out,
|
|
||||||
vpmap1, vpmap2,
|
|
||||||
gt);
|
|
||||||
|
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
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));
|
typename boost::range_value<Polyline>::type>::value));
|
||||||
|
|
||||||
std::vector<face_descriptor> faces;
|
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
|
// make one box per facet
|
||||||
std::vector<Box> boxes1;
|
std::vector<Box> boxes1;
|
||||||
std::vector<Box> boxes2;
|
std::vector<Box> boxes2;
|
||||||
boxes1.reserve(
|
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
|
||||||
std::distance( boost::begin(face_range), boost::end(face_range) )
|
boxes2.reserve(std::distance(boost::begin(polyline), boost::end(polyline)) - 1);
|
||||||
);
|
|
||||||
|
|
||||||
boxes2.reserve(
|
|
||||||
std::distance( boost::begin(polyline), boost::end(polyline) ) - 1
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
for(face_descriptor f : face_range)
|
for(face_descriptor f : face_range)
|
||||||
{
|
{
|
||||||
|
|
@ -571,7 +568,6 @@ compute_face_polyline_intersection( const FaceRange& face_range,
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate box pointers
|
// generate box pointers
|
||||||
|
|
||||||
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
|
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
|
||||||
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
|
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
|
||||||
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
|
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,
|
OutputIterator,
|
||||||
Polyline,
|
Polyline,
|
||||||
VertexPointMap>
|
VertexPointMap>
|
||||||
Intersect_face_polyline(tm,
|
Intersect_face_polyline(tm, faces, polyline, out, vpmap, gt);
|
||||||
faces,
|
|
||||||
polyline,
|
|
||||||
out,
|
|
||||||
vpmap,
|
|
||||||
gt);
|
|
||||||
|
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
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));
|
get_const_property_map(boost::vertex_point, tm));
|
||||||
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
|
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
|
||||||
typedef typename boost::range_value<PolylineRange>::type Polyline;
|
typedef typename boost::range_value<PolylineRange>::type Polyline;
|
||||||
CGAL_static_assertion(
|
CGAL_static_assertion((boost::is_same<Point, typename boost::range_value<Polyline>::type>::value));
|
||||||
(boost::is_same<Point,
|
|
||||||
typename boost::range_value<Polyline>::type>::value));
|
|
||||||
|
|
||||||
std::vector<face_descriptor> faces;
|
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::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
|
// make one box per facet
|
||||||
std::vector<Box> boxes1;
|
std::vector<Box> boxes1;
|
||||||
std::vector<Box> boxes2;
|
std::vector<Box> boxes2;
|
||||||
boxes1.reserve(
|
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
|
||||||
std::distance( boost::begin(face_range), boost::end(face_range) )
|
|
||||||
);
|
|
||||||
|
|
||||||
std::size_t polylines_size = 0;
|
std::size_t polylines_size = 0;
|
||||||
for(Polyline poly : polyline_range)
|
for(Polyline poly : polyline_range)
|
||||||
{
|
{
|
||||||
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
|
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)
|
for(face_descriptor f : face_range)
|
||||||
{
|
{
|
||||||
faces.push_back(f);
|
faces.push_back(f);
|
||||||
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), std::make_pair(0, faces.size()-1)));
|
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) );
|
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)
|
for(std::size_t j = 0; j < range_size; ++j)
|
||||||
{
|
{
|
||||||
|
|
@ -730,12 +719,7 @@ compute_face_polylines_intersection(const FaceRange& face_range,
|
||||||
PolylineRange,
|
PolylineRange,
|
||||||
OutputIterator,
|
OutputIterator,
|
||||||
VertexPointMap>
|
VertexPointMap>
|
||||||
Intersect_face_polyline(tm,
|
Intersect_face_polyline(tm, faces, polyline_range, out, vpmap, gt);
|
||||||
faces,
|
|
||||||
polyline_range,
|
|
||||||
out,
|
|
||||||
vpmap,
|
|
||||||
gt);
|
|
||||||
|
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||||
|
|
@ -773,18 +757,15 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
|
||||||
OutputIterator out,
|
OutputIterator out,
|
||||||
const Kernel& K)
|
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;
|
typedef typename Kernel::Point_3 Point;
|
||||||
// make one box per facet
|
// make one box per facet
|
||||||
std::vector<Box> boxes1;
|
std::vector<Box> boxes1;
|
||||||
std::vector<Box> boxes2;
|
std::vector<Box> boxes2;
|
||||||
boxes1.reserve(
|
boxes1.reserve(std::distance(boost::begin(polyline1), boost::end(polyline1)) - 1);
|
||||||
std::distance( boost::begin(polyline1), boost::end(polyline1) ) - 1
|
boxes2.reserve(std::distance(boost::begin(polyline2), boost::end(polyline2)) - 1);
|
||||||
);
|
|
||||||
|
|
||||||
boxes2.reserve(
|
|
||||||
std::distance( boost::begin(polyline2), boost::end(polyline2) ) - 1
|
|
||||||
);
|
|
||||||
|
|
||||||
for(std::size_t i =0; i< polyline1.size()-1; ++i)
|
for(std::size_t i =0; i< polyline1.size()-1; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -813,10 +794,7 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
|
||||||
Kernel,
|
Kernel,
|
||||||
Box,
|
Box,
|
||||||
OutputIterator>
|
OutputIterator>
|
||||||
intersect_polylines(polyline1,
|
intersect_polylines(polyline1, polyline2, out, K);
|
||||||
polyline2,
|
|
||||||
out,
|
|
||||||
K);
|
|
||||||
|
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||||
|
|
@ -856,7 +834,9 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
||||||
const Kernel& K)
|
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
|
//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 Kernel::Point_3 Point;
|
||||||
typedef typename boost::range_value<PolylineRange>::type Polyline;
|
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());
|
b1 += CGAL::bbox_3(poly.begin(), poly.end());
|
||||||
}
|
}
|
||||||
boxes1.reserve( polylines_size );
|
boxes1.reserve( polylines_size );
|
||||||
|
|
||||||
polylines_size = 0;
|
polylines_size = 0;
|
||||||
for(Polyline poly : polylines2)
|
for(Polyline poly : polylines2)
|
||||||
{
|
{
|
||||||
|
|
@ -881,6 +862,7 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
||||||
|
|
||||||
if(!CGAL::do_overlap(b1,b2))
|
if(!CGAL::do_overlap(b1,b2))
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) );
|
std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) );
|
||||||
for(std::size_t j = 0; j < range_size; ++j)
|
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
|
// compute intersections filtered out by boxes
|
||||||
|
|
||||||
internal::Intersect_polyline_ranges<PolylineRange,
|
internal::Intersect_polyline_ranges<PolylineRange,
|
||||||
Kernel,
|
Kernel,
|
||||||
Box,
|
Box,
|
||||||
OutputIterator>
|
OutputIterator>
|
||||||
intersect_polylines(polylines1,
|
intersect_polylines(polylines1, polylines2, out, K);
|
||||||
polylines2,
|
|
||||||
out,
|
|
||||||
K);
|
|
||||||
|
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
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);
|
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;
|
std::vector<Mesh_box> boxes;
|
||||||
boxes.reserve(std::distance(range.begin(), range.end()));
|
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) );
|
boxes.push_back( Mesh_box(Polygon_mesh_processing::bbox(*it), it) );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Mesh_box*> boxes_ptr(
|
std::vector<Mesh_box*> boxes_ptr(boost::make_counting_iterator(&boxes[0]),
|
||||||
boost::make_counting_iterator(&boxes[0]),
|
boost::make_counting_iterator(&boxes[0]+boxes.size()));
|
||||||
boost::make_counting_iterator(&boxes[0]+boxes.size()));
|
|
||||||
|
|
||||||
typedef typename boost::range_value<NamedParametersRange>::type NP_rng;
|
typedef typename boost::range_value<NamedParametersRange>::type NP_rng;
|
||||||
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
|
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
|
||||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters, NP_rng>::type GT;
|
typedef typename GetGeomTraits<TriangleMesh, NamedParameters, NP_rng>::type GT;
|
||||||
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
|
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
|
||||||
|
|
||||||
|
|
||||||
//get all the pairs of meshes intersecting (no strict inclusion test)
|
//get all the pairs of meshes intersecting (no strict inclusion test)
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
internal::Mesh_callback<TriangleMeshRange, GT, OutputIterator, NamedParametersRange> callback(range, out, report_overlap, gt, nps);
|
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(),
|
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), callback, cutoff);
|
||||||
callback, cutoff);
|
|
||||||
return callback.m_iterator;
|
return callback.m_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1634,7 +1611,7 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
||||||
|
|
||||||
template <class TriangleMeshRange, class OutputIterator>
|
template <class TriangleMeshRange, class OutputIterator>
|
||||||
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
||||||
OutputIterator out)
|
OutputIterator out)
|
||||||
{
|
{
|
||||||
return intersecting_meshes(range, out, parameters::all_default());
|
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()
|
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>
|
#include <CGAL/enable_warnings.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,215 +21,378 @@
|
||||||
|
|
||||||
#include <CGAL/disable_warnings.h>
|
#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_function_params.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.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
|
#ifdef DOXYGEN_RUNNING
|
||||||
#define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters
|
#define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters
|
||||||
#define CGAL_PMP_NP_CLASS NamedParameters
|
#define CGAL_PMP_NP_CLASS NamedParameters
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
namespace Polygon_mesh_processing {
|
||||||
namespace internal {
|
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>
|
// Checks for 'real' intersections, i.e. not simply a shared vertex or edge
|
||||||
void operator()(const T& t) {
|
template <class GT, class TM, class VPM>
|
||||||
*m_intersected = true;
|
bool do_faces_intersect(typename boost::graph_traits<TM>::halfedge_descriptor h,
|
||||||
*(*m_iterator)++ = t;
|
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;
|
h = next(h, tmesh);
|
||||||
bool* m_intersected;
|
}
|
||||||
};
|
|
||||||
// typedefs
|
// check for shared vertex --> maybe intersection, maybe not
|
||||||
typedef typename Kernel::Segment_3 Segment;
|
int i(0), j(0);
|
||||||
typedef typename Kernel::Triangle_3 Triangle;
|
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::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 TM& m_tmesh;
|
||||||
const VertexPointMap m_vpmap;
|
const VPM m_vpmap;
|
||||||
mutable OutputIterator m_iterator;
|
typename GT::Construct_segment_3 m_construct_segment;
|
||||||
mutable bool m_intersected;
|
typename GT::Construct_triangle_3 m_construct_triangle;
|
||||||
mutable boost::function_output_iterator<Output_iterator_with_bool> m_iterator_wrapper;
|
typename GT::Do_intersect_3 m_do_intersect;
|
||||||
|
|
||||||
typename Kernel::Construct_segment_3 segment_functor;
|
Strict_intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it)
|
||||||
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)
|
|
||||||
:
|
:
|
||||||
m_tmesh(tmesh),
|
m_iterator(it),
|
||||||
m_vpmap(vpmap),
|
m_tmesh(tmesh),
|
||||||
m_iterator(it),
|
m_vpmap(vpmap),
|
||||||
m_intersected(false),
|
m_construct_segment(gt.construct_segment_3_object()),
|
||||||
m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)),
|
m_construct_triangle(gt.construct_triangle_3_object()),
|
||||||
segment_functor(kernel.construct_segment_3_object()),
|
m_do_intersect(gt.do_intersect_3_object())
|
||||||
triangle_functor(kernel.construct_triangle_3_object()),
|
{}
|
||||||
do_intersect_3_functor(kernel.do_intersect_3_object())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void operator()(const Box* b, const Box* c) const
|
void operator()(const Box* b, const Box* c) const
|
||||||
{
|
{
|
||||||
halfedge_descriptor h = halfedge(b->info(), m_tmesh);
|
const halfedge_descriptor h = halfedge(b->info(), m_tmesh);
|
||||||
halfedge_descriptor opp_h;
|
const halfedge_descriptor g = halfedge(c->info(), m_tmesh);
|
||||||
|
|
||||||
// check for shared egde
|
if(do_faces_intersect<GT>(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect))
|
||||||
for(unsigned int i=0; i<3; ++i){
|
*m_iterator++ = std::make_pair(b->info(), c->info());
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}// 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
|
typedef TriangleMesh TM;
|
||||||
template <class TriangleMesh
|
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
|
||||||
, class FaceRange
|
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
|
||||||
, class OutputIterator
|
|
||||||
, class NamedParameters
|
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;
|
||||||
OutputIterator
|
|
||||||
self_intersections( const FaceRange& face_range,
|
typedef typename GetGeomTraits<TM, NamedParameters>::type GT;
|
||||||
const TriangleMesh& tmesh,
|
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
|
||||||
OutputIterator out,
|
|
||||||
const NamedParameters& np);
|
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
|
#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
|
* \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
|
* This function depends on the package \ref PkgBoxIntersectionD
|
||||||
|
*
|
||||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
* @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 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>`
|
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
|
||||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||||
*
|
*
|
||||||
|
|
@ -249,181 +412,35 @@ self_intersections( const FaceRange& face_range,
|
||||||
*
|
*
|
||||||
* @return `out`
|
* @return `out`
|
||||||
*/
|
*/
|
||||||
template <class TriangleMesh
|
template <class ConcurrencyTag = Sequential_tag,
|
||||||
, class OutputIterator
|
class TriangleMesh,
|
||||||
#ifdef DOXYGEN_RUNNING
|
class FacePairOutputIterator,
|
||||||
, class NamedParameters
|
class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
|
||||||
#else //avoid ambiguity with self_intersections(faces, tmesh, out)
|
FacePairOutputIterator
|
||||||
, class P, class T, class R
|
self_intersections(const TriangleMesh& tmesh,
|
||||||
#endif
|
FacePairOutputIterator out,
|
||||||
>
|
const CGAL_PMP_NP_CLASS& np)
|
||||||
OutputIterator
|
|
||||||
self_intersections(const TriangleMesh& tmesh
|
|
||||||
, OutputIterator out
|
|
||||||
#ifdef DOXYGEN_RUNNING
|
|
||||||
, const NamedParameters& np)
|
|
||||||
#else
|
|
||||||
, const Named_function_parameters<P,T,R>& np)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
return self_intersections(faces(tmesh), tmesh, out, np);
|
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, np);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
template <class TriangleMesh, class OutputIterator>
|
template <class ConcurrencyTag = Sequential_tag, class TriangleMesh, class FacePairOutputIterator>
|
||||||
OutputIterator
|
FacePairOutputIterator
|
||||||
self_intersections(const TriangleMesh& tmesh, OutputIterator out)
|
self_intersections(const TriangleMesh& tmesh, FacePairOutputIterator out)
|
||||||
{
|
{
|
||||||
return self_intersections(tmesh, out,
|
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, parameters::all_default());
|
||||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
|
||||||
}
|
}
|
||||||
/// \endcond
|
/// \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
|
* \ingroup PMP_intersection_grp
|
||||||
* tests if a set of faces of a triangulated surface mesh self-intersects.
|
* tests if a set of faces of a triangulated surface mesh self-intersects.
|
||||||
* This function depends on the package \ref PkgBoxIntersectionD
|
* This function depends on the package \ref PkgBoxIntersectionD
|
||||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
* @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 FaceRange a range of `face_descriptor`
|
||||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
* @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
|
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `SelfIntersectionTraits` \cgalParamEnd
|
||||||
* \cgalNamedParamsEnd
|
* \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 TriangleMesh,
|
||||||
class NamedParameters
|
class NamedParameters>
|
||||||
>
|
|
||||||
bool does_self_intersect(const FaceRange& face_range,
|
bool does_self_intersect(const FaceRange& face_range,
|
||||||
const TriangleMesh& tmesh,
|
const TriangleMesh& tmesh,
|
||||||
const NamedParameters& np)
|
const NamedParameters& np)
|
||||||
|
|
@ -453,35 +470,65 @@ bool does_self_intersect(const FaceRange& face_range,
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> OutputIterator;
|
CGAL::Emptyset_iterator unused_out;
|
||||||
self_intersections(face_range, tmesh, OutputIterator(), np);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/**
|
||||||
template <class TriangleMesh>
|
* \ingroup PMP_intersection_grp
|
||||||
bool does_self_intersect(const TriangleMesh& tmesh)
|
* 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,
|
return does_self_intersect<ConcurrencyTag>(faces(tmesh), tmesh, np);
|
||||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
bool does_self_intersect(const FaceRange& face_range,
|
||||||
const TriangleMesh& tmesh)
|
const TriangleMesh& tmesh)
|
||||||
{
|
{
|
||||||
return does_self_intersect(face_range, tmesh,
|
return does_self_intersect<ConcurrencyTag>(face_range, tmesh, CGAL::parameters::all_default());
|
||||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \endcond
|
/// \endcond
|
||||||
|
|
||||||
}// end namespace Polygon_mesh_processing
|
}// namespace Polygon_mesh_processing
|
||||||
|
|
||||||
}// namespace CGAL
|
}// namespace CGAL
|
||||||
|
|
||||||
#include <CGAL/enable_warnings.h>
|
#include <CGAL/enable_warnings.h>
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ endif()
|
||||||
|
|
||||||
if( TBB_FOUND )
|
if( TBB_FOUND )
|
||||||
CGAL_target_use_TBB(test_pmp_distance)
|
CGAL_target_use_TBB(test_pmp_distance)
|
||||||
|
CGAL_target_use_TBB(self_intersection_surface_mesh_test)
|
||||||
else()
|
else()
|
||||||
message( STATUS "NOTICE: Intel TBB was not found. test_pmp_distance will use sequential code." )
|
message( STATUS "NOTICE: Intel TBB was not found. test_pmp_distance will use sequential code." )
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||||
|
|
||||||
#include <CGAL/Surface_mesh.h>
|
#include <CGAL/Surface_mesh.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||||
|
#include <CGAL/tags.h>
|
||||||
#include <CGAL/Timer.h>
|
#include <CGAL/Timer.h>
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic;
|
#include <cstdlib>
|
||||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epec;
|
#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>
|
template <typename K>
|
||||||
int
|
int test_self_intersections(const char* filename,
|
||||||
test_self_intersections(const char* filename, const bool expected)
|
const bool expected)
|
||||||
{
|
{
|
||||||
typedef CGAL::Surface_mesh<typename K::Point_3> Mesh;
|
typedef CGAL::Surface_mesh<typename K::Point_3> Mesh;
|
||||||
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
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();
|
timer.start();
|
||||||
|
|
||||||
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
|
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
|
||||||
CGAL::Polygon_mesh_processing::self_intersections(
|
|
||||||
m,
|
if(std::is_same<K, EPECK>::value) // EPECK isn't threadsafe
|
||||||
std::back_inserter(intersected_tris),
|
{
|
||||||
CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m)));
|
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();
|
bool intersecting_1 = !intersected_tris.empty();
|
||||||
|
|
||||||
std::cout << "self_intersections test took " << timer.time() << " sec." << std::endl;
|
std::cout << "self_intersections test took " << timer.time() << " sec." << std::endl;
|
||||||
std::cout << intersected_tris.size() << " pairs of triangles are intersecting." << std::endl;
|
std::cout << intersected_tris.size() << " pairs of triangles are intersecting." << std::endl;
|
||||||
|
|
||||||
timer.reset();
|
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 << "does_self_intersect test took " << timer.time() << " sec." << std::endl;
|
||||||
std::cout << (intersecting_2 ? "There is a self-intersection." :
|
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'
|
assert(!ss.fail()); // make sure that argv[2] is either 'true' or 'false'
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "First test (Epic):" << std::endl;
|
std::cout << "First test (EPICK):" << std::endl;
|
||||||
int r = test_self_intersections<Epic>(filename, expected);
|
int r = test_self_intersections<EPICK>(filename, expected);
|
||||||
|
|
||||||
std::cout << "First test (Epec):" << std::endl;
|
std::cout << "First test (EPECK):" << std::endl;
|
||||||
r += test_self_intersections<Epec>(filename, expected);
|
r += test_self_intersections<EPECK>(filename, expected);
|
||||||
|
|
||||||
// Second test ---------------------------------------------------------------
|
// Second test ---------------------------------------------------------------
|
||||||
expected = true;
|
expected = true;
|
||||||
|
|
@ -93,11 +114,11 @@ int main(int argc, char** argv)
|
||||||
assert(!ss.fail());
|
assert(!ss.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Second test (Epic):" << std::endl;
|
std::cout << "Second test (EPICK):" << std::endl;
|
||||||
r += test_self_intersections<Epic>(filename, expected);
|
r += test_self_intersections<EPICK>(filename, expected);
|
||||||
|
|
||||||
std::cout << "Second test (Epec):" << std::endl;
|
std::cout << "Second test (EPECK):" << std::endl;
|
||||||
r += test_self_intersections<Epec>(filename, expected);
|
r += test_self_intersections<EPECK>(filename, expected);
|
||||||
|
|
||||||
// Third test ----------------------------------------------------------------
|
// Third test ----------------------------------------------------------------
|
||||||
expected = true;
|
expected = true;
|
||||||
|
|
@ -109,11 +130,11 @@ int main(int argc, char** argv)
|
||||||
assert(!ss.fail());
|
assert(!ss.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Third test (Epic):" << std::endl;
|
std::cout << "Third test (EPICK):" << std::endl;
|
||||||
r += test_self_intersections<Epic>(filename, expected);
|
r += test_self_intersections<EPICK>(filename, expected);
|
||||||
|
|
||||||
std::cout << "Third test (Epec):" << std::endl;
|
std::cout << "Third test (EPECK):" << std::endl;
|
||||||
r += test_self_intersections<Epec>(filename, expected);
|
r += test_self_intersections<EPECK>(filename, expected);
|
||||||
|
|
||||||
// Fourth test ----------------------------------------------------------------
|
// Fourth test ----------------------------------------------------------------
|
||||||
expected = true;
|
expected = true;
|
||||||
|
|
@ -125,11 +146,11 @@ int main(int argc, char** argv)
|
||||||
assert(!ss.fail());
|
assert(!ss.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Fourth test (Epic):" << std::endl;
|
std::cout << "Fourth test (EPICK):" << std::endl;
|
||||||
r += test_self_intersections<Epic>(filename, expected);
|
r += test_self_intersections<EPICK>(filename, expected);
|
||||||
|
|
||||||
std::cout << "Fourth test (Epec):" << std::endl;
|
std::cout << "Fourth test (EPECK):" << std::endl;
|
||||||
r += test_self_intersections<Epec>(filename, expected);
|
r += test_self_intersections<EPECK>(filename, expected);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,6 +252,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND)
|
||||||
add_item(scene_image_item Scene_image_item.cpp)
|
add_item(scene_image_item Scene_image_item.cpp)
|
||||||
add_item(scene_surface_mesh_item Scene_surface_mesh_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
|
# special
|
||||||
|
|
||||||
add_item(scene_item_decorator Scene_polyhedron_item_decorator.cpp )
|
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)
|
add_item(scene_selection_item Scene_polyhedron_selection_item.cpp)
|
||||||
target_link_libraries(scene_selection_item PUBLIC scene_item_decorator scene_k_ring_selection)
|
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)
|
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)
|
target_link_libraries(scene_shortest_path_item PUBLIC scene_item_decorator scene_surface_mesh_item scene_polylines_item)
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,16 @@
|
||||||
|
|
||||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||||
#include <CGAL/Three/Three.h>
|
#include <CGAL/Three/Three.h>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
|
#include <CGAL/exceptions.h>
|
||||||
#include <CGAL/IO/File_scanner_OFF.h>
|
#include <CGAL/IO/File_scanner_OFF.h>
|
||||||
#include <CGAL/IO/OBJ_reader.h>
|
#include <CGAL/IO/OBJ_reader.h>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using namespace CGAL::Three;
|
using namespace CGAL::Three;
|
||||||
class Polyhedron_demo_off_plugin :
|
class Polyhedron_demo_off_plugin :
|
||||||
public QObject,
|
public QObject,
|
||||||
|
|
@ -186,7 +189,7 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) {
|
||||||
try{
|
try{
|
||||||
CGAL::Polygon_mesh_processing::non_manifold_vertices(*surface_mesh, OutputIterator());
|
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();
|
QApplication::restoreOverrideCursor();
|
||||||
|
|
|
||||||
|
|
@ -2497,7 +2497,7 @@ QString Scene_polyhedron_selection_item::computeStats(int type)
|
||||||
return QString("n/a");
|
return QString("n/a");
|
||||||
if(is_triangle_mesh(*d->poly)){
|
if(is_triangle_mesh(*d->poly)){
|
||||||
bool self_intersect
|
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)
|
if (self_intersect)
|
||||||
return QString("Yes");
|
return QString("Yes");
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||||
#include "triangulate_primitive.h"
|
#include "triangulate_primitive.h"
|
||||||
|
|
||||||
|
#include <CGAL/exceptions.h>
|
||||||
#include <CGAL/IO/File_writer_wavefront.h>
|
#include <CGAL/IO/File_writer_wavefront.h>
|
||||||
#include <CGAL/IO/generic_copy_OFF.h>
|
#include <CGAL/IO/generic_copy_OFF.h>
|
||||||
#include <CGAL/IO/OBJ_reader.h>
|
#include <CGAL/IO/OBJ_reader.h>
|
||||||
|
|
@ -1581,7 +1582,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
|
||||||
try{
|
try{
|
||||||
CGAL::Polygon_mesh_processing::non_manifold_vertices(*d->smesh_, OutputIterator());
|
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;
|
d->has_nm_vertices = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1659,7 +1660,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
|
||||||
{
|
{
|
||||||
//todo : add a test about cache validity
|
//todo : add a test about cache validity
|
||||||
if(is_triangle_mesh(*d->smesh_))
|
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)
|
if (d->self_intersect)
|
||||||
return QString("Yes");
|
return QString("Yes");
|
||||||
else if(is_triangle_mesh(*d->smesh_))
|
else if(is_triangle_mesh(*d->smesh_))
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,19 @@ public:
|
||||||
"warning condition failed") {}
|
"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
|
} //namespace CGAL
|
||||||
|
|
||||||
#endif // CGAL_EXCEPTIONS_H
|
#endif // CGAL_EXCEPTIONS_H
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ class Intersect_facets
|
||||||
typename Kernel::Construct_triangle_2 triangle_functor;
|
typename Kernel::Construct_triangle_2 triangle_functor;
|
||||||
typename Kernel::Do_intersect_2 do_intersect_2_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 TriangleMesh& mesh;
|
||||||
const VertexUVMap uvmap;
|
const VertexUVMap uvmap;
|
||||||
|
|
@ -250,7 +251,8 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
|
||||||
typedef typename Kernel::FT NT;
|
typedef typename Kernel::FT NT;
|
||||||
typedef typename Kernel::Point_2 Point_2;
|
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
|
// Create the corresponding vector of bounding boxes
|
||||||
std::vector<Box> boxes;
|
std::vector<Box> boxes;
|
||||||
|
|
@ -283,8 +285,7 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
|
||||||
unsigned int counter = 0;
|
unsigned int counter = 0;
|
||||||
Intersect_facets<TriangleMesh, VertexUVMap> intersect_facets(mesh, uvmap, counter);
|
Intersect_facets<TriangleMesh, VertexUVMap> intersect_facets(mesh, uvmap, counter);
|
||||||
std::ptrdiff_t cutoff = 2000;
|
std::ptrdiff_t cutoff = 2000;
|
||||||
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
|
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), intersect_facets, cutoff);
|
||||||
intersect_facets, cutoff);
|
|
||||||
return (counter == 0);
|
return (counter == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue