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
|
||||
Section \ref secboxintersperformance .
|
||||
|
||||
\cgalHeading{Concurrency}
|
||||
|
||||
The first template parameter of the function enables to choose whether
|
||||
the algorithm is to be run in parallel, if `CGAL::Parallel_tag` is specified
|
||||
and %CGAL has been linked with the Intel TBB library, or sequentially,
|
||||
if `CGAL::Sequential_tag` - the default value - is specified.
|
||||
The parallelization of the algorithm is based on a divide-and-conquer
|
||||
approach: the two ranges are split in a number of smaller ranges, and
|
||||
all combinations of subranges are treated in parallel. It is thus
|
||||
recommended to use ranges of pointers to bounding boxes, to keep
|
||||
these copies light.
|
||||
|
||||
\warning The parallel mode comes with a small overhead due to the
|
||||
duplication and splitting of the input ranges. It is an improvement
|
||||
for almost all inputs, but not all. A configuration where the two ranges
|
||||
are small and entirely disjoint might result in a slightly worse
|
||||
runtime when using the parallel version. Users should benchmark both
|
||||
versions to verify that their data does not fall in this (small)
|
||||
set of inputs.
|
||||
|
||||
\warning When using the parallel mode, the callback function must
|
||||
be threadsafe.
|
||||
|
||||
\cgalHeading{Example}
|
||||
|
||||
The box implementation provided with
|
||||
|
|
@ -274,7 +297,8 @@ void box_intersection_all_pairs_d(
|
|||
|
||||
|
||||
*/
|
||||
template< class RandomAccessIterator1,
|
||||
template< class ConcurrencyTag = CGAL::Sequential_tag,
|
||||
class RandomAccessIterator1,
|
||||
class RandomAccessIterator2,
|
||||
class Callback >
|
||||
void box_intersection_d(
|
||||
|
|
@ -291,7 +315,8 @@ void box_intersection_d(
|
|||
Invocation with custom box traits.
|
||||
|
||||
*/
|
||||
template< class RandomAccessIterator1,
|
||||
template< class ConcurrencyTag = CGAL::Sequential_tag,
|
||||
class RandomAccessIterator1,
|
||||
class RandomAccessIterator2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_d(
|
||||
|
|
@ -489,8 +514,11 @@ namespace CGAL {
|
|||
|
||||
\cgalHeading{Implementation}
|
||||
|
||||
See the implementation section of the `box_intersection_d()`
|
||||
function.
|
||||
See the implementation section of the `box_intersection_d()` function.
|
||||
|
||||
\cgalHeading{Concurrency}
|
||||
|
||||
See the concurrency section of the `box_intersection_d()` function.
|
||||
|
||||
\cgalHeading{Example}
|
||||
|
||||
|
|
@ -520,7 +548,8 @@ namespace CGAL {
|
|||
`RandomAccessIterator`.
|
||||
|
||||
*/
|
||||
template< class RandomAccessIterator, class Callback >
|
||||
template< class ConcurrencyTag = CGAL::Sequential_tag,
|
||||
class RandomAccessIterator, class Callback >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIterator begin, RandomAccessIterator end,
|
||||
Callback callback,
|
||||
|
|
@ -532,7 +561,8 @@ void box_self_intersection_d(
|
|||
|
||||
Invocation with custom box traits.
|
||||
*/
|
||||
template< class RandomAccessIterator,
|
||||
template< class ConcurrencyTag = CGAL::Sequential_tag
|
||||
class RandomAccessIterator,
|
||||
class Callback, class BoxTraits >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIterator begin, RandomAccessIterator end,
|
||||
|
|
|
|||
|
|
@ -16,34 +16,34 @@
|
|||
|
||||
#include <CGAL/license/Box_intersection_d.h>
|
||||
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Box_intersection_d/Box_d.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace Box_intersection_d {
|
||||
|
||||
template<class NT_, int N, class Info_>
|
||||
class Box_with_info_d : public Box_d< NT_, N, ID_FROM_BOX_ADDRESS> {
|
||||
template<class NT_, int N, class Info_, class IdPolicy = ID_EXPLICIT>
|
||||
class Box_with_info_d
|
||||
: public Box_d< NT_, N, IdPolicy>
|
||||
{
|
||||
protected:
|
||||
Info_ m_info;
|
||||
public:
|
||||
typedef Box_d< NT_, N, ID_FROM_BOX_ADDRESS> Base;
|
||||
typedef NT_ NT;
|
||||
typedef Info_ Info;
|
||||
typedef Box_d< NT_, N, IdPolicy> Base;
|
||||
typedef NT_ NT;
|
||||
typedef Info_ Info;
|
||||
|
||||
Box_with_info_d() {}
|
||||
Box_with_info_d( Info h) : m_info(h) {}
|
||||
Box_with_info_d( bool complete, Info h): Base(complete), m_info(h) {}
|
||||
Box_with_info_d(NT l[N], NT h[N], Info n) : Base( l, h), m_info(n) {}
|
||||
Box_with_info_d( const Bbox_2& b, Info h) : Base( b), m_info(h) {}
|
||||
Box_with_info_d( const Bbox_3& b, Info h) : Base( b), m_info(h) {}
|
||||
|
||||
Info info() const { return m_info; }
|
||||
};
|
||||
|
||||
} // end namespace Box_intersection_d
|
||||
} // namespace Box_intersection_d
|
||||
} // namespace CGAL
|
||||
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif
|
||||
#endif // CGAL_BOX_INTERSECTION_D_BOX_WITH_INFO_D_H
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <CGAL/license/Box_intersection_d.h>
|
||||
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
#include <CGAL/Box_intersection_d/box_limits.h>
|
||||
|
||||
|
|
@ -24,7 +23,6 @@
|
|||
#include <boost/random/uniform_int.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
|
|
@ -93,6 +91,8 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end,
|
|||
bool in_order = true )
|
||||
{
|
||||
typedef typename Traits::Compare Compare;
|
||||
|
||||
// Putting a parallel sort here slows down the overall parallel algorithm
|
||||
std::sort( p_begin, p_end, Compare( 0 ) );
|
||||
std::sort( i_begin, i_end, Compare( 0 ) );
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end,
|
|||
RandomAccessIter2 i_begin, RandomAccessIter2 i_end,
|
||||
T lo, T hi,
|
||||
Callback callback, Predicate_traits traits,
|
||||
std::ptrdiff_t cutoff, int dim, bool in_order )
|
||||
std::ptrdiff_t cutoff, int dim, bool in_order)
|
||||
{
|
||||
typedef typename Predicate_traits::Spanning Spanning;
|
||||
typedef typename Predicate_traits::Lo_less Lo_less;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
//
|
||||
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>
|
||||
// Andreas Meyer <ameyer@mpi-sb.mpg.de>
|
||||
|
|
@ -25,12 +25,191 @@
|
|||
#include <CGAL/Box_intersection_d/Box_traits_d.h>
|
||||
#include <CGAL/Box_intersection_d/box_limits.h>
|
||||
|
||||
#include <CGAL/use.h>
|
||||
#include <CGAL/tags.h>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/task_group.h>
|
||||
#endif
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// THE CALLBACK MUST BE THREADSAFE IF YOU ARE USING THE PARALLEL MODE
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace CGAL {
|
||||
namespace internal {
|
||||
|
||||
// Generic call with custom predicate traits parameter.
|
||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
||||
template< class ConcurrencyTag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class Traits >
|
||||
void box_intersection_segment_tree_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback,
|
||||
const Traits& traits,
|
||||
const std::ptrdiff_t cutoff,
|
||||
const bool in_order)
|
||||
{
|
||||
typedef typename Traits::NT NT;
|
||||
|
||||
CGAL_assertion(Traits::dimension() > 0);
|
||||
const int dim = Traits::dimension() - 1;
|
||||
|
||||
const NT inf = Box_intersection_d::box_limits<NT>::inf();
|
||||
const NT sup = Box_intersection_d::box_limits<NT>::sup();
|
||||
|
||||
#ifndef CGAL_LINKED_WITH_TBB
|
||||
CGAL_static_assertion_msg (!(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
#else // CGAL_LINKED_WITH_TBB
|
||||
if(boost::is_convertible<ConcurrencyTag, Parallel_tag>::value)
|
||||
{
|
||||
// Here is an illustration for n=2.
|
||||
//
|
||||
// Doing a R1-R2 intersection with a 2-split is doing 4 subpairs in parallel
|
||||
// a-c and b-d
|
||||
// r1[0][0] --a-- r1[0][1] --b-- r1[0][2]
|
||||
// r2[0][0] --c-- r2[0][1] --d-- r2[0][2]
|
||||
//
|
||||
// a-d and b-c
|
||||
// r1[1][0] --a-- r1[1][1] --b-- r1[1][2]
|
||||
// r2[1][0] --c-- r2[1][1] --d-- r2[1][2]
|
||||
//
|
||||
// Ranges must be duplicates since sorting is performed
|
||||
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::difference_type diff_size;
|
||||
|
||||
typedef std::vector<val_t> val_container;
|
||||
typedef typename val_container::iterator It;
|
||||
|
||||
static constexpr int n = 4;
|
||||
|
||||
const diff_size r1s = std::distance(begin1, end1);
|
||||
const diff_size r2s = std::distance(begin2, end2);
|
||||
|
||||
val_container range_1_copies, range_2_copies;
|
||||
range_1_copies.reserve(r1s * n);
|
||||
range_2_copies.reserve(r2s * n);
|
||||
|
||||
const diff_size r1_step = r1s / n;
|
||||
const diff_size r2_step = r2s / n;
|
||||
|
||||
for(int i=0; i<n; ++i)
|
||||
{
|
||||
range_1_copies.insert(range_1_copies.end(), begin1, end1);
|
||||
range_2_copies.insert(range_2_copies.end(), begin2, end2);
|
||||
}
|
||||
|
||||
// for example for n=2, there's 'begin', 'mid', and 'end' but we leave out 'end' for convenience
|
||||
std::array<std::array<It, n>, n> range_1_iterators;
|
||||
std::array<std::array<It, n>, n> range_2_iterators;
|
||||
|
||||
for(int i=0; i<n; ++i)
|
||||
{
|
||||
for(int j=0; j<n; ++j)
|
||||
{
|
||||
range_1_iterators[i][j] = range_1_copies.begin() + i * r1s + j * r1_step;
|
||||
range_2_iterators[i][j] = range_2_copies.begin() + i * r2s + j * r2_step;
|
||||
}
|
||||
}
|
||||
|
||||
tbb::task_group g;
|
||||
|
||||
for(int i=0; i<n; ++i)
|
||||
{
|
||||
for(int j=0; j<n; ++j)
|
||||
{
|
||||
// 'j' vs 'j+i', meaning for each value of 'i' we're matching r1[i] with a shifted version of r2[i]
|
||||
int r1_endi, r1_endj;
|
||||
int r2_endi, r2_endj;
|
||||
|
||||
if(i == (n-1))
|
||||
{
|
||||
if(j == (n-1)) // both very last range and very last iterator
|
||||
{
|
||||
r1_endi = -1;
|
||||
r1_endj = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1_endi = i;
|
||||
r1_endj = j+1;
|
||||
}
|
||||
}
|
||||
else // i != (n-1)
|
||||
{
|
||||
if(j == (n-1)) // end of that range, but not of the full container
|
||||
{
|
||||
r1_endi = i+1;
|
||||
r1_endj = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r1_endi = i;
|
||||
r1_endj = j+1;
|
||||
}
|
||||
}
|
||||
|
||||
if(i == (n-1))
|
||||
{
|
||||
if(j+i == (n-1)) // both very last range and very last iterator
|
||||
{
|
||||
r2_endi = -1;
|
||||
r2_endj = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
r2_endi = i;
|
||||
r2_endj = (j+i+1)%n;
|
||||
}
|
||||
}
|
||||
else // i != (n-1)
|
||||
{
|
||||
if(j+i == (n-1)) // end of that range, but not of the full container
|
||||
{
|
||||
r2_endi = i+1;
|
||||
r2_endj = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r2_endi = i;
|
||||
r2_endj = (j+i+1)%n;
|
||||
}
|
||||
}
|
||||
|
||||
It r1_start = range_1_iterators[i][j];
|
||||
It r1_end = (r1_endi == -1) ? range_1_copies.end() : range_1_iterators[r1_endi][r1_endj];
|
||||
It r2_start = range_2_iterators[i][(j+i)%n];
|
||||
It r2_end = (r2_endi == -1) ? range_2_copies.end() : range_2_iterators[r2_endi][r2_endj];
|
||||
CGAL_assertion(range_1_copies.begin() <= r1_start && r1_start <= r1_end && r1_end <= range_1_copies.end());
|
||||
CGAL_assertion(range_2_copies.begin() <= r2_start && r2_start <= r2_end && r2_end <= range_2_copies.end());
|
||||
|
||||
// Specify "copy by value" otherwise the values of iterators for next (i,j) iterations
|
||||
// become shared with different lambdas being run in parallel, and things go wrong
|
||||
g.run([=]{ Box_intersection_d::segment_tree( r1_start, r1_end, r2_start, r2_end,
|
||||
inf, sup, callback, traits, cutoff, dim, in_order); });
|
||||
}
|
||||
}
|
||||
|
||||
g.wait();
|
||||
}
|
||||
else
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
{
|
||||
Box_intersection_d::segment_tree(begin1, end1, begin2, end2, inf, sup, callback, traits, cutoff, dim, in_order);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Generic call with custom predicate traits parameter.
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class BoxPredicateTraits >
|
||||
void box_intersection_custom_predicates_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
|
|
@ -40,23 +219,15 @@ void box_intersection_custom_predicates_d(
|
|||
std::ptrdiff_t cutoff = 10,
|
||||
Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE)
|
||||
{
|
||||
typedef BoxPredicateTraits Traits;
|
||||
typedef typename Traits::NT NT;
|
||||
CGAL_assertion( Traits::dimension() > 0 );
|
||||
const int dim = Traits::dimension() - 1;
|
||||
const NT inf = Box_intersection_d::box_limits<NT>::inf();
|
||||
const NT sup = Box_intersection_d::box_limits<NT>::sup();
|
||||
Box_intersection_d::segment_tree(begin1, end1, begin2, end2,
|
||||
inf, sup, callback, traits, cutoff, dim, true);
|
||||
if(setting == Box_intersection_d::BIPARTITE)
|
||||
Box_intersection_d::segment_tree(begin2, end2, begin1, end1,
|
||||
inf, sup, callback, traits, cutoff, dim, false);
|
||||
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin1, end1, begin2, end2, callback, traits, cutoff, true);
|
||||
if(setting == Box_intersection_d::BIPARTITE)
|
||||
internal::box_intersection_segment_tree_d<ConcurrencyTag>(begin2, end2, begin1, end1, callback, traits, cutoff, false);
|
||||
}
|
||||
|
||||
|
||||
// Generic call with box traits parameter.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
|
|
@ -67,18 +238,19 @@ void box_intersection_d(
|
|||
Box_intersection_d::Topology topology,
|
||||
Box_intersection_d::Setting setting)
|
||||
{
|
||||
if (topology == Box_intersection_d::CLOSED) {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
|
||||
callback, Traits(), cutoff, setting);
|
||||
} else {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
|
||||
box_intersection_custom_predicates_d(begin1, end1, begin2, end2,
|
||||
callback, Traits(), cutoff, setting);
|
||||
}
|
||||
if (topology == Box_intersection_d::CLOSED) {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
|
||||
callback, Traits(), cutoff, setting);
|
||||
} else {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
|
||||
box_intersection_custom_predicates_d<ConcurrencyTag>(begin1, end1, begin2, end2,
|
||||
callback, Traits(), cutoff, setting);
|
||||
}
|
||||
}
|
||||
|
||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
|
|
@ -86,35 +258,39 @@ void box_intersection_d(
|
|||
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff,
|
||||
Box_intersection_d::Topology topology)
|
||||
{
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
||||
cutoff, topology, Box_intersection_d::BIPARTITE);
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||
cutoff, topology, Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff)
|
||||
{
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
||||
cutoff, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||
cutoff, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
template< class RandomAccessIter1, class RandomAccessIter2,
|
||||
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback, BoxTraits box_traits)
|
||||
{
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, box_traits,
|
||||
10, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, box_traits,
|
||||
10, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
|
||||
// Specialized call with default box traits.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
|
|
@ -122,53 +298,58 @@ void box_intersection_d(
|
|||
Box_intersection_d::Topology topology,
|
||||
Box_intersection_d::Setting setting)
|
||||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, topology, setting);
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, topology, setting);
|
||||
}
|
||||
|
||||
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback, std::ptrdiff_t cutoff,
|
||||
Box_intersection_d::Topology topology)
|
||||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, topology, Box_intersection_d::BIPARTITE);
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, topology, Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback, std::ptrdiff_t cutoff)
|
||||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
cutoff, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
template< class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter1, class RandomAccessIter2, class Callback >
|
||||
void box_intersection_d(
|
||||
RandomAccessIter1 begin1, RandomAccessIter1 end1,
|
||||
RandomAccessIter2 begin2, RandomAccessIter2 end2,
|
||||
Callback callback)
|
||||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
10, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
typedef typename std::iterator_traits<RandomAccessIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_d<ConcurrencyTag>( begin1, end1, begin2, end2, callback, Box_traits(),
|
||||
10, Box_intersection_d::CLOSED,
|
||||
Box_intersection_d::BIPARTITE);
|
||||
}
|
||||
|
||||
|
||||
// Generic call with box traits parameter, specialized for self-intersection.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class RandomAccessIter, class Callback, class BoxTraits >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter, class Callback, class BoxTraits >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback,
|
||||
|
|
@ -176,49 +357,52 @@ void box_self_intersection_d(
|
|||
std::ptrdiff_t cutoff,
|
||||
Box_intersection_d::Topology topology)
|
||||
{
|
||||
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
|
||||
// is necessary because the 'std::partition' and range splits on the first range
|
||||
// would be messed up by sorts on the second range otherwise.
|
||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||
std::vector< val_t> i( begin, end);
|
||||
box_intersection_d( begin, end, i.begin(), i.end(),
|
||||
callback, box_traits, cutoff, topology,
|
||||
Box_intersection_d::COMPLETE);
|
||||
// Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...'
|
||||
// is necessary because the 'std::partition' and range splits on the first range
|
||||
// would be messed up by sorts on the second range otherwise.
|
||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||
std::vector< val_t> i( begin, end);
|
||||
|
||||
box_intersection_d<ConcurrencyTag>( begin, end, i.begin(), i.end(),
|
||||
callback, box_traits, cutoff, topology,
|
||||
Box_intersection_d::COMPLETE);
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback, class BoxTraits >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter, class Callback, class BoxTraits >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback,
|
||||
BoxTraits box_traits,
|
||||
std::ptrdiff_t cutoff)
|
||||
{
|
||||
return box_self_intersection_d(begin, end, callback, box_traits, cutoff,
|
||||
Box_intersection_d::CLOSED);
|
||||
return box_self_intersection_d<ConcurrencyTag>(begin, end, callback, box_traits, cutoff,
|
||||
Box_intersection_d::CLOSED);
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback, class BoxTraits >
|
||||
template< class ConcurrencyTag = Sequential_tag,
|
||||
class RandomAccessIter, class Callback, class BoxTraits >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback,
|
||||
BoxTraits box_traits)
|
||||
{
|
||||
return box_self_intersection_d(begin, end, callback, box_traits, 10);
|
||||
return box_self_intersection_d<ConcurrencyTag>(begin, end, callback, box_traits, 10);
|
||||
}
|
||||
|
||||
// Specialized call with default box traits, specialized for self-intersection.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class RandomAccessIter, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback)
|
||||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_self_intersection_d(begin, end, callback, Box_traits());
|
||||
box_self_intersection_d<ConcurrencyTag>(begin, end, callback, Box_traits());
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback,
|
||||
|
|
@ -226,10 +410,10 @@ void box_self_intersection_d(
|
|||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_self_intersection_d(begin, end, callback, Box_traits(), cutoff);
|
||||
box_self_intersection_d<ConcurrencyTag>(begin, end, callback, Box_traits(), cutoff);
|
||||
}
|
||||
|
||||
template< class RandomAccessIter, class Callback >
|
||||
template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback >
|
||||
void box_self_intersection_d(
|
||||
RandomAccessIter begin, RandomAccessIter end,
|
||||
Callback callback,
|
||||
|
|
@ -238,28 +422,27 @@ void box_self_intersection_d(
|
|||
{
|
||||
typedef typename std::iterator_traits<RandomAccessIter>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_self_intersection_d(begin, end, callback,
|
||||
Box_traits(), cutoff, topology );
|
||||
box_self_intersection_d<ConcurrencyTag>(begin, end, callback,
|
||||
Box_traits(), cutoff, topology );
|
||||
}
|
||||
|
||||
|
||||
// Generic call for trivial all-pairs algorithm with box traits parameter.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class ForwardIter1, class ForwardIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback, BoxTraits)
|
||||
{
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
callback, Traits());
|
||||
}
|
||||
|
||||
template< class ForwardIter1, class ForwardIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback, BoxTraits,
|
||||
|
|
@ -269,18 +452,18 @@ void box_intersection_all_pairs_d(
|
|||
bool complete_case = (setting != Box_intersection_d::BIPARTITE);
|
||||
if (topology == Box_intersection_d::CLOSED) {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
callback, Traits(), complete_case);
|
||||
} else {
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,false> Traits;
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
Box_intersection_d::all_pairs( begin1, end1, begin2, end2,
|
||||
callback, Traits(), complete_case);
|
||||
}
|
||||
}
|
||||
|
||||
template< class ForwardIter1, class ForwardIter2,
|
||||
class Callback, class BoxTraits >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback, BoxTraits traits,
|
||||
|
|
@ -293,20 +476,20 @@ void box_intersection_all_pairs_d(
|
|||
// Specialized call for trivial all-pairs algorithm with default box traits.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class ForwardIter1, class ForwardIter2, class Callback >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback)
|
||||
{
|
||||
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
callback, Box_traits(),
|
||||
Box_intersection_d::CLOSED );
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
callback, Box_traits(),
|
||||
Box_intersection_d::CLOSED );
|
||||
}
|
||||
|
||||
template< class ForwardIter1, class ForwardIter2, class Callback >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback,
|
||||
|
|
@ -314,12 +497,12 @@ void box_intersection_all_pairs_d(
|
|||
{
|
||||
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
callback, Box_traits(), topology);
|
||||
}
|
||||
|
||||
template< class ForwardIter1, class ForwardIter2, class Callback >
|
||||
void box_intersection_all_pairs_d(
|
||||
void box_intersection_all_pairs_d(
|
||||
ForwardIter1 begin1, ForwardIter1 end1,
|
||||
ForwardIter2 begin2, ForwardIter2 end2,
|
||||
Callback callback,
|
||||
|
|
@ -328,7 +511,7 @@ void box_intersection_all_pairs_d(
|
|||
{
|
||||
typedef typename std::iterator_traits<ForwardIter1>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
box_intersection_all_pairs_d( begin1, end1, begin2, end2,
|
||||
callback, Box_traits(), topology, setting);
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +519,7 @@ void box_intersection_all_pairs_d(
|
|||
// specialized for self-intersection test.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class ForwardIter, class Callback, class BoxTraits >
|
||||
void box_self_intersection_all_pairs_d(
|
||||
void box_self_intersection_all_pairs_d(
|
||||
ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits /* traits */)
|
||||
{
|
||||
typedef Box_intersection_d::Predicate_traits_d<BoxTraits,true> Traits;
|
||||
|
|
@ -344,7 +527,7 @@ void box_self_intersection_all_pairs_d(
|
|||
}
|
||||
|
||||
template< class ForwardIter, class Callback, class BoxTraits >
|
||||
void box_self_intersection_all_pairs_d(
|
||||
void box_self_intersection_all_pairs_d(
|
||||
ForwardIter begin1, ForwardIter end1, Callback callback, BoxTraits,
|
||||
Box_intersection_d::Topology topology)
|
||||
{
|
||||
|
|
@ -361,17 +544,17 @@ void box_self_intersection_all_pairs_d(
|
|||
// specialized for self-intersection test.
|
||||
// - make all default parameters explicit overloads (workaround)
|
||||
template< class ForwardIter, class Callback >
|
||||
void box_self_intersection_all_pairs_d(
|
||||
void box_self_intersection_all_pairs_d(
|
||||
ForwardIter begin1, ForwardIter end1, Callback callback)
|
||||
{
|
||||
typedef typename std::iterator_traits<ForwardIter>::value_type val_t;
|
||||
typedef Box_intersection_d::Box_traits_d< val_t> Box_traits;
|
||||
box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(),
|
||||
Box_intersection_d::CLOSED );
|
||||
box_self_intersection_all_pairs_d( begin1, end1, callback, Box_traits(),
|
||||
Box_intersection_d::CLOSED );
|
||||
}
|
||||
|
||||
template< class ForwardIter, class Callback >
|
||||
void box_self_intersection_all_pairs_d(
|
||||
void box_self_intersection_all_pairs_d(
|
||||
ForwardIter begin1, ForwardIter end1, Callback callback,
|
||||
Box_intersection_d::Topology topology)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,20 +5,23 @@
|
|||
cmake_minimum_required(VERSION 3.1...3.15)
|
||||
project( Box_intersection_d_Tests )
|
||||
|
||||
find_package( CGAL QUIET )
|
||||
|
||||
find_package(CGAL QUIET)
|
||||
find_package( TBB )
|
||||
|
||||
if ( CGAL_FOUND )
|
||||
|
||||
# create a target per cppfile
|
||||
file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
foreach(cppfile ${cppfiles})
|
||||
create_single_source_cgal_program( "${cppfile}" )
|
||||
endforeach()
|
||||
create_single_source_cgal_program( "automated_test.cpp" )
|
||||
create_single_source_cgal_program( "benchmark_box_intersection.cpp" )
|
||||
create_single_source_cgal_program( "random_set_test.cpp" )
|
||||
create_single_source_cgal_program( "test_box_grid.cpp" )
|
||||
|
||||
if( TBB_FOUND )
|
||||
CGAL_target_use_TBB( test_box_grid )
|
||||
else()
|
||||
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )
|
||||
endif()
|
||||
else()
|
||||
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,217 +1,297 @@
|
|||
// file: test/Box_intersection_d/box_grid.C
|
||||
// similar to examples/Box_intersection_d/box_grid.C but stricter in checking
|
||||
// and more extensive in what is tested.
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
typedef CGAL::Box_intersection_d::Box_d<int,2> Box;
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/tags.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#endif
|
||||
|
||||
typedef CGAL::Box_intersection_d::Box_d<int, 2> Box;
|
||||
|
||||
// coordinates for 9 boxes of a grid
|
||||
int p[9*4] = { 0,0,1,1, 1,0,2,1, 2,0,3,1, // lower
|
||||
0,1,1,2, 1,1,2,2, 2,1,3,2, // middle
|
||||
0,2,1,3, 1,2,2,3, 2,2,3,3};// upper
|
||||
// 9 boxes + 2 selected boxes as query; center and upper right
|
||||
Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10),
|
||||
Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22),
|
||||
Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34),
|
||||
Box( p+16, p+18), Box( p+32, p+34)};
|
||||
const Box init_boxes[11] = { Box( p, p+ 2), Box( p+ 4, p+ 6), Box( p+ 8, p+10),
|
||||
Box( p+12, p+14), Box( p+16, p+18), Box( p+20, p+22),
|
||||
Box( p+24, p+26), Box( p+28, p+30), Box( p+32, p+34),
|
||||
Box( p+16, p+18), Box( p+32, p+34)};
|
||||
Box boxes[11];
|
||||
Box* query = boxes+9;
|
||||
|
||||
void init() {
|
||||
for ( int i = 0; i < 11; ++i)
|
||||
boxes[i] = init_boxes[i];
|
||||
void init()
|
||||
{
|
||||
for ( int i = 0; i < 11; ++i)
|
||||
boxes[i] = init_boxes[i];
|
||||
}
|
||||
|
||||
void check_result( const char* text, std::vector<std::size_t>& result,
|
||||
const std::size_t* check, std::size_t size) {
|
||||
// sort, show, and check result
|
||||
std::sort( result.begin(), result.end());
|
||||
std::cout << text << ": got " << result.size() << " elements, expected "
|
||||
<< size << " elements\n got : ";
|
||||
std::copy( result.begin(), result.end(),
|
||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
||||
std::cout << "\n expected: ";
|
||||
std::copy( check, check+size,
|
||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
||||
std::cout << '\n' << std::endl;
|
||||
assert( result.size() == size
|
||||
&& std::equal( check, check+size, result.begin()));
|
||||
template <typename Vector>
|
||||
void check_result( const char* text,
|
||||
Vector& result,
|
||||
const std::size_t* check,
|
||||
std::size_t size)
|
||||
{
|
||||
// sort, show, and check result
|
||||
std::sort( result.begin(), result.end());
|
||||
std::cout << text << ": got " << result.size() << " elements, expected "
|
||||
<< size << " elements\n got : ";
|
||||
std::copy( result.begin(), result.end(),
|
||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
||||
std::cout << "\n expected: ";
|
||||
std::copy( check, check+size,
|
||||
std::ostream_iterator<std::size_t>( std::cout, ","));
|
||||
std::cout << '\n' << std::endl;
|
||||
assert( result.size() == size
|
||||
&& std::equal( check, check+size, result.begin()));
|
||||
}
|
||||
|
||||
// callback function object writing results to an output iterator
|
||||
template <class OutputIterator>
|
||||
struct Report {
|
||||
OutputIterator it;
|
||||
Report( OutputIterator i) : it(i) {} // store iterator in object
|
||||
// We encode both id-numbers in a single number, a.id() + 100 * b.id(),
|
||||
// and write that number to the output iterator.
|
||||
void operator()( const Box& a, const Box& b) { *it++ = a.id()+100*b.id(); }
|
||||
template <class Container>
|
||||
struct Report
|
||||
{
|
||||
Container& c_;
|
||||
|
||||
Report(Container& c) : c_(c) {} // store iterator in object
|
||||
// We encode both id-numbers in a single number, a.id() + 100 * b.id(),
|
||||
// and write that number to the output iterator.
|
||||
void operator()(const Box& a, const Box& b) { c_.push_back(a.id()+100*b.id()); }
|
||||
void operator()(const Box* a, const Box* b) { c_.push_back(a->id()+100*b->id()); }
|
||||
};
|
||||
template <class Iter> // helper function to create the function object
|
||||
Report<Iter> report( Iter it) { return Report<Iter>(it); }
|
||||
|
||||
template <class Container> // helper function to create the function object
|
||||
Report<Container> report(Container& c) { return Report<Container>(c); }
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// box_intersection_d
|
||||
// run the intersection algorithms and store results in a vector
|
||||
// ---------------------------------------------------------------------
|
||||
void test_box_intersection() {
|
||||
// intersect 3x3 with 2 query boxes, closed boxes
|
||||
init();
|
||||
std::vector<std::size_t> result;
|
||||
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
|
||||
report( std::back_inserter( result)));
|
||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
||||
1004,1005,1007,1008};
|
||||
check_result( "Box inters. 3x3, 2, closed", result, check1, 13);
|
||||
void test_box_intersection()
|
||||
{
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
tbb::concurrent_vector<std::size_t> result;
|
||||
#else
|
||||
std::vector<std::size_t> result;
|
||||
#endif
|
||||
|
||||
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
|
||||
report( std::back_inserter( result)),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check2[2] = {904,1008};
|
||||
check_result( "Box inters. 3x3, 2, half-open", result, check2, 2);
|
||||
// Some degenerate cases
|
||||
init();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, boxes, boxes,
|
||||
report(result));
|
||||
assert(result.empty());
|
||||
|
||||
// self intersect 3x2, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
||||
report( std::back_inserter( result)));
|
||||
std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405};
|
||||
check_result( "Box self inters. 3x2, closed", result, check3, 11);
|
||||
init();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes, query, query + 1,
|
||||
report(result));
|
||||
assert(result.empty());
|
||||
|
||||
// self intersect 3x2, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
||||
report( std::back_inserter( result)),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check4[1] = {9999};
|
||||
check_result( "Box self inters. 3x2, half-open", result, check4, 0);
|
||||
init();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes + 3, query, query,
|
||||
report(result));
|
||||
assert(result.empty());
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+11,
|
||||
report( std::back_inserter( result)),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check5[2] = {409,810};
|
||||
check_result( "Box self inters. 3x3+2, half-open", result, check5, 2);
|
||||
// With pointers
|
||||
init();
|
||||
std::vector<const Box*> range_1 = {{ boxes, boxes+1, boxes+2, boxes+3, boxes+4, boxes+5,
|
||||
boxes+6, boxes+7, boxes+8 }};
|
||||
std::vector<const Box*> range_2 = {{ query, query+1 }};
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
std::vector<Box> boxes2( boxes, boxes+11);
|
||||
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
|
||||
report( std::back_inserter( result)),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::COMPLETE);
|
||||
check_result( "Box inters. 3x3+2, half-open", result, check5, 2);
|
||||
|
||||
// compare this with the bipartite case
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
||||
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
|
||||
report( std::back_inserter( result)),
|
||||
std::ptrdiff_t(20),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::BIPARTITE);
|
||||
std::size_t check6[4] = {409,810,904,1008};
|
||||
check_result( "Box inters. 3x3+2, half-open", result, check6, 4);
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.begin(),
|
||||
range_2.begin(), range_2.end(),
|
||||
report(result));
|
||||
assert(result.empty());
|
||||
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
|
||||
range_2.begin(), range_2.begin(),
|
||||
report(result));
|
||||
assert(result.empty());
|
||||
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(range_1.begin(), range_1.end(),
|
||||
range_2.begin(), range_2.end(),
|
||||
report(result));
|
||||
std::size_t check0[13] = {900,901,902,903,904,905,906,907,908,
|
||||
1004,1005,1007,1008};
|
||||
check_result( "Box inters. 3x3 (ptr), 2, closed", result, check0, 13);
|
||||
|
||||
// intersect 3x3 with 2 query boxes, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes+9, query, query+1, report(result));
|
||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908};
|
||||
check_result( "Box inters. 3x3, 2, closed", result, check1, 9);
|
||||
|
||||
// intersect 3x3 with 2 query boxes, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>(boxes, boxes+9, query, query+2, report(result));
|
||||
std::size_t check1bis[13] = {900,901,902,903,904,905,906,907,908,
|
||||
1004,1005,1007,1008};
|
||||
check_result( "Box inters. 3x3, 2, closed", result, check1bis, 13);
|
||||
|
||||
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_d( boxes, boxes+9, query, query+2,
|
||||
report(result),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check2[2] = {904,1008};
|
||||
check_result( "Box inters. 3x3, 2, half-open", result, check2, 2);
|
||||
|
||||
// intersect 3x3 with 2 query boxes, half-open boxes and changed cutoff (reversed)
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_d<CGAL::Parallel_if_available_tag>( query, query+2, boxes, boxes+9,
|
||||
report(result),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check2bis[2] = {409,810};
|
||||
check_result( "Box inters. 3x3 (reversed), 2, half-open", result, check2bis, 2);
|
||||
|
||||
// self intersect 3x2, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
||||
report(result));
|
||||
std::size_t check3[11] = {1,3,4,102,103,104,105,204,205,304,405};
|
||||
check_result( "Box self inters. 3x2, closed", result, check3, 11);
|
||||
|
||||
// self intersect 3x2, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+6,
|
||||
report(result),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check4[1] = {9999};
|
||||
check_result( "Box self inters. 3x2, half-open", result, check4, 0);
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_d( boxes, boxes+11,
|
||||
report(result),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check5[2] = {409,810};
|
||||
check_result( "Box self inters. 3x3+2, half-open", result, check5, 2);
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
std::vector<Box> boxes2( boxes, boxes+11);
|
||||
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
|
||||
report(result),
|
||||
std::ptrdiff_t(1),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::COMPLETE);
|
||||
check_result( "Box inters. 3x3+2, half-open", result, check5, 2);
|
||||
|
||||
// compare this with the bipartite case
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
||||
CGAL::box_intersection_d( boxes, boxes+11, boxes2.begin(), boxes2.end(),
|
||||
report(result),
|
||||
std::ptrdiff_t(20),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::BIPARTITE);
|
||||
std::size_t check6[4] = {409,810,904,1008};
|
||||
check_result( "Box inters. 3x3+2, half-open", result, check6, 4);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// box_intersection_all_pairs_d
|
||||
// run the intersection algorithms and store results in a vector
|
||||
// ---------------------------------------------------------------------
|
||||
void test_box_intersection_all_pairs() {
|
||||
// intersect 3x3 with 2 query boxes, closed boxes
|
||||
init();
|
||||
std::vector<std::size_t> result;
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||
report( std::back_inserter( result)));
|
||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
||||
1004,1005,1007,1008};
|
||||
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
|
||||
void test_box_intersection_all_pairs()
|
||||
{
|
||||
// intersect 3x3 with 2 query boxes, closed boxes
|
||||
init();
|
||||
std::vector<std::size_t> result;
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||
report(result));
|
||||
std::size_t check1[13] = {900,901,902,903,904,905,906,907,908,
|
||||
1004,1005,1007,1008};
|
||||
check_result( "All-pairs inters. 3x3, 2, closed", result, check1, 13);
|
||||
|
||||
// intersect 3x3 with 2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||
report( std::back_inserter( result)),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check2[2] = {904,1008};
|
||||
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
|
||||
// intersect 3x3 with 2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+9, query, query+2,
|
||||
report(result),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check2[2] = {904,1008};
|
||||
check_result( "All-pairs inters. 3x3, 2, half-open", result, check2, 2);
|
||||
|
||||
// self intersect 3x2, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||
report( std::back_inserter( result)));
|
||||
std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504};
|
||||
check_result( "All-pairs self inters. 3x2, closed", result, check3, 11);
|
||||
// self intersect 3x2, closed boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||
report(result));
|
||||
std::size_t check3[11] = {100,201,300,301,400,401,402,403,501,502,504};
|
||||
check_result( "All-pairs self inters. 3x2, closed", result, check3, 11);
|
||||
|
||||
// self intersect 3x2, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||
report( std::back_inserter( result)),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check4[1] = {9999};
|
||||
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
|
||||
// self intersect 3x2, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+6,
|
||||
report(result),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check4[1] = {9999};
|
||||
check_result( "All-pairs self inters. 3x2, half-open", result, check4, 0);
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
|
||||
report( std::back_inserter( result)),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check5[2] = {904,1008};
|
||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
init();
|
||||
result.clear();
|
||||
CGAL::box_self_intersection_all_pairs_d( boxes, boxes+11,
|
||||
report(result),
|
||||
CGAL::Box_intersection_d::HALF_OPEN);
|
||||
std::size_t check5[2] = {904,1008};
|
||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
||||
|
||||
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
std::vector<Box> boxes2( boxes, boxes+11);
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||
boxes2.begin(), boxes2.end(),
|
||||
report( std::back_inserter( result)),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::COMPLETE);
|
||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
||||
|
||||
// compare this with the bipartite case
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||
boxes2.begin(), boxes2.end(),
|
||||
report( std::back_inserter( result)),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::BIPARTITE);
|
||||
std::size_t check6[4] = {409,810,904,1008};
|
||||
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
|
||||
// self intersect 3x3+2 query boxes, half-open boxes, full function interf.
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
std::vector<Box> boxes2( boxes, boxes+11);
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||
boxes2.begin(), boxes2.end(),
|
||||
report(result),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::COMPLETE);
|
||||
check_result( "All-pairs self inters. 3x3+2, half-open", result, check5,2);
|
||||
|
||||
// compare this with the bipartite case
|
||||
// self intersect 3x3+2 query boxes, half-open boxes
|
||||
// tests also mixed types for the two iterator ranges
|
||||
init();
|
||||
result.clear();
|
||||
boxes2 = std::vector<Box>( boxes, boxes+11);
|
||||
CGAL::box_intersection_all_pairs_d( boxes, boxes+11,
|
||||
boxes2.begin(), boxes2.end(),
|
||||
report(result),
|
||||
CGAL::Box_intersection_d::HALF_OPEN,
|
||||
CGAL::Box_intersection_d::BIPARTITE);
|
||||
std::size_t check6[4] = {409,810,904,1008};
|
||||
check_result( "All-pairs inters. 3x3+2, half-open", result, check6, 4);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_box_intersection();
|
||||
test_box_intersection_all_pairs();
|
||||
|
||||
int main() {
|
||||
test_box_intersection();
|
||||
test_box_intersection_all_pairs();
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||
# include <CGAL/internal/Static_filters/Equal_3.h>
|
||||
# include <CGAL/internal/Static_filters/Equal_2.h>
|
||||
|
|
@ -65,6 +64,7 @@
|
|||
# include <CGAL/internal/Static_filters/Do_intersect_2.h>
|
||||
#endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS
|
||||
|
||||
#include <CGAL/internal/Static_filters/Coplanar_3.h>
|
||||
#include <CGAL/internal/Static_filters/Compare_y_at_x_2.h>
|
||||
#include <CGAL/internal/Static_filters/Side_of_oriented_circle_2.h>
|
||||
#include <CGAL/internal/Static_filters/Side_of_oriented_sphere_3.h>
|
||||
|
|
@ -121,6 +121,7 @@ public:
|
|||
typedef Static_filters_predicates::Side_of_oriented_circle_2<K_base> Side_of_oriented_circle_2;
|
||||
typedef Static_filters_predicates::Side_of_oriented_sphere_3<K_base> Side_of_oriented_sphere_3;
|
||||
typedef Static_filters_predicates::Compare_squared_radius_3<K_base> Compare_squared_radius_3;
|
||||
typedef Static_filters_predicates::Coplanar_3<K_base,Self> Coplanar_3;
|
||||
|
||||
typedef Static_filters_predicates::Compare_weighted_squared_radius_3<K_base> Compare_weighted_squared_radius_3;
|
||||
typedef Static_filters_predicates::Power_side_of_oriented_power_sphere_3<K_base> Power_side_of_oriented_power_sphere_3;
|
||||
|
|
@ -138,28 +139,28 @@ public:
|
|||
{ return Collinear_3(); }
|
||||
|
||||
#ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||
Equal_2
|
||||
Equal_2
|
||||
equal_2_object() const
|
||||
{ return Equal_2(); }
|
||||
|
||||
Equal_3
|
||||
Equal_3
|
||||
equal_3_object() const
|
||||
{ return Equal_3(); }
|
||||
#endif // NOT CGAL_NO_EQUAL_3_STATIC_FILTERS
|
||||
|
||||
#ifndef CGAL_NO_COMPARE_X_2_STATIC_FILTERS
|
||||
Compare_x_2
|
||||
Compare_x_2
|
||||
compare_x_2_object() const
|
||||
{ return Compare_x_2(); }
|
||||
|
||||
Compare_y_2
|
||||
Compare_y_2
|
||||
compare_y_2_object() const
|
||||
{ return Compare_y_2(); }
|
||||
|
||||
#endif // NOT CGAL_NO_COMPARE_Y_2_STATIC_FILTERS
|
||||
|
||||
#ifndef CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
||||
Is_degenerate_3
|
||||
Is_degenerate_3
|
||||
is_degenerate_3_object() const
|
||||
{ return Is_degenerate_3(); }
|
||||
#endif // NOT CGAL_NO_IS_DEGENERATE_3_STATIC_FILTERS
|
||||
|
|
@ -182,7 +183,12 @@ Compare_y_2
|
|||
compare_squared_radius_3_object() const
|
||||
{ return Compare_squared_radius_3(); }
|
||||
|
||||
Power_side_of_oriented_power_sphere_3 power_side_of_oriented_power_sphere_3_object() const
|
||||
Coplanar_3
|
||||
coplanar_3_object() const
|
||||
{ return Coplanar_3(); }
|
||||
|
||||
Power_side_of_oriented_power_sphere_3
|
||||
power_side_of_oriented_power_sphere_3_object() const
|
||||
{ return Power_side_of_oriented_power_sphere_3();}
|
||||
|
||||
Compare_weighted_squared_radius_3
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ Release date: June 2020
|
|||
- **Breaking change**: the internal search tree is now lazily constructed. To disable it, one must call
|
||||
the new function `do_not_accelerate_distance_queries()` before the first distance query.
|
||||
|
||||
### Intersecting Sequences of dD Iso-oriented Boxes
|
||||
- Added parallel versions of the functions `CGAL::box_intersection_d()` and `CGAL::box_self_intersection_d()`.
|
||||
|
||||
### Polygon Mesh Processing
|
||||
|
||||
- Introduced a new function, `CGAL::Polygon_mesh_processing::remove_connected_components_of_negligible_size()`,
|
||||
|
|
@ -28,6 +31,8 @@ Release date: June 2020
|
|||
components that would be removed with the specified threshold, but without actually removing them.
|
||||
- The function `CGAL::Polygon_mesh_processing::stitch_borders()` now returns the number
|
||||
of halfedge pairs that were stitched.
|
||||
- Added parallel versions of the functions `CGAL::Polygon_mesh_processing::does_self_intersect()`
|
||||
and `CGAL::Polygon_mesh_processing::self_intersections()`.
|
||||
|
||||
### 2D Triangulations
|
||||
- To fix an inconsistency between code and documentation and to clarify which types of intersections
|
||||
|
|
|
|||
|
|
@ -488,7 +488,7 @@ CGAL_Kernel_pred_RT(Coplanar_orientation_3,
|
|||
coplanar_orientation_3_object)
|
||||
CGAL_Kernel_pred_RT(Coplanar_side_of_bounded_circle_3,
|
||||
coplanar_side_of_bounded_circle_3_object)
|
||||
CGAL_Kernel_pred(Coplanar_3,
|
||||
CGAL_Kernel_pred_RT(Coplanar_3,
|
||||
coplanar_3_object)
|
||||
CGAL_Kernel_pred(Counterclockwise_in_between_2,
|
||||
counterclockwise_in_between_2_object)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ endif(OpenMesh_FOUND)
|
|||
|
||||
find_package( TBB )
|
||||
if( TBB_FOUND )
|
||||
CGAL_target_use_TBB(self_intersections_example)
|
||||
CGAL_target_use_TBB(hausdorff_distance_remeshing_example)
|
||||
else()
|
||||
message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." )
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@
|
|||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
#include <CGAL/Real_timer.h>
|
||||
#include <CGAL/tags.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
|
||||
typedef boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
|
|
@ -20,20 +23,25 @@ int main(int argc, char* argv[])
|
|||
if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh))
|
||||
{
|
||||
std::cerr << "Not a valid input file." << std::endl;
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool intersecting = PMP::does_self_intersect(mesh,
|
||||
PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)));
|
||||
std::cout << "Using parallel mode? " << std::is_same<CGAL::Parallel_if_available_tag, CGAL::Parallel_tag>::value << std::endl;
|
||||
|
||||
std::cout
|
||||
<< (intersecting ? "There are self-intersections." : "There is no self-intersection.")
|
||||
<< std::endl;
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
|
||||
bool intersecting = PMP::does_self_intersect<CGAL::Parallel_if_available_tag>(mesh, CGAL::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)));
|
||||
std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl;
|
||||
std::cout << "Elapsed time (does self intersect): " << timer.time() << std::endl;
|
||||
|
||||
timer.reset();
|
||||
|
||||
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
|
||||
PMP::self_intersections(mesh, std::back_inserter(intersected_tris));
|
||||
|
||||
PMP::self_intersections<CGAL::Parallel_if_available_tag>(faces(mesh), mesh, std::back_inserter(intersected_tris));
|
||||
std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
std::cout << "Elapsed time (self intersections): " << timer.time() << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <CGAL/Filtered_predicate.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
|
||||
#include <CGAL/Aff_transformation_3.h>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
|
||||
|
||||
|
||||
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/enum.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
|
|
@ -38,7 +38,9 @@ protected:
|
|||
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
|
||||
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
|
||||
|
||||
public:
|
||||
Collect_face_bbox_per_edge_bbox(
|
||||
|
|
@ -80,9 +82,12 @@ protected:
|
|||
typedef boost::graph_traits<TriangleMesh> Graph_traits;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
|
||||
|
||||
typedef typename boost::property_traits<VertexPointMap>::reference Point;
|
||||
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
|
||||
|
||||
public:
|
||||
Collect_face_bbox_per_edge_bbox_with_coplanar_handling(
|
||||
const TriangleMesh& tm_faces,
|
||||
|
|
@ -162,7 +167,10 @@ protected:
|
|||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
|
||||
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
|
||||
|
||||
typedef typename boost::property_traits<VertexPointMap>::reference Point;
|
||||
|
||||
bool is_edge_target_incident_to_face(halfedge_descriptor hd,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/Intersection_type.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_of_coplanar_triangles_3.h>
|
||||
|
|
@ -156,7 +155,8 @@ class Intersection_of_triangle_meshes
|
|||
typedef typename graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename graph_traits::vertex_descriptor vertex_descriptor;
|
||||
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, halfedge_descriptor, Box_policy> Box;
|
||||
|
||||
typedef boost::unordered_set<face_descriptor> Face_set;
|
||||
typedef boost::unordered_map<edge_descriptor, Face_set> Edge_to_faces;
|
||||
|
|
@ -250,10 +250,11 @@ class Intersection_of_triangle_meshes
|
|||
if (callback_si.self_intersections_found())
|
||||
throw Self_intersection_exception();
|
||||
}
|
||||
else
|
||||
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
|
||||
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
|
||||
callback, cutoff );
|
||||
else {
|
||||
CGAL::box_intersection_d( face_boxes_ptr.begin(), face_boxes_ptr.end(),
|
||||
edge_boxes_ptr.begin(), edge_boxes_ptr.end(),
|
||||
callback, cutoff );
|
||||
}
|
||||
}
|
||||
|
||||
// for autorefinement
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ void collect_close_stitchable_boundary_edges(PM& pm,
|
|||
typedef boost::unordered_map<halfedge_descriptor, int> Halfedge_multiplicity;
|
||||
typedef std::vector<std::pair<halfedge_descriptor, halfedge_descriptor> > Halfedge_pairs;
|
||||
|
||||
typedef typename Box_intersection_d::Box_with_info_d<double, 3, edge_descriptor> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, edge_descriptor, Box_policy> Box;
|
||||
|
||||
typedef Union_find<vertex_descriptor> UF_vertices;
|
||||
typedef std::map<vertex_descriptor, typename UF_vertices::handle> Handle_map;
|
||||
|
|
@ -141,7 +142,6 @@ void collect_close_stitchable_boundary_edges(PM& pm,
|
|||
for(Box& b : boxes)
|
||||
box_ptrs.push_back(&b);
|
||||
|
||||
|
||||
Halfedge_multiplicity multiplicity;
|
||||
Halfedge_pairs matching_hedges;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,20 +17,27 @@
|
|||
|
||||
#include <CGAL/disable_warnings.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/boost/iterator/counting_iterator.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/boost/iterator/counting_iterator.hpp>
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
#include <CGAL/Polygon_mesh_processing/bbox.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/Side_of_triangle_mesh.h>
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing{
|
||||
namespace internal {
|
||||
|
|
@ -401,8 +408,10 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
|||
|
||||
typedef TriangleMesh TM;
|
||||
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor> Box;
|
||||
|
||||
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor, Box_policy> Box;
|
||||
|
||||
CGAL::Bbox_3 b1 = CGAL::Polygon_mesh_processing::bbox(tm1, np1),
|
||||
b2 = CGAL::Polygon_mesh_processing::bbox(tm2, np2);
|
||||
|
||||
|
|
@ -414,12 +423,8 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
|||
// make one box per facet
|
||||
std::vector<Box> boxes1;
|
||||
std::vector<Box> boxes2;
|
||||
boxes1.reserve(
|
||||
std::distance( boost::begin(face_range1), boost::end(face_range1) )
|
||||
);
|
||||
boxes2.reserve(
|
||||
std::distance( boost::begin(face_range2), boost::end(face_range2) )
|
||||
);
|
||||
boxes1.reserve(std::distance(boost::begin(face_range1), boost::end(face_range1)));
|
||||
boxes2.reserve(std::distance(boost::begin(face_range2), boost::end(face_range2)));
|
||||
|
||||
typedef typename GetVertexPointMap<TM, NamedParameters1>::const_type VertexPointMap1;
|
||||
typedef typename GetVertexPointMap<TM, NamedParameters2>::const_type VertexPointMap2;
|
||||
|
|
@ -433,6 +438,7 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
|||
typename boost::property_traits<VertexPointMap1>::value_type,
|
||||
typename boost::property_traits<VertexPointMap2>::value_type
|
||||
>::value) );
|
||||
|
||||
for(face_descriptor f : face_range1)
|
||||
{
|
||||
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm1), f));
|
||||
|
|
@ -449,7 +455,6 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
|||
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
|
||||
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
|
||||
|
||||
|
||||
// compute intersections filtered out by boxes
|
||||
typedef typename GetGeomTraits<TM, NamedParameters1>::type GeomTraits;
|
||||
GeomTraits gt = choose_parameter(get_parameter(np1, internal_np::geom_traits), GeomTraits());
|
||||
|
|
@ -459,10 +464,7 @@ compute_face_face_intersection(const FaceRange& face_range1,
|
|||
Box,
|
||||
OutputIterator,
|
||||
VertexPointMap1,
|
||||
VertexPointMap2> Intersect_faces(tm1, tm2,
|
||||
out,
|
||||
vpmap1, vpmap2,
|
||||
gt);
|
||||
VertexPointMap2> Intersect_faces(tm1, tm2, out, vpmap1, vpmap2, gt);
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||
|
|
@ -541,21 +543,16 @@ compute_face_polyline_intersection( const FaceRange& face_range,
|
|||
typename boost::range_value<Polyline>::type>::value));
|
||||
|
||||
std::vector<face_descriptor> faces;
|
||||
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
|
||||
faces.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
|
||||
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t, Box_policy> Box;
|
||||
|
||||
// make one box per facet
|
||||
std::vector<Box> boxes1;
|
||||
std::vector<Box> boxes2;
|
||||
boxes1.reserve(
|
||||
std::distance( boost::begin(face_range), boost::end(face_range) )
|
||||
);
|
||||
|
||||
boxes2.reserve(
|
||||
std::distance( boost::begin(polyline), boost::end(polyline) ) - 1
|
||||
);
|
||||
|
||||
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
|
||||
boxes2.reserve(std::distance(boost::begin(polyline), boost::end(polyline)) - 1);
|
||||
|
||||
for(face_descriptor f : face_range)
|
||||
{
|
||||
|
|
@ -571,7 +568,6 @@ compute_face_polyline_intersection( const FaceRange& face_range,
|
|||
}
|
||||
|
||||
// generate box pointers
|
||||
|
||||
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
|
||||
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
|
||||
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
|
||||
|
|
@ -587,12 +583,7 @@ compute_face_polyline_intersection( const FaceRange& face_range,
|
|||
OutputIterator,
|
||||
Polyline,
|
||||
VertexPointMap>
|
||||
Intersect_face_polyline(tm,
|
||||
faces,
|
||||
polyline,
|
||||
out,
|
||||
vpmap,
|
||||
gt);
|
||||
Intersect_face_polyline(tm, faces, polyline, out, vpmap, gt);
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||
|
|
@ -672,34 +663,32 @@ compute_face_polylines_intersection(const FaceRange& face_range,
|
|||
get_const_property_map(boost::vertex_point, tm));
|
||||
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
|
||||
typedef typename boost::range_value<PolylineRange>::type Polyline;
|
||||
CGAL_static_assertion(
|
||||
(boost::is_same<Point,
|
||||
typename boost::range_value<Polyline>::type>::value));
|
||||
CGAL_static_assertion((boost::is_same<Point, typename boost::range_value<Polyline>::type>::value));
|
||||
|
||||
std::vector<face_descriptor> faces;
|
||||
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
|
||||
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t>, Box_policy> Box;
|
||||
|
||||
// make one box per facet
|
||||
std::vector<Box> boxes1;
|
||||
std::vector<Box> boxes2;
|
||||
boxes1.reserve(
|
||||
std::distance( boost::begin(face_range), boost::end(face_range) )
|
||||
);
|
||||
boxes1.reserve(std::distance(boost::begin(face_range), boost::end(face_range)));
|
||||
|
||||
std::size_t polylines_size = 0;
|
||||
for(Polyline poly : polyline_range)
|
||||
{
|
||||
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
|
||||
}
|
||||
boxes2.reserve( polylines_size );
|
||||
boxes2.reserve(polylines_size);
|
||||
|
||||
for(face_descriptor f : face_range)
|
||||
{
|
||||
faces.push_back(f);
|
||||
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), std::make_pair(0, faces.size()-1)));
|
||||
}
|
||||
|
||||
std::size_t range_size = std::distance( boost::begin(polyline_range), boost::end(polyline_range) );
|
||||
for(std::size_t j = 0; j < range_size; ++j)
|
||||
{
|
||||
|
|
@ -730,12 +719,7 @@ compute_face_polylines_intersection(const FaceRange& face_range,
|
|||
PolylineRange,
|
||||
OutputIterator,
|
||||
VertexPointMap>
|
||||
Intersect_face_polyline(tm,
|
||||
faces,
|
||||
polyline_range,
|
||||
out,
|
||||
vpmap,
|
||||
gt);
|
||||
Intersect_face_polyline(tm, faces, polyline_range, out, vpmap, gt);
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||
|
|
@ -773,18 +757,15 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
|
|||
OutputIterator out,
|
||||
const Kernel& K)
|
||||
{
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t, Box_policy> Box;
|
||||
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
// make one box per facet
|
||||
std::vector<Box> boxes1;
|
||||
std::vector<Box> boxes2;
|
||||
boxes1.reserve(
|
||||
std::distance( boost::begin(polyline1), boost::end(polyline1) ) - 1
|
||||
);
|
||||
|
||||
boxes2.reserve(
|
||||
std::distance( boost::begin(polyline2), boost::end(polyline2) ) - 1
|
||||
);
|
||||
boxes1.reserve(std::distance(boost::begin(polyline1), boost::end(polyline1)) - 1);
|
||||
boxes2.reserve(std::distance(boost::begin(polyline2), boost::end(polyline2)) - 1);
|
||||
|
||||
for(std::size_t i =0; i< polyline1.size()-1; ++i)
|
||||
{
|
||||
|
|
@ -813,10 +794,7 @@ compute_polyline_polyline_intersection(const Polyline& polyline1,
|
|||
Kernel,
|
||||
Box,
|
||||
OutputIterator>
|
||||
intersect_polylines(polyline1,
|
||||
polyline2,
|
||||
out,
|
||||
K);
|
||||
intersect_polylines(polyline1, polyline2, out, K);
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||
|
|
@ -856,7 +834,9 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
|||
const Kernel& K)
|
||||
{
|
||||
//info.first is the index of the polyline in the range, info.second is the index of the point in the polyline
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t>, Box_policy> Box;
|
||||
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename boost::range_value<PolylineRange>::type Polyline;
|
||||
|
||||
|
|
@ -871,6 +851,7 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
|||
b1 += CGAL::bbox_3(poly.begin(), poly.end());
|
||||
}
|
||||
boxes1.reserve( polylines_size );
|
||||
|
||||
polylines_size = 0;
|
||||
for(Polyline poly : polylines2)
|
||||
{
|
||||
|
|
@ -878,9 +859,10 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
|||
b2 += CGAL::bbox_3(poly.begin(), poly.end());
|
||||
}
|
||||
boxes2.reserve(polylines_size);
|
||||
|
||||
|
||||
if(!CGAL::do_overlap(b1,b2))
|
||||
return out;
|
||||
|
||||
std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) );
|
||||
for(std::size_t j = 0; j < range_size; ++j)
|
||||
{
|
||||
|
|
@ -915,15 +897,11 @@ compute_polylines_polylines_intersection(const PolylineRange& polylines1,
|
|||
|
||||
|
||||
// compute intersections filtered out by boxes
|
||||
|
||||
internal::Intersect_polyline_ranges<PolylineRange,
|
||||
Kernel,
|
||||
Box,
|
||||
OutputIterator>
|
||||
intersect_polylines(polylines1,
|
||||
polylines2,
|
||||
out,
|
||||
K);
|
||||
intersect_polylines(polylines1, polylines2, out, K);
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
|
||||
|
|
@ -1595,7 +1573,9 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
|||
|
||||
bool report_overlap = choose_parameter(get_parameter(np, internal_np::overlap_test),false);
|
||||
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, TriangleMeshIterator> Mesh_box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, TriangleMeshIterator, Box_policy> Mesh_box;
|
||||
|
||||
std::vector<Mesh_box> boxes;
|
||||
boxes.reserve(std::distance(range.begin(), range.end()));
|
||||
|
||||
|
|
@ -1604,21 +1584,18 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
|||
boxes.push_back( Mesh_box(Polygon_mesh_processing::bbox(*it), it) );
|
||||
}
|
||||
|
||||
std::vector<Mesh_box*> boxes_ptr(
|
||||
boost::make_counting_iterator(&boxes[0]),
|
||||
boost::make_counting_iterator(&boxes[0]+boxes.size()));
|
||||
std::vector<Mesh_box*> boxes_ptr(boost::make_counting_iterator(&boxes[0]),
|
||||
boost::make_counting_iterator(&boxes[0]+boxes.size()));
|
||||
|
||||
typedef typename boost::range_value<NamedParametersRange>::type NP_rng;
|
||||
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
|
||||
typedef typename GetGeomTraits<TriangleMesh, NamedParameters, NP_rng>::type GT;
|
||||
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
|
||||
|
||||
|
||||
//get all the pairs of meshes intersecting (no strict inclusion test)
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
internal::Mesh_callback<TriangleMeshRange, GT, OutputIterator, NamedParametersRange> callback(range, out, report_overlap, gt, nps);
|
||||
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
|
||||
callback, cutoff);
|
||||
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), callback, cutoff);
|
||||
return callback.m_iterator;
|
||||
}
|
||||
|
||||
|
|
@ -1634,7 +1611,7 @@ OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
|||
|
||||
template <class TriangleMeshRange, class OutputIterator>
|
||||
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
|
||||
OutputIterator out)
|
||||
OutputIterator out)
|
||||
{
|
||||
return intersecting_meshes(range, out, parameters::all_default());
|
||||
}
|
||||
|
|
@ -1827,9 +1804,10 @@ surface_self_intersection(const TriangleMesh& tm,
|
|||
CGAL::Polygon_mesh_processing::parameters::all_default()
|
||||
);
|
||||
}
|
||||
} //end of namespace experimental
|
||||
|
||||
} } //end of namespace CGAL::Polygon_mesh_processing
|
||||
} //end of namespace experimental
|
||||
} //end of namespace Polygon_mesh_processing
|
||||
} //end of namespace CGAL
|
||||
|
||||
#include <CGAL/enable_warnings.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,215 +21,378 @@
|
|||
|
||||
#include <CGAL/disable_warnings.h>
|
||||
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
|
||||
#include <CGAL/Kernel/global_functions_3.h>
|
||||
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
|
||||
|
||||
#include <CGAL/algorithm.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
#include <CGAL/box_intersection_d.h>
|
||||
#include <CGAL/exceptions.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/iterator.h>
|
||||
#include <CGAL/Kernel/global_functions_3.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/use.h>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#endif
|
||||
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters
|
||||
#define CGAL_PMP_NP_CLASS NamedParameters
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
namespace Polygon_mesh_processing {
|
||||
namespace internal {
|
||||
template <class TM,//TriangleMesh
|
||||
class Kernel,
|
||||
class Box,
|
||||
class OutputIterator,
|
||||
class VertexPointMap>
|
||||
struct Intersect_facets
|
||||
{
|
||||
// wrapper to check whether anything is inserted to output iterator
|
||||
struct Output_iterator_with_bool
|
||||
{
|
||||
Output_iterator_with_bool(OutputIterator* out, bool* intersected)
|
||||
: m_iterator(out), m_intersected(intersected) { }
|
||||
|
||||
template<class T>
|
||||
void operator()(const T& t) {
|
||||
*m_intersected = true;
|
||||
*(*m_iterator)++ = t;
|
||||
// Checks for 'real' intersections, i.e. not simply a shared vertex or edge
|
||||
template <class GT, class TM, class VPM>
|
||||
bool do_faces_intersect(typename boost::graph_traits<TM>::halfedge_descriptor h,
|
||||
typename boost::graph_traits<TM>::halfedge_descriptor g,
|
||||
const TM& tmesh,
|
||||
const VPM vpmap,
|
||||
const typename GT::Construct_segment_3& construct_segment,
|
||||
const typename GT::Construct_triangle_3& construct_triangle,
|
||||
const typename GT::Do_intersect_3& do_intersect)
|
||||
{
|
||||
typedef typename boost::graph_traits<TM>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
|
||||
|
||||
typedef typename GT::Segment_3 Segment;
|
||||
typedef typename GT::Triangle_3 Triangle;
|
||||
|
||||
CGAL_assertion(!is_border(h, tmesh));
|
||||
CGAL_assertion(!is_border(g, tmesh));
|
||||
|
||||
vertex_descriptor hv[3], gv[3];
|
||||
hv[0] = target(h, tmesh);
|
||||
hv[1] = target(next(h, tmesh), tmesh);
|
||||
hv[2] = source(h, tmesh);
|
||||
|
||||
gv[0] = target(g, tmesh);
|
||||
gv[1] = target(next(g, tmesh), tmesh);
|
||||
gv[2] = source(g, tmesh);
|
||||
|
||||
// check for shared edge
|
||||
for(unsigned int i=0; i<3; ++i)
|
||||
{
|
||||
halfedge_descriptor opp_h = opposite(h, tmesh);
|
||||
if(face(opp_h, tmesh) == face(g, tmesh))
|
||||
{
|
||||
// there is an intersection if the four points are coplanar and the triangles overlap
|
||||
if(CGAL::coplanar(get(vpmap, hv[i]),
|
||||
get(vpmap, hv[(i+1)%3]),
|
||||
get(vpmap, hv[(i+2)%3]),
|
||||
get(vpmap, target(next(opp_h, tmesh), tmesh))) &&
|
||||
CGAL::coplanar_orientation(get(vpmap, hv[(i+2)%3]),
|
||||
get(vpmap, hv[i]),
|
||||
get(vpmap, hv[(i+1)%3]),
|
||||
get(vpmap, target(next(opp_h, tmesh), tmesh)))
|
||||
== CGAL::POSITIVE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there is a shared edge but no intersection
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
OutputIterator* m_iterator;
|
||||
bool* m_intersected;
|
||||
};
|
||||
// typedefs
|
||||
typedef typename Kernel::Segment_3 Segment;
|
||||
typedef typename Kernel::Triangle_3 Triangle;
|
||||
h = next(h, tmesh);
|
||||
}
|
||||
|
||||
// check for shared vertex --> maybe intersection, maybe not
|
||||
int i(0), j(0);
|
||||
bool shared = false;
|
||||
for(; i<3 && (! shared); ++i)
|
||||
{
|
||||
for(j=0; j<3 && (! shared); ++j)
|
||||
{
|
||||
if(hv[i] == gv[j])
|
||||
{
|
||||
shared = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(shared)
|
||||
break;
|
||||
}
|
||||
|
||||
if(shared)
|
||||
{
|
||||
// found shared vertex:
|
||||
CGAL_assertion(hv[i] == gv[j]);
|
||||
|
||||
// geometric check if the opposite segments intersect the triangles
|
||||
const Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2]));
|
||||
const Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2]));
|
||||
|
||||
const Segment s1 = construct_segment(get(vpmap, hv[(i+1)%3]), get(vpmap, hv[(i+2)%3]));
|
||||
const Segment s2 = construct_segment(get(vpmap, gv[(j+1)%3]), get(vpmap, gv[(j+2)%3]));
|
||||
|
||||
if(do_intersect(t1, s2))
|
||||
return true;
|
||||
else if(do_intersect(t2, s1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for geometric intersection
|
||||
const Triangle th = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2]));
|
||||
const Triangle tg = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2]));
|
||||
if(do_intersect(th, tg))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
template <class Box, class TM, class VPM, class GT,
|
||||
class OutputIterator>
|
||||
struct Strict_intersect_faces // "strict" as in "not sharing a subface"
|
||||
{
|
||||
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename boost::property_map<TM, boost::vertex_point_t>::const_type Ppmap;
|
||||
|
||||
// members
|
||||
mutable OutputIterator m_iterator;
|
||||
const TM& m_tmesh;
|
||||
const VertexPointMap m_vpmap;
|
||||
mutable OutputIterator m_iterator;
|
||||
mutable bool m_intersected;
|
||||
mutable boost::function_output_iterator<Output_iterator_with_bool> m_iterator_wrapper;
|
||||
const VPM m_vpmap;
|
||||
typename GT::Construct_segment_3 m_construct_segment;
|
||||
typename GT::Construct_triangle_3 m_construct_triangle;
|
||||
typename GT::Do_intersect_3 m_do_intersect;
|
||||
|
||||
typename Kernel::Construct_segment_3 segment_functor;
|
||||
typename Kernel::Construct_triangle_3 triangle_functor;
|
||||
typename Kernel::Do_intersect_3 do_intersect_3_functor;
|
||||
|
||||
|
||||
Intersect_facets(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel)
|
||||
Strict_intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it)
|
||||
:
|
||||
m_tmesh(tmesh),
|
||||
m_vpmap(vpmap),
|
||||
m_iterator(it),
|
||||
m_intersected(false),
|
||||
m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)),
|
||||
segment_functor(kernel.construct_segment_3_object()),
|
||||
triangle_functor(kernel.construct_triangle_3_object()),
|
||||
do_intersect_3_functor(kernel.do_intersect_3_object())
|
||||
{ }
|
||||
m_iterator(it),
|
||||
m_tmesh(tmesh),
|
||||
m_vpmap(vpmap),
|
||||
m_construct_segment(gt.construct_segment_3_object()),
|
||||
m_construct_triangle(gt.construct_triangle_3_object()),
|
||||
m_do_intersect(gt.do_intersect_3_object())
|
||||
{}
|
||||
|
||||
void operator()(const Box* b, const Box* c) const
|
||||
{
|
||||
halfedge_descriptor h = halfedge(b->info(), m_tmesh);
|
||||
halfedge_descriptor opp_h;
|
||||
const halfedge_descriptor h = halfedge(b->info(), m_tmesh);
|
||||
const halfedge_descriptor g = halfedge(c->info(), m_tmesh);
|
||||
|
||||
// check for shared egde
|
||||
for(unsigned int i=0; i<3; ++i){
|
||||
opp_h = opposite(h, m_tmesh);
|
||||
if(face(opp_h, m_tmesh) == c->info()){
|
||||
// there is an intersection if the four points are coplanar and
|
||||
// the triangles overlap
|
||||
if(CGAL::coplanar(get(m_vpmap, target(h, m_tmesh)),
|
||||
get(m_vpmap, target(next(h, m_tmesh), m_tmesh)),
|
||||
get(m_vpmap, source(h, m_tmesh)),
|
||||
get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) &&
|
||||
CGAL::coplanar_orientation(get(m_vpmap, source(h, m_tmesh)),
|
||||
get(m_vpmap, target(h, m_tmesh)),
|
||||
get(m_vpmap, target(next(h, m_tmesh), m_tmesh)),
|
||||
get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)))
|
||||
== CGAL::POSITIVE){
|
||||
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
|
||||
return;
|
||||
} else { // there is a shared edge but no intersection
|
||||
return;
|
||||
}
|
||||
}
|
||||
h = next(h, m_tmesh);
|
||||
}
|
||||
|
||||
// check for shared vertex --> maybe intersection, maybe not
|
||||
halfedge_descriptor g = halfedge(c->info(),m_tmesh);
|
||||
halfedge_descriptor v;
|
||||
|
||||
if(target(h,m_tmesh) == target(g,m_tmesh))
|
||||
v = g;
|
||||
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
|
||||
v = next(g,m_tmesh);
|
||||
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
|
||||
v = next(next(g,m_tmesh),m_tmesh);
|
||||
|
||||
if(v == halfedge_descriptor()){
|
||||
h = next(h,m_tmesh);
|
||||
if(target(h,m_tmesh) == target(g,m_tmesh))
|
||||
v = g;
|
||||
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
|
||||
v = next(g,m_tmesh);
|
||||
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
|
||||
v = next(next(g,m_tmesh),m_tmesh);
|
||||
if(v == halfedge_descriptor()){
|
||||
h = next(h,m_tmesh);
|
||||
if(target(h,m_tmesh) == target(g,m_tmesh))
|
||||
v = g;
|
||||
if(target(h,m_tmesh) == target(next(g,m_tmesh),m_tmesh))
|
||||
v = next(g,m_tmesh);
|
||||
if(target(h,m_tmesh) == target(next(next(g,m_tmesh),m_tmesh),m_tmesh))
|
||||
v = next(next(g,m_tmesh),m_tmesh);
|
||||
}
|
||||
}
|
||||
|
||||
if(v != halfedge_descriptor()){
|
||||
// found shared vertex:
|
||||
CGAL_assertion(target(h,m_tmesh) == target(v,m_tmesh));
|
||||
// geometric check if the opposite segments intersect the triangles
|
||||
Triangle t1 = triangle_functor( get(m_vpmap,target(h,m_tmesh)),
|
||||
get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
|
||||
Triangle t2 = triangle_functor( get(m_vpmap, target(v,m_tmesh)),
|
||||
get(m_vpmap, target(next(v,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh)));
|
||||
|
||||
Segment s1 = segment_functor( get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
|
||||
Segment s2 = segment_functor( get(m_vpmap, target(next(v,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh)));
|
||||
|
||||
if(do_intersect_3_functor(t1,s2)){
|
||||
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
|
||||
} else if(do_intersect_3_functor(t2,s1)){
|
||||
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// check for geometric intersection
|
||||
Triangle t1 = triangle_functor( get(m_vpmap, target(h,m_tmesh)),
|
||||
get(m_vpmap, target(next(h,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh)));
|
||||
Triangle t2 = triangle_functor( get(m_vpmap, target(g,m_tmesh)),
|
||||
get(m_vpmap, target(next(g,m_tmesh),m_tmesh)),
|
||||
get(m_vpmap, target(next(next(g,m_tmesh),m_tmesh),m_tmesh)));
|
||||
if(do_intersect_3_functor(t1, t2)){
|
||||
*m_iterator_wrapper++ = std::make_pair(b->info(), c->info());
|
||||
}
|
||||
} // end operator ()
|
||||
}; // end struct Intersect_facets
|
||||
|
||||
struct Throw_at_output {
|
||||
class Throw_at_output_exception: public std::exception
|
||||
{ };
|
||||
|
||||
template<class T>
|
||||
void operator()(const T& /* t */) const {
|
||||
throw Throw_at_output_exception();
|
||||
if(do_faces_intersect<GT>(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect))
|
||||
*m_iterator++ = std::make_pair(b->info(), c->info());
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace internal
|
||||
template <class ConcurrencyTag,
|
||||
class TriangleMesh,
|
||||
class FaceRange,
|
||||
class FacePairOutputIterator,
|
||||
class NamedParameters>
|
||||
FacePairOutputIterator
|
||||
self_intersections_impl(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
FacePairOutputIterator out,
|
||||
const bool throw_on_SI,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
namespace Polygon_mesh_processing {
|
||||
using CGAL::parameters::choose_parameter;
|
||||
using CGAL::parameters::get_parameter;
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
template <class TriangleMesh
|
||||
, class FaceRange
|
||||
, class OutputIterator
|
||||
, class NamedParameters
|
||||
>
|
||||
OutputIterator
|
||||
self_intersections( const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np);
|
||||
typedef TriangleMesh TM;
|
||||
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
|
||||
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor, Box_policy> Box;
|
||||
|
||||
typedef typename GetGeomTraits<TM, NamedParameters>::type GT;
|
||||
GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT());
|
||||
|
||||
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VPM;
|
||||
VPM vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, tmesh));
|
||||
|
||||
const unsigned int seed = choose_parameter(get_parameter(np, internal_np::random_seed), 0);
|
||||
CGAL_USE(seed); // used in the random shuffle of the range, which is only done to balance tasks in parallel
|
||||
|
||||
const std::ptrdiff_t cutoff = 2000;
|
||||
|
||||
// make one box per face
|
||||
std::vector<Box> boxes;
|
||||
boxes.reserve(std::distance(std::begin(face_range), std::end(face_range)));
|
||||
|
||||
// This loop is very cheap, so there is hardly anything to gain from parallelizing it
|
||||
for(face_descriptor f : face_range)
|
||||
{
|
||||
halfedge_descriptor h = halfedge(f, tmesh);
|
||||
typename boost::property_traits<VPM>::reference
|
||||
p = get(vpmap, target(h,tmesh)),
|
||||
q = get(vpmap, target(next(h, tmesh), tmesh)),
|
||||
r = get(vpmap, target(prev(h, tmesh), tmesh));
|
||||
|
||||
// tiny fixme: if f is degenerate, we might still have a real intersection between f
|
||||
// and another face f', but right now we are not creating a box for f and thus not returning those
|
||||
if(collinear(p, q, r))
|
||||
{
|
||||
if(throw_on_SI)
|
||||
throw CGAL::internal::Throw_at_output_exception();
|
||||
else
|
||||
*out++= std::make_pair(f, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f));
|
||||
}
|
||||
}
|
||||
|
||||
// generate box pointers
|
||||
std::vector<const Box*> box_ptr;
|
||||
box_ptr.reserve(boxes.size());
|
||||
|
||||
for(Box& b : boxes)
|
||||
box_ptr.push_back(&b);
|
||||
|
||||
// In case we are throwing, like in `does_self_intersect()`, we keep the geometric test to throw ASAP.
|
||||
// This is obviously not optimal if there are no or few self-intersections: it would be a greater speed-up
|
||||
// to do the same as for `self_intersections()`. However, doing like `self_intersections()` would
|
||||
// be a major slow-down over sequential code if there are a lot of self-intersections...
|
||||
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> Throwing_output_iterator;
|
||||
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, Throwing_output_iterator> Throwing_filter;
|
||||
Throwing_filter throwing_filter(tmesh, vpmap, gt, Throwing_output_iterator());
|
||||
|
||||
#if !defined(CGAL_LINKED_WITH_TBB)
|
||||
CGAL_static_assertion_msg (!(std::is_convertible<ConcurrencyTag, Parallel_tag>::value),
|
||||
"Parallel_tag is enabled but TBB is unavailable.");
|
||||
#else
|
||||
if(std::is_convertible<ConcurrencyTag, Parallel_tag>::value)
|
||||
{
|
||||
// We are going to split the range into a number of smaller ranges. To handle
|
||||
// smaller trees of roughly the same size, we first apply a random shuffle to the range
|
||||
CGAL::Random rng(seed);
|
||||
CGAL::cpp98::random_shuffle(box_ptr.begin(), box_ptr.end(), rng);
|
||||
|
||||
// Write in a concurrent vector all pairs that intersect
|
||||
typedef tbb::concurrent_vector<std::pair<face_descriptor, face_descriptor> > Face_pairs;
|
||||
typedef std::back_insert_iterator<Face_pairs> Face_pairs_back_inserter;
|
||||
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, Face_pairs_back_inserter> Intersecting_faces_filter;
|
||||
|
||||
Face_pairs face_pairs;
|
||||
Intersecting_faces_filter callback(tmesh, vpmap, gt, std::back_inserter(face_pairs));
|
||||
|
||||
if(throw_on_SI)
|
||||
CGAL::box_self_intersection_d<ConcurrencyTag>(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff);
|
||||
else
|
||||
CGAL::box_self_intersection_d<ConcurrencyTag>(box_ptr.begin(), box_ptr.end(), callback, cutoff);
|
||||
|
||||
// Sequentially write into the output iterator
|
||||
for(std::size_t i=0; i<face_pairs.size(); ++i)
|
||||
*out ++= face_pairs[i];
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sequential version of the code
|
||||
// Compute self-intersections filtered out by boxes
|
||||
typedef internal::Strict_intersect_faces<Box, TM, VPM, GT, FacePairOutputIterator> Intersecting_faces_filter;
|
||||
Intersecting_faces_filter intersect_faces(tmesh, vpmap, gt, out);
|
||||
|
||||
if(throw_on_SI)
|
||||
CGAL::box_self_intersection_d<CGAL::Sequential_tag>(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff);
|
||||
else
|
||||
CGAL::box_self_intersection_d<CGAL::Sequential_tag>(box_ptr.begin(), box_ptr.end(), intersect_faces, cutoff);
|
||||
|
||||
return intersect_faces.m_iterator;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/*!
|
||||
* \ingroup PMP_intersection_grp
|
||||
* collects intersections between a subset of faces of a triangulated surface mesh.
|
||||
* Two faces are said to intersect if the corresponding triangles intersect
|
||||
* and the intersection is not an edge nor a vertex incident to both faces.
|
||||
*
|
||||
* This function depends on the package \ref PkgBoxIntersectionD
|
||||
*
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
|
||||
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
|
||||
* @tparam FaceRange a model of `ConstRange` with value type `boost::graph_traits<TriangleMesh>::%face_descriptor`.
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type
|
||||
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param face_range the range of faces to check for self-intersection.
|
||||
* @param tmesh the triangulated surface mesh to be checked
|
||||
* @param out output iterator to be filled with all pairs of non-adjacent faces that intersect
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
|
||||
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*/
|
||||
template < class ConcurrencyTag = Sequential_tag,
|
||||
class TriangleMesh,
|
||||
class FaceRange,
|
||||
class FacePairOutputIterator,
|
||||
class NamedParameters>
|
||||
FacePairOutputIterator
|
||||
self_intersections(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
FacePairOutputIterator out,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
return internal::self_intersections_impl<ConcurrencyTag>(face_range, tmesh, out, false /*don't throw*/, np);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <class ConcurrencyTag = Sequential_tag,
|
||||
class TriangleMesh,
|
||||
class FaceRange,
|
||||
class FacePairOutputIterator>
|
||||
FacePairOutputIterator
|
||||
self_intersections(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
FacePairOutputIterator out)
|
||||
{
|
||||
return self_intersections<ConcurrencyTag>(face_range, tmesh, out, CGAL::parameters::all_default());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/**
|
||||
* \ingroup PMP_intersection_grp
|
||||
* detects and records self-intersections of a triangulated surface mesh.
|
||||
* collects intersections between all the faces of a triangulated surface mesh.
|
||||
* Two faces are said to intersect if the corresponding triangles intersect
|
||||
* and the intersection is not an edge nor a vertex incident to both faces.
|
||||
*
|
||||
* This function depends on the package \ref PkgBoxIntersectionD
|
||||
*
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
|
||||
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam OutputIterator a model of `OutputIterator` holding objects of type
|
||||
* @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type
|
||||
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
|
|
@ -249,181 +412,35 @@ self_intersections( const FaceRange& face_range,
|
|||
*
|
||||
* @return `out`
|
||||
*/
|
||||
template <class TriangleMesh
|
||||
, class OutputIterator
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
, class NamedParameters
|
||||
#else //avoid ambiguity with self_intersections(faces, tmesh, out)
|
||||
, class P, class T, class R
|
||||
#endif
|
||||
>
|
||||
OutputIterator
|
||||
self_intersections(const TriangleMesh& tmesh
|
||||
, OutputIterator out
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
, const NamedParameters& np)
|
||||
#else
|
||||
, const Named_function_parameters<P,T,R>& np)
|
||||
#endif
|
||||
template <class ConcurrencyTag = Sequential_tag,
|
||||
class TriangleMesh,
|
||||
class FacePairOutputIterator,
|
||||
class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
|
||||
FacePairOutputIterator
|
||||
self_intersections(const TriangleMesh& tmesh,
|
||||
FacePairOutputIterator out,
|
||||
const CGAL_PMP_NP_CLASS& np)
|
||||
{
|
||||
return self_intersections(faces(tmesh), tmesh, out, np);
|
||||
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, np);
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <class TriangleMesh, class OutputIterator>
|
||||
OutputIterator
|
||||
self_intersections(const TriangleMesh& tmesh, OutputIterator out)
|
||||
template <class ConcurrencyTag = Sequential_tag, class TriangleMesh, class FacePairOutputIterator>
|
||||
FacePairOutputIterator
|
||||
self_intersections(const TriangleMesh& tmesh, FacePairOutputIterator out)
|
||||
{
|
||||
return self_intersections(tmesh, out,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
return self_intersections<ConcurrencyTag>(faces(tmesh), tmesh, out, parameters::all_default());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
* \ingroup PMP_intersection_grp
|
||||
* Same as above but the self-intersections reported
|
||||
* are only limited to the faces in `face_range`.
|
||||
*
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
|
||||
* model of `Range`.
|
||||
* Its iterator type is `RandomAccessIterator`.
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam OutputIterator a model of `OutputIterator` holding objects of type
|
||||
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param face_range the range of faces to check for self-intersection.
|
||||
* @param tmesh the triangulated surface mesh to be checked
|
||||
* @param out output iterator to be filled with all pairs of non-adjacent faces that intersect
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
|
||||
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
|
||||
*/
|
||||
template <class TriangleMesh
|
||||
, class FaceRange
|
||||
, class OutputIterator
|
||||
, class NamedParameters
|
||||
>
|
||||
OutputIterator
|
||||
self_intersections( const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
OutputIterator out,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
typedef TriangleMesh TM;
|
||||
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
|
||||
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor> Box;
|
||||
|
||||
// make one box per facet
|
||||
std::vector<Box> boxes;
|
||||
boxes.reserve(
|
||||
std::distance( boost::begin(face_range), boost::end(face_range) )
|
||||
);
|
||||
|
||||
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VertexPointMap;
|
||||
VertexPointMap vpmap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, tmesh));
|
||||
|
||||
for(face_descriptor f : face_range)
|
||||
{
|
||||
typename boost::property_traits<VertexPointMap>::reference
|
||||
p = get(vpmap, target(halfedge(f,tmesh),tmesh)),
|
||||
q = get(vpmap, target(next(halfedge(f, tmesh), tmesh), tmesh)),
|
||||
r = get(vpmap, target(next(next(halfedge(f, tmesh), tmesh), tmesh), tmesh));
|
||||
|
||||
if ( collinear(p, q, r) )
|
||||
*out++= std::make_pair(f,f);
|
||||
else
|
||||
boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f));
|
||||
}
|
||||
// generate box pointers
|
||||
std::vector<const Box*> box_ptr;
|
||||
box_ptr.reserve(num_faces(tmesh));
|
||||
|
||||
for(Box& b : boxes)
|
||||
box_ptr.push_back(&b);
|
||||
|
||||
// compute self-intersections filtered out by boxes
|
||||
typedef typename GetGeomTraits<TM, NamedParameters>::type GeomTraits;
|
||||
CGAL::internal::Intersect_facets<TM,GeomTraits,Box,OutputIterator,VertexPointMap>
|
||||
intersect_facets(tmesh, out, vpmap,
|
||||
parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits()));
|
||||
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff);
|
||||
return intersect_facets.m_iterator;
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <class TriangleMesh
|
||||
, class FaceRange
|
||||
, class OutputIterator
|
||||
>
|
||||
OutputIterator self_intersections(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
OutputIterator out)
|
||||
{
|
||||
return self_intersections(face_range, tmesh, out,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/**
|
||||
* \ingroup PMP_intersection_grp
|
||||
* tests if a triangulated surface mesh self-intersects.
|
||||
* This function depends on the package \ref PkgBoxIntersectionD
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tmesh the triangulated surface mesh to be tested
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
|
||||
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return true if `tmesh` self-intersects
|
||||
*/
|
||||
template <class TriangleMesh
|
||||
, class CGAL_PMP_NP_TEMPLATE_PARAMETERS
|
||||
>
|
||||
bool does_self_intersect(const TriangleMesh& tmesh
|
||||
, const CGAL_PMP_NP_CLASS& np)
|
||||
{
|
||||
CGAL_precondition(CGAL::is_triangle_mesh(tmesh));
|
||||
|
||||
try
|
||||
{
|
||||
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> OutputIterator;
|
||||
self_intersections(tmesh, OutputIterator(), np);
|
||||
}
|
||||
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
|
||||
{ return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PMP_intersection_grp
|
||||
* tests if a set of faces of a triangulated surface mesh self-intersects.
|
||||
* This function depends on the package \ref PkgBoxIntersectionD
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
|
||||
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
|
||||
* @tparam FaceRange a range of `face_descriptor`
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
|
|
@ -439,12 +456,12 @@ bool does_self_intersect(const TriangleMesh& tmesh
|
|||
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `SelfIntersectionTraits` \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return true if the faces in `face_range` self-intersect
|
||||
* @return `true` if the faces in `face_range` self-intersect
|
||||
*/
|
||||
template <class FaceRange,
|
||||
template <class ConcurrencyTag = Sequential_tag,
|
||||
class FaceRange,
|
||||
class TriangleMesh,
|
||||
class NamedParameters
|
||||
>
|
||||
class NamedParameters>
|
||||
bool does_self_intersect(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh,
|
||||
const NamedParameters& np)
|
||||
|
|
@ -453,35 +470,65 @@ bool does_self_intersect(const FaceRange& face_range,
|
|||
|
||||
try
|
||||
{
|
||||
typedef boost::function_output_iterator<CGAL::internal::Throw_at_output> OutputIterator;
|
||||
self_intersections(face_range, tmesh, OutputIterator(), np);
|
||||
CGAL::Emptyset_iterator unused_out;
|
||||
internal::self_intersections_impl<ConcurrencyTag>(face_range, tmesh, unused_out, true /*throw*/, np);
|
||||
}
|
||||
catch(CGAL::internal::Throw_at_output_exception&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
|
||||
{ return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <class TriangleMesh>
|
||||
bool does_self_intersect(const TriangleMesh& tmesh)
|
||||
/**
|
||||
* \ingroup PMP_intersection_grp
|
||||
* tests if a triangulated surface mesh self-intersects.
|
||||
* This function depends on the package \ref PkgBoxIntersectionD
|
||||
* @pre `CGAL::is_triangle_mesh(tmesh)`
|
||||
*
|
||||
* @tparam ConcurrencyTag enables sequential versus parallel algorithm.
|
||||
* Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`.
|
||||
* @tparam TriangleMesh a model of `FaceListGraph`
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tmesh the triangulated surface mesh to be tested
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tmesh`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
|
||||
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*
|
||||
* @return `true` if `tmesh` self-intersects
|
||||
*/
|
||||
template <class ConcurrencyTag = Sequential_tag,
|
||||
class TriangleMesh,
|
||||
class CGAL_PMP_NP_TEMPLATE_PARAMETERS>
|
||||
bool does_self_intersect(const TriangleMesh& tmesh,
|
||||
const CGAL_PMP_NP_CLASS& np)
|
||||
{
|
||||
return does_self_intersect(tmesh,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
return does_self_intersect<ConcurrencyTag>(faces(tmesh), tmesh, np);
|
||||
}
|
||||
|
||||
template <class FaceRange, class TriangleMesh>
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <class ConcurrencyTag = Sequential_tag, class TriangleMesh>
|
||||
bool does_self_intersect(const TriangleMesh& tmesh)
|
||||
{
|
||||
return does_self_intersect<ConcurrencyTag>(faces(tmesh), tmesh, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
template <class ConcurrencyTag = Sequential_tag, class FaceRange, class TriangleMesh>
|
||||
bool does_self_intersect(const FaceRange& face_range,
|
||||
const TriangleMesh& tmesh)
|
||||
{
|
||||
return does_self_intersect(face_range, tmesh,
|
||||
CGAL::Polygon_mesh_processing::parameters::all_default());
|
||||
return does_self_intersect<ConcurrencyTag>(face_range, tmesh, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
}// end namespace Polygon_mesh_processing
|
||||
|
||||
}// namespace Polygon_mesh_processing
|
||||
}// namespace CGAL
|
||||
|
||||
#include <CGAL/enable_warnings.h>
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ endif()
|
|||
|
||||
if( TBB_FOUND )
|
||||
CGAL_target_use_TBB(test_pmp_distance)
|
||||
CGAL_target_use_TBB(self_intersection_surface_mesh_test)
|
||||
else()
|
||||
message( STATUS "NOTICE: Intel TBB was not found. test_pmp_distance will use sequential code." )
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,22 +1,25 @@
|
|||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/self_intersections.h>
|
||||
|
||||
#include <CGAL/tags.h>
|
||||
#include <CGAL/Timer.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic;
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Epec;
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel EPICK;
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel EPECK;
|
||||
|
||||
namespace PMP = ::CGAL::Polygon_mesh_processing;
|
||||
namespace CP = ::CGAL::parameters;
|
||||
|
||||
template <typename K>
|
||||
int
|
||||
test_self_intersections(const char* filename, const bool expected)
|
||||
int test_self_intersections(const char* filename,
|
||||
const bool expected)
|
||||
{
|
||||
typedef CGAL::Surface_mesh<typename K::Point_3> Mesh;
|
||||
typedef typename boost::graph_traits<Mesh>::face_descriptor face_descriptor;
|
||||
|
|
@ -35,18 +38,36 @@ test_self_intersections(const char* filename, const bool expected)
|
|||
timer.start();
|
||||
|
||||
std::vector<std::pair<face_descriptor, face_descriptor> > intersected_tris;
|
||||
CGAL::Polygon_mesh_processing::self_intersections(
|
||||
m,
|
||||
std::back_inserter(intersected_tris),
|
||||
CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
|
||||
if(std::is_same<K, EPECK>::value) // EPECK isn't threadsafe
|
||||
{
|
||||
PMP::self_intersections<CGAL::Sequential_tag>(
|
||||
m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
}
|
||||
else
|
||||
{
|
||||
PMP::self_intersections<CGAL::Parallel_if_available_tag>(
|
||||
m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
}
|
||||
bool intersecting_1 = !intersected_tris.empty();
|
||||
|
||||
std::cout << "self_intersections test took " << timer.time() << " sec." << std::endl;
|
||||
std::cout << intersected_tris.size() << " pairs of triangles are intersecting." << std::endl;
|
||||
|
||||
timer.reset();
|
||||
bool intersecting_2 = CGAL::Polygon_mesh_processing::does_self_intersect(m,
|
||||
CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
|
||||
bool intersecting_2;
|
||||
|
||||
if(std::is_same<K, EPECK>::value) // EPECK isn't threadsafe
|
||||
{
|
||||
intersecting_2 = PMP::does_self_intersect<CGAL::Sequential_tag>(
|
||||
m, CP::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
}
|
||||
else
|
||||
{
|
||||
intersecting_2 = PMP::does_self_intersect<CGAL::Parallel_if_available_tag>(
|
||||
m, CP::vertex_index_map(get(CGAL::vertex_point, m)));
|
||||
}
|
||||
|
||||
std::cout << "does_self_intersect test took " << timer.time() << " sec." << std::endl;
|
||||
std::cout << (intersecting_2 ? "There is a self-intersection." :
|
||||
|
|
@ -77,11 +98,11 @@ int main(int argc, char** argv)
|
|||
assert(!ss.fail()); // make sure that argv[2] is either 'true' or 'false'
|
||||
}
|
||||
|
||||
std::cout << "First test (Epic):" << std::endl;
|
||||
int r = test_self_intersections<Epic>(filename, expected);
|
||||
std::cout << "First test (EPICK):" << std::endl;
|
||||
int r = test_self_intersections<EPICK>(filename, expected);
|
||||
|
||||
std::cout << "First test (Epec):" << std::endl;
|
||||
r += test_self_intersections<Epec>(filename, expected);
|
||||
std::cout << "First test (EPECK):" << std::endl;
|
||||
r += test_self_intersections<EPECK>(filename, expected);
|
||||
|
||||
// Second test ---------------------------------------------------------------
|
||||
expected = true;
|
||||
|
|
@ -93,11 +114,11 @@ int main(int argc, char** argv)
|
|||
assert(!ss.fail());
|
||||
}
|
||||
|
||||
std::cout << "Second test (Epic):" << std::endl;
|
||||
r += test_self_intersections<Epic>(filename, expected);
|
||||
std::cout << "Second test (EPICK):" << std::endl;
|
||||
r += test_self_intersections<EPICK>(filename, expected);
|
||||
|
||||
std::cout << "Second test (Epec):" << std::endl;
|
||||
r += test_self_intersections<Epec>(filename, expected);
|
||||
std::cout << "Second test (EPECK):" << std::endl;
|
||||
r += test_self_intersections<EPECK>(filename, expected);
|
||||
|
||||
// Third test ----------------------------------------------------------------
|
||||
expected = true;
|
||||
|
|
@ -109,11 +130,11 @@ int main(int argc, char** argv)
|
|||
assert(!ss.fail());
|
||||
}
|
||||
|
||||
std::cout << "Third test (Epic):" << std::endl;
|
||||
r += test_self_intersections<Epic>(filename, expected);
|
||||
std::cout << "Third test (EPICK):" << std::endl;
|
||||
r += test_self_intersections<EPICK>(filename, expected);
|
||||
|
||||
std::cout << "Third test (Epec):" << std::endl;
|
||||
r += test_self_intersections<Epec>(filename, expected);
|
||||
std::cout << "Third test (EPECK):" << std::endl;
|
||||
r += test_self_intersections<EPECK>(filename, expected);
|
||||
|
||||
// Fourth test ----------------------------------------------------------------
|
||||
expected = true;
|
||||
|
|
@ -125,11 +146,11 @@ int main(int argc, char** argv)
|
|||
assert(!ss.fail());
|
||||
}
|
||||
|
||||
std::cout << "Fourth test (Epic):" << std::endl;
|
||||
r += test_self_intersections<Epic>(filename, expected);
|
||||
std::cout << "Fourth test (EPICK):" << std::endl;
|
||||
r += test_self_intersections<EPICK>(filename, expected);
|
||||
|
||||
std::cout << "Fourth test (Epec):" << std::endl;
|
||||
r += test_self_intersections<Epec>(filename, expected);
|
||||
std::cout << "Fourth test (EPECK):" << std::endl;
|
||||
r += test_self_intersections<EPECK>(filename, expected);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,7 +251,10 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND)
|
|||
add_item(scene_edit_box_item Plugins/PCA/Scene_edit_box_item.cpp )
|
||||
add_item(scene_image_item Scene_image_item.cpp)
|
||||
add_item(scene_surface_mesh_item Scene_surface_mesh_item.cpp)
|
||||
|
||||
|
||||
if(TBB_FOUND)
|
||||
CGAL_target_use_TBB(scene_surface_mesh_item)
|
||||
endif()
|
||||
# special
|
||||
|
||||
add_item(scene_item_decorator Scene_polyhedron_item_decorator.cpp )
|
||||
|
|
@ -262,6 +265,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND)
|
|||
|
||||
add_item(scene_selection_item Scene_polyhedron_selection_item.cpp)
|
||||
target_link_libraries(scene_selection_item PUBLIC scene_item_decorator scene_k_ring_selection)
|
||||
if(TBB_FOUND)
|
||||
CGAL_target_use_TBB(scene_selection_item)
|
||||
endif()
|
||||
|
||||
add_item(scene_shortest_path_item Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp)
|
||||
target_link_libraries(scene_shortest_path_item PUBLIC scene_item_decorator scene_surface_mesh_item scene_polylines_item)
|
||||
|
|
|
|||
|
|
@ -9,13 +9,16 @@
|
|||
|
||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||
#include <CGAL/Three/Three.h>
|
||||
#include <fstream>
|
||||
|
||||
#include <CGAL/exceptions.h>
|
||||
#include <CGAL/IO/File_scanner_OFF.h>
|
||||
#include <CGAL/IO/OBJ_reader.h>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
class Polyhedron_demo_off_plugin :
|
||||
public QObject,
|
||||
|
|
@ -186,7 +189,7 @@ Polyhedron_demo_off_plugin::load_off(QFileInfo fileinfo) {
|
|||
try{
|
||||
CGAL::Polygon_mesh_processing::non_manifold_vertices(*surface_mesh, OutputIterator());
|
||||
}
|
||||
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
|
||||
catch( CGAL::internal::Throw_at_output_exception& )
|
||||
{
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
|
|
|||
|
|
@ -2497,7 +2497,7 @@ QString Scene_polyhedron_selection_item::computeStats(int type)
|
|||
return QString("n/a");
|
||||
if(is_triangle_mesh(*d->poly)){
|
||||
bool self_intersect
|
||||
= CGAL::Polygon_mesh_processing::does_self_intersect(*(d->poly));
|
||||
= CGAL::Polygon_mesh_processing::does_self_intersect<CGAL::Parallel_if_available_tag>(*(d->poly));
|
||||
if (self_intersect)
|
||||
return QString("Yes");
|
||||
else
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include "triangulate_primitive.h"
|
||||
|
||||
#include <CGAL/exceptions.h>
|
||||
#include <CGAL/IO/File_writer_wavefront.h>
|
||||
#include <CGAL/IO/generic_copy_OFF.h>
|
||||
#include <CGAL/IO/OBJ_reader.h>
|
||||
|
|
@ -1581,7 +1582,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
|
|||
try{
|
||||
CGAL::Polygon_mesh_processing::non_manifold_vertices(*d->smesh_, OutputIterator());
|
||||
}
|
||||
catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& )
|
||||
catch( CGAL::internal::Throw_at_output_exception& )
|
||||
{
|
||||
d->has_nm_vertices = true;
|
||||
}
|
||||
|
|
@ -1659,7 +1660,7 @@ QString Scene_surface_mesh_item::computeStats(int type)
|
|||
{
|
||||
//todo : add a test about cache validity
|
||||
if(is_triangle_mesh(*d->smesh_))
|
||||
d->self_intersect = CGAL::Polygon_mesh_processing::does_self_intersect(*(d->smesh_));
|
||||
d->self_intersect = CGAL::Polygon_mesh_processing::does_self_intersect<CGAL::Parallel_if_available_tag>(*(d->smesh_));
|
||||
if (d->self_intersect)
|
||||
return QString("Yes");
|
||||
else if(is_triangle_mesh(*d->smesh_))
|
||||
|
|
|
|||
|
|
@ -185,7 +185,19 @@ public:
|
|||
"warning condition failed") {}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// The following classes are useful to create output iterators (with the help
|
||||
// of boost::function_output_iterator) that will throw as soon as something is being written.
|
||||
class Throw_at_output_exception : public std::exception { };
|
||||
|
||||
struct Throw_at_output
|
||||
{
|
||||
template<class T>
|
||||
void operator()(const T& /* t */) const { throw Throw_at_output_exception(); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} //namespace CGAL
|
||||
|
||||
#endif // CGAL_EXCEPTIONS_H
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@ class Intersect_facets
|
|||
typename Kernel::Construct_triangle_2 triangle_functor;
|
||||
typename Kernel::Do_intersect_2 do_intersect_2_functor;
|
||||
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor, Box_policy> Box;
|
||||
|
||||
const TriangleMesh& mesh;
|
||||
const VertexUVMap uvmap;
|
||||
|
|
@ -250,7 +251,8 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
|
|||
typedef typename Kernel::FT NT;
|
||||
typedef typename Kernel::Point_2 Point_2;
|
||||
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor> Box;
|
||||
typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy;
|
||||
typedef CGAL::Box_intersection_d::Box_with_info_d<NT, 2, face_descriptor, Box_policy> Box;
|
||||
|
||||
// Create the corresponding vector of bounding boxes
|
||||
std::vector<Box> boxes;
|
||||
|
|
@ -283,8 +285,7 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh,
|
|||
unsigned int counter = 0;
|
||||
Intersect_facets<TriangleMesh, VertexUVMap> intersect_facets(mesh, uvmap, counter);
|
||||
std::ptrdiff_t cutoff = 2000;
|
||||
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
|
||||
intersect_facets, cutoff);
|
||||
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(), intersect_facets, cutoff);
|
||||
return (counter == 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue