diff --git a/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h b/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h index 89b6facc3cc..b8eb1310a32 100644 --- a/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h +++ b/Box_intersection_d/doc/Box_intersection_d/CGAL/box_intersection_d.h @@ -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, diff --git a/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h b/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h index 2a53c9db171..eeccd7f9819 100644 --- a/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h +++ b/Box_intersection_d/include/CGAL/Box_intersection_d/Box_with_info_d.h @@ -16,34 +16,34 @@ #include - #include #include namespace CGAL { - namespace Box_intersection_d { -template -class Box_with_info_d : public Box_d< NT_, N, ID_FROM_BOX_ADDRESS> { +template +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 diff --git a/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h b/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h index 74a113c46b8..d9fccef3776 100644 --- a/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h +++ b/Box_intersection_d/include/CGAL/Box_intersection_d/segment_tree.h @@ -16,7 +16,6 @@ #include - #include #include @@ -24,7 +23,6 @@ #include #include - #include #include #include @@ -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; diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index d7952400617..94752c41462 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -6,7 +6,7 @@ // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// +// // // Author(s) : Lutz Kettner // Andreas Meyer @@ -25,12 +25,191 @@ #include #include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#endif + +#include #include +//////////////////////////////////////////////////////////////////////////////////////////////// +/// 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::inf(); + const NT sup = Box_intersection_d::box_limits::sup(); + +#ifndef CGAL_LINKED_WITH_TBB + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else // CGAL_LINKED_WITH_TBB + if(boost::is_convertible::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::value_type val_t; + typedef typename std::iterator_traits::difference_type diff_size; + + typedef std::vector 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> range_1_iterators; + std::array, n> range_2_iterators; + + for(int i=0; i 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::inf(); - const NT sup = Box_intersection_d::box_limits::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(begin1, end1, begin2, end2, callback, traits, cutoff, true); + if(setting == Box_intersection_d::BIPARTITE) + internal::box_intersection_segment_tree_d(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 Traits; - box_intersection_custom_predicates_d(begin1, end1, begin2, end2, - callback, Traits(), cutoff, setting); - } else { - typedef Box_intersection_d::Predicate_traits_d 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 Traits; + box_intersection_custom_predicates_d(begin1, end1, begin2, end2, + callback, Traits(), cutoff, setting); + } else { + typedef Box_intersection_d::Predicate_traits_d Traits; + box_intersection_custom_predicates_d(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( 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( 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( 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::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::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); } -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::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::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); } -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::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::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); } -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::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::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); } - // 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::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::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); } -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(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(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::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(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::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(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::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(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 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 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 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::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::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::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 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::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) { diff --git a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt index 1beb02ff8d0..6f4ec1704ce 100644 --- a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt +++ b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt @@ -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() diff --git a/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp b/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp index 4d51695b9bd..0b06520214f 100644 --- a/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp +++ b/Box_intersection_d/test/Box_intersection_d/test_box_grid.cpp @@ -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 -#include -#include -#include -#include -typedef CGAL::Box_intersection_d::Box_d Box; +#include +#include + +#include +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#endif + +typedef CGAL::Box_intersection_d::Box_d 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& 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::cout, ",")); - std::cout << "\n expected: "; - std::copy( check, check+size, - std::ostream_iterator( std::cout, ",")); - std::cout << '\n' << std::endl; - assert( result.size() == size - && std::equal( check, check+size, result.begin())); +template +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::cout, ",")); + std::cout << "\n expected: "; + std::copy( check, check+size, + std::ostream_iterator( 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 -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 +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 // helper function to create the function object -Report report( Iter it) { return Report(it); } + +template // helper function to create the function object +Report report(Container& c) { return Report(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 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 result; +#else + std::vector 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(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(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(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 range_1 = {{ boxes, boxes+1, boxes+2, boxes+3, boxes+4, boxes+5, + boxes+6, boxes+7, boxes+8 }}; + std::vector 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 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( 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(range_1.begin(), range_1.begin(), + range_2.begin(), range_2.end(), + report(result)); + assert(result.empty()); + + CGAL::box_intersection_d(range_1.begin(), range_1.end(), + range_2.begin(), range_2.begin(), + report(result)); + assert(result.empty()); + + CGAL::box_intersection_d(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(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(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( 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 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( 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 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 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 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( 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 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( 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; } diff --git a/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h b/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h new file mode 100644 index 00000000000..20fbade4402 --- /dev/null +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h @@ -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 diff --git a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h index 9dbf6c02f5b..55bd1d3778b 100644 --- a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h @@ -41,7 +41,6 @@ #endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011 - #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS # include # include @@ -65,6 +64,7 @@ # include #endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS +#include #include #include #include @@ -121,6 +121,7 @@ public: typedef Static_filters_predicates::Side_of_oriented_circle_2 Side_of_oriented_circle_2; typedef Static_filters_predicates::Side_of_oriented_sphere_3 Side_of_oriented_sphere_3; typedef Static_filters_predicates::Compare_squared_radius_3 Compare_squared_radius_3; + typedef Static_filters_predicates::Coplanar_3 Coplanar_3; typedef Static_filters_predicates::Compare_weighted_squared_radius_3 Compare_weighted_squared_radius_3; typedef Static_filters_predicates::Power_side_of_oriented_power_sphere_3 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 diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index c13c8649420..eab559b68f8 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -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 diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index efe62876159..18d35b53366 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -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) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 95a539040ac..eff0d48d229 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -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." ) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp index 93a2de84858..a44efca2da7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp @@ -2,12 +2,15 @@ #include #include +#include +#include +#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Surface_mesh Mesh; -typedef boost::graph_traits::face_descriptor face_descriptor; +typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::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::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(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 > intersected_tris; - PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); - + PMP::self_intersections(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; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_transformation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_transformation.h index 30377ebaf9c..9e9f488824d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_transformation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_transformation.h @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h index 56ac7610d26..fdf829e5805 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_callbacks.h @@ -15,7 +15,7 @@ #include - +#include #include #include #include @@ -38,7 +38,9 @@ protected: typedef boost::graph_traits 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 Box; + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; public: Collect_face_bbox_per_edge_bbox( @@ -80,9 +82,12 @@ protected: typedef boost::graph_traits 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 Box; + typedef typename boost::property_traits::reference Point; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d 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 Box; + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + typedef typename boost::property_traits::reference Point; bool is_edge_target_incident_to_face(halfedge_descriptor hd, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h index e7778e76441..ab52338fcab 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -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 Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; typedef boost::unordered_set Face_set; typedef boost::unordered_map 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 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h index c1ee33318a1..f18ef7186be 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/repair_extra.h @@ -110,7 +110,8 @@ void collect_close_stitchable_boundary_edges(PM& pm, typedef boost::unordered_map Halfedge_multiplicity; typedef std::vector > Halfedge_pairs; - typedef typename Box_intersection_d::Box_with_info_d Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; typedef Union_find UF_vertices; typedef std::map 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; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h index 0d036f3522f..f46e8ccd821 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -17,20 +17,27 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#include +#include +#include +#include + 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::face_descriptor face_descriptor; - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; - + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d 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 boxes1; std::vector 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::const_type VertexPointMap1; typedef typename GetVertexPointMap::const_type VertexPointMap2; @@ -433,6 +438,7 @@ compute_face_face_intersection(const FaceRange& face_range1, typename boost::property_traits::value_type, typename boost::property_traits::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 box2_ptr(boost::make_counting_iterator(&boxes2[0]), boost::make_counting_iterator(&boxes2[0]+boxes2.size())); - // compute intersections filtered out by boxes typedef typename GetGeomTraits::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::type>::value)); std::vector 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 Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; // make one box per facet std::vector boxes1; std::vector 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 box1_ptr(boost::make_counting_iterator(&boxes1[0]), boost::make_counting_iterator(&boxes1[0]+boxes1.size())); std::vector box2_ptr(boost::make_counting_iterator(&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::value_type Point; typedef typename boost::range_value::type Polyline; - CGAL_static_assertion( - (boost::is_same::type>::value)); + CGAL_static_assertion((boost::is_same::type>::value)); std::vector faces; faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) )); - typedef typename CGAL::Box_intersection_d::Box_with_info_d > Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d, Box_policy> Box; // make one box per facet std::vector boxes1; std::vector 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 Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + typedef typename Kernel::Point_3 Point; // make one box per facet std::vector boxes1; std::vector 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 > Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d, Box_policy> Box; + typedef typename Kernel::Point_3 Point; typedef typename boost::range_value::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 - 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 Mesh_box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Mesh_box; + std::vector 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 boxes_ptr( - boost::make_counting_iterator(&boxes[0]), - boost::make_counting_iterator(&boxes[0]+boxes.size())); + std::vector boxes_ptr(boost::make_counting_iterator(&boxes[0]), + boost::make_counting_iterator(&boxes[0]+boxes.size())); typedef typename boost::range_value::type NP_rng; typedef typename boost::range_value::type TriangleMesh; typedef typename GetGeomTraits::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 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 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 diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h index 409bdc4900d..c3a06220c53 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h @@ -21,215 +21,378 @@ #include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include + #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 -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 - 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 +bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, + typename boost::graph_traits::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::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::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 +struct Strict_intersect_faces // "strict" as in "not sharing a subface" +{ typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::property_map::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 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 - void operator()(const T& /* t */) const { - throw Throw_at_output_exception(); + if(do_faces_intersect(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 +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 -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np); + typedef TriangleMesh TM; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; + + typedef typename GetGeomTraits::type GT; + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); + + typedef typename GetVertexPointMap::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 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::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 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 Throwing_output_iterator; + typedef internal::Strict_intersect_faces 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::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if(std::is_convertible::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 > Face_pairs; + typedef std::back_insert_iterator Face_pairs_back_inserter; + typedef internal::Strict_intersect_faces 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(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff); + else + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), callback, cutoff); + + // Sequentially write into the output iterator + for(std::size_t i=0; i Intersecting_faces_filter; + Intersecting_faces_filter intersect_faces(tmesh, vpmap, gt, out); + + if(throw_on_SI) + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_filter, cutoff); + else + CGAL::box_self_intersection_d(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::%face_descriptor`. + * @tparam TriangleMesh a model of `FaceListGraph` + * @tparam FacePairOutputIterator a model of `OutputIterator` holding objects of type + * `std::pair::%face_descriptor, boost::graph_traits::%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(face_range, tmesh, out, false /*don't throw*/, np); +} + +/// \cond SKIP_IN_MANUAL +template +FacePairOutputIterator +self_intersections(const FaceRange& face_range, + const TriangleMesh& tmesh, + FacePairOutputIterator out) +{ + return self_intersections(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::%face_descriptor, boost::graph_traits::%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 -OutputIterator -self_intersections(const TriangleMesh& tmesh - , OutputIterator out -#ifdef DOXYGEN_RUNNING - , const NamedParameters& np) -#else - , const Named_function_parameters& np) -#endif +template +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(faces(tmesh), tmesh, out, np); } /// \cond SKIP_IN_MANUAL -template -OutputIterator -self_intersections(const TriangleMesh& tmesh, OutputIterator out) +template +FacePairOutputIterator +self_intersections(const TriangleMesh& tmesh, FacePairOutputIterator out) { - return self_intersections(tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return self_intersections(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::%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::%face_descriptor, boost::graph_traits::%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 -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::face_descriptor face_descriptor; - typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; - - // make one box per facet - std::vector boxes; - boxes.reserve( - std::distance( boost::begin(face_range), boost::end(face_range) ) - ); - - typedef typename GetVertexPointMap::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::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 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::type GeomTraits; - CGAL::internal::Intersect_facets - 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 -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 -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 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 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 OutputIterator; - self_intersections(face_range, tmesh, OutputIterator(), np); + CGAL::Emptyset_iterator unused_out; + internal::self_intersections_impl(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 -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 +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(faces(tmesh), tmesh, np); } -template +/// \cond SKIP_IN_MANUAL +template +bool does_self_intersect(const TriangleMesh& tmesh) +{ + return does_self_intersect(faces(tmesh), tmesh, CGAL::parameters::all_default()); +} + +template 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(face_range, tmesh, CGAL::parameters::all_default()); } - /// \endcond -}// end namespace Polygon_mesh_processing - +}// namespace Polygon_mesh_processing }// namespace CGAL #include diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 2bf92f35e85..b708ac434a8 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -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() diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp index 3addd6c9323..11cb16b40a7 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/self_intersection_surface_mesh_test.cpp @@ -1,22 +1,25 @@ -#include -#include -#include -#include - #include #include #include #include - +#include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic; -typedef CGAL::Exact_predicates_exact_constructions_kernel Epec; +#include +#include +#include +#include + +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 -int -test_self_intersections(const char* filename, const bool expected) +int test_self_intersections(const char* filename, + const bool expected) { typedef CGAL::Surface_mesh Mesh; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -35,18 +38,36 @@ test_self_intersections(const char* filename, const bool expected) timer.start(); std::vector > 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::value) // EPECK isn't threadsafe + { + PMP::self_intersections( + m, std::back_inserter(intersected_tris), CP::vertex_index_map(get(CGAL::vertex_point, m))); + } + else + { + PMP::self_intersections( + 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::value) // EPECK isn't threadsafe + { + intersecting_2 = PMP::does_self_intersect( + m, CP::vertex_index_map(get(CGAL::vertex_point, m))); + } + else + { + intersecting_2 = PMP::does_self_intersect( + 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(filename, expected); + std::cout << "First test (EPICK):" << std::endl; + int r = test_self_intersections(filename, expected); - std::cout << "First test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "First test (EPECK):" << std::endl; + r += test_self_intersections(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(filename, expected); + std::cout << "Second test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Second test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Second test (EPECK):" << std::endl; + r += test_self_intersections(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(filename, expected); + std::cout << "Third test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Third test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Third test (EPECK):" << std::endl; + r += test_self_intersections(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(filename, expected); + std::cout << "Fourth test (EPICK):" << std::endl; + r += test_self_intersections(filename, expected); - std::cout << "Fourth test (Epec):" << std::endl; - r += test_self_intersections(filename, expected); + std::cout << "Fourth test (EPECK):" << std::endl; + r += test_self_intersections(filename, expected); return r; } diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 6427dc55d7d..1b1cd817152 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -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) diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp index 580023022f7..e62593c9b89 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/OFF_io_plugin.cpp @@ -9,13 +9,16 @@ #include #include -#include +#include #include #include #include #include +#include +#include + 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(); diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp index 8c8a1dcab5f..342349af861 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.cpp @@ -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(*(d->poly)); if (self_intersect) return QString("Yes"); else diff --git a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 7b6febf0ff9..65ecb788392 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -33,6 +33,7 @@ #include #include "triangulate_primitive.h" +#include #include #include #include @@ -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(*(d->smesh_)); if (d->self_intersect) return QString("Yes"); else if(is_triangle_mesh(*d->smesh_)) diff --git a/STL_Extension/include/CGAL/exceptions.h b/STL_Extension/include/CGAL/exceptions.h index 21305a47851..ddd047d395a 100644 --- a/STL_Extension/include/CGAL/exceptions.h +++ b/STL_Extension/include/CGAL/exceptions.h @@ -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 + void operator()(const T& /* t */) const { throw Throw_at_output_exception(); } +}; + +} // namespace internal } //namespace CGAL #endif // CGAL_EXCEPTIONS_H diff --git a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.h index 49b7895e507..2398eff4a91 100644 --- a/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.h +++ b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.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 Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d 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 Box; + typedef CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; + typedef CGAL::Box_intersection_d::Box_with_info_d Box; // Create the corresponding vector of bounding boxes std::vector boxes; @@ -283,8 +285,7 @@ bool is_one_to_one_mapping(const TriangleMesh& mesh, unsigned int counter = 0; Intersect_facets 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); }