From cc75efdbb5d0fccbb2ca1853f5f4d4d454e4a468 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 7 Nov 2019 15:57:23 +0100 Subject: [PATCH 01/61] Add static filter for Coplanar_3 --- .../CGAL/internal/Static_filters/Coplanar_3.h | 54 +++++++++++++++++++ .../internal/Static_filters/Static_filters.h | 9 ++++ .../include/CGAL/Kernel/interface_macros.h | 2 +- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 Filtered_kernel/include/CGAL/internal/Static_filters/Coplanar_3.h 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..95216db79f9 100644 --- a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h @@ -42,6 +42,8 @@ #endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011 +# include + #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS # include # include @@ -96,6 +98,7 @@ class Static_filters : public K_base { typedef Static_filters Self; + typedef Static_filters_predicates::Coplanar_3 Coplanar_3; public: #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS typedef Static_filters_predicates::Equal_2 Equal_2; @@ -137,6 +140,12 @@ public: collinear_3_object() const { return Collinear_3(); } + Coplanar_3 + coplanar_3_object() const + { + return Coplanar_3(); + } + #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS Equal_2 equal_2_object() const 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) From 21bd1af50526a69371c4cde930de60fa9b9f1cb3 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 7 Nov 2019 17:54:46 +0100 Subject: [PATCH 02/61] Avoid chains of next and target --- .../self_intersections.h | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) 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..7d09bc5ea1d 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 @@ -73,6 +73,7 @@ struct Intersect_facets typedef typename Kernel::Segment_3 Segment; typedef typename Kernel::Triangle_3 Triangle; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::property_map::const_type Ppmap; // members @@ -102,6 +103,17 @@ struct Intersect_facets void operator()(const Box* b, const Box* c) const { halfedge_descriptor h = halfedge(b->info(), m_tmesh); + halfedge_descriptor g = halfedge(c->info(),m_tmesh); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, m_tmesh); + hv[1] = target(next(h, m_tmesh), m_tmesh); + hv[2] = source(h, m_tmesh); + + gv[0] = target(g, m_tmesh); + gv[1] = target(next(g, m_tmesh), m_tmesh); + gv[2] = source(g, m_tmesh); + halfedge_descriptor opp_h; // check for shared egde @@ -110,13 +122,13 @@ struct Intersect_facets 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)), + if(CGAL::coplanar(get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)&3]), + get(m_vpmap, hv[(i+2)&3]), 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)), + CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)&3]), + get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)&3]), get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) == CGAL::POSITIVE){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); @@ -129,50 +141,37 @@ struct Intersect_facets } // 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); + 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(v != halfedge_descriptor()){ + if(shared){ // 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))); + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); - 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))); + Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)&3]), + get(m_vpmap, hv[(i+2)&3]) ); + Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)&3]), + get(m_vpmap, gv[(j+2)&3])); if(do_intersect_3_functor(t1,s2)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); @@ -183,12 +182,12 @@ struct Intersect_facets } // 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))); + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); if(do_intersect_3_functor(t1, t2)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); } From e18413c9b5016f7d29c72b4acf8d4d3ab8d83164 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 7 Nov 2019 21:26:53 +0100 Subject: [PATCH 03/61] fixes --- .../self_intersections.h | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) 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 7d09bc5ea1d..decbb718f93 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 @@ -122,13 +122,18 @@ struct Intersect_facets if(face(opp_h, m_tmesh) == c->info()){ // there is an intersection if the four points are coplanar and // the triangles overlap + get(m_vpmap, hv[i]); + get(m_vpmap, hv[(i + 1) % 3]); + get(m_vpmap, hv[(i + 2) % 3]); + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); + if(CGAL::coplanar(get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)&3]), - get(m_vpmap, hv[(i+2)&3]), + get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]), get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && - CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)&3]), + CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)&3]), + get(m_vpmap, hv[(i+1)%3]), get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) == CGAL::POSITIVE){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); @@ -152,14 +157,14 @@ struct Intersect_facets shared = true; break; } - if(shared){ - break; - } } + if (shared) { + break; + } } if(shared){ // found shared vertex: - CGAL_assertion(target(h,m_tmesh) == target(v,m_tmesh)); + assert(hv[i] == gv[j]); // geometric check if the opposite segments intersect the triangles Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), get(m_vpmap, hv[1]), @@ -168,10 +173,10 @@ struct Intersect_facets get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); - Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)&3]), - get(m_vpmap, hv[(i+2)&3]) ); - Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)&3]), - get(m_vpmap, gv[(j+2)&3])); + Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]) ); + Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), + get(m_vpmap, gv[(j+2)%3])); if(do_intersect_3_functor(t1,s2)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); From b6bc521c22dfd24e6393740eb9d896d2a1d964d1 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 8 Nov 2019 16:21:20 +0100 Subject: [PATCH 04/61] WIP does not even compile --- .../CGAL/Box_intersection_d/segment_tree.h | 65 ++++------------- .../include/CGAL/box_intersection_d.h | 9 ++- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../self_intersections_example.cpp | 12 +++- .../self_intersections.h | 72 +++++++++++++++++-- 5 files changed, 99 insertions(+), 60 deletions(-) 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..d7514750c9b 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 @@ -24,7 +24,8 @@ #include #include - +#include +#include #include #include #include @@ -93,8 +94,8 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, bool in_order = true ) { typedef typename Traits::Compare Compare; - std::sort( p_begin, p_end, Compare( 0 ) ); - std::sort( i_begin, i_end, Compare( 0 ) ); + tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); + tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); // for each box viewed as interval i for( RandomAccessIter2 i = i_begin; i != i_end; ++i ) { @@ -133,8 +134,8 @@ void modified_two_way_scan( { typedef typename Traits::Compare Compare; - std::sort( p_begin, p_end, Compare( 0 ) ); - std::sort( i_begin, i_end, Compare( 0 ) ); + tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); + tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); // for each box viewed as interval while( i_begin != i_end && p_begin != p_end ) { @@ -323,7 +324,8 @@ 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, + tbb::task_group& tg) { typedef typename Predicate_traits::Spanning Spanning; typedef typename Predicate_traits::Lo_less Lo_less; @@ -332,37 +334,10 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, const T inf = box_limits< T >::inf(); const T sup = box_limits< T >::sup(); -#if CGAL_BOX_INTERSECTION_DEBUG - CGAL_STATIC_THREAD_LOCAL_VARIABLE(int, level, -1); - Counter bla( level ); - CGAL_BOX_INTERSECTION_DUMP("range: [" << lo << "," << hi << ") dim " - << dim << std::endl ) - CGAL_BOX_INTERSECTION_DUMP("intervals: " ) - //dump_box_numbers( i_begin, i_end, traits ); - dump_intervals( i_begin, i_end, traits, dim ); - CGAL_BOX_INTERSECTION_DUMP("points: " ) - //dump_box_numbers( p_begin, p_end, traits ); - dump_points( p_begin, p_end, traits, dim ); -#endif - -#if CGAL_SEGMENT_TREE_CHECK_INVARIANTS - { - // first: each point is inside segment [lo,hi) - for( RandomAccessIter1 it = p_begin; it != p_end; ++it ) { - CGAL_assertion( Lo_less( hi, dim )(*it) ); - CGAL_assertion( Lo_less( lo, dim )(*it) == false ); - } - // second: each interval intersects segment [lo,hi) - for( RandomAccessIter2 it = i_begin; it != i_end; ++it ) - CGAL_assertion( Hi_greater(lo,dim)(*it) && Lo_less(hi,dim)(*it)); - } -#endif - if( p_begin == p_end || i_begin == i_end || lo >= hi ) return; if( dim == 0 ) { - CGAL_BOX_INTERSECTION_DUMP( "dim = 0. scanning ... " << std::endl ) one_way_scan( p_begin, p_end, i_begin, i_end, callback, traits, dim, in_order ); return; @@ -371,7 +346,6 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, if( std::distance( p_begin, p_end ) < cutoff || std::distance( i_begin, i_end ) < cutoff ) { - CGAL_BOX_INTERSECTION_DUMP( "scanning ... " << std::endl ) modified_two_way_scan( p_begin, p_end, i_begin, i_end, callback, traits, dim, in_order ); return; @@ -381,23 +355,18 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, std::partition( i_begin, i_end, Spanning( lo, hi, dim ) ); if( i_begin != i_span_end ) { - CGAL_BOX_INTERSECTION_DUMP( "checking spanning intervals ... " - << std::endl ) + // make two calls for roots of segment tree at next level. segment_tree( p_begin, p_end, i_begin, i_span_end, inf, sup, - callback, traits, cutoff, dim - 1, in_order ); + callback, traits, cutoff, dim - 1, in_order, tg ); segment_tree( i_begin, i_span_end, p_begin, p_end, inf, sup, - callback, traits, cutoff, dim - 1, !in_order ); + callback, traits, cutoff, dim - 1, !in_order, tg ); } T mi; RandomAccessIter1 p_mid = split_points( p_begin, p_end, traits, dim, mi ); if( p_mid == p_begin || p_mid == p_end ) { - CGAL_BOX_INTERSECTION_DUMP( "unable to split points! ") - //dump_points( p_begin, p_end, traits, dim ); - CGAL_BOX_INTERSECTION_DUMP( "performing modified two_way_san ... " - << std::endl ) modified_two_way_scan( p_begin, p_end, i_span_end, i_end, callback, traits, dim, in_order ); return; @@ -407,21 +376,17 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, // separate left intervals. // left intervals have a low point strictly less than mi i_mid = std::partition( i_span_end, i_end, Lo_less( mi, dim ) ); - CGAL_BOX_INTERSECTION_DUMP("->left" << std::endl ) + segment_tree( p_begin, p_mid, i_span_end, i_mid, lo, mi, - callback, traits, cutoff, dim, in_order ); + callback, traits, cutoff, dim, in_order, tg ); // separate right intervals. // right intervals have a high point strictly higher than mi i_mid = std::partition( i_span_end, i_end, Hi_greater( mi, dim ) ); - CGAL_BOX_INTERSECTION_DUMP("->right"<< std::endl ) + segment_tree( p_mid, p_end, i_span_end, i_mid, mi, hi, - callback, traits, cutoff, dim, in_order ); + callback, traits, cutoff, dim, in_order, tg ); } -#if CGAL_BOX_INTERSECTION_DEBUG - #undef CGAL_BOX_INTERSECTION_DUMP -#endif -#undef CGAL_BOX_INTERSECTION_DEBUG } // end namespace Box_intersection_d diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index d7952400617..d2e3415ed8e 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -25,6 +25,8 @@ #include #include +#include + #include namespace CGAL { @@ -40,6 +42,7 @@ void box_intersection_custom_predicates_d( std::ptrdiff_t cutoff = 10, Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE) { + tbb::task_group tg; typedef BoxPredicateTraits Traits; typedef typename Traits::NT NT; CGAL_assertion( Traits::dimension() > 0 ); @@ -47,10 +50,12 @@ void box_intersection_custom_predicates_d( 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); + inf, sup, callback, traits, cutoff, dim, true, tg); if(setting == Box_intersection_d::BIPARTITE) Box_intersection_d::segment_tree(begin2, end2, begin1, end1, - inf, sup, callback, traits, cutoff, dim, false); + inf, sup, callback, traits, cutoff, dim, false, tg); + + tg.wait(); } diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 88701b9e196..eeebbd3e6cc 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -108,6 +108,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..403d22786a0 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,6 +2,8 @@ #include #include +#include +#include #include @@ -22,17 +24,23 @@ int main(int argc, char* argv[]) std::cerr << "Not a valid input file." << std::endl; return 1; } - + /* bool intersecting = PMP::does_self_intersect(mesh, PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl; + */ + CGAL::Real_timer rtimer; + CGAL::Timer timer; + rtimer.start(); + timer.start(); + std::vector > intersected_tris; PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); - + std::cout << rtimer.time() << " " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; return 0; 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 decbb718f93..e18be4a35d4 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 @@ -40,12 +40,17 @@ #include #include +#include +#include + #ifdef DOXYGEN_RUNNING #define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters #define CGAL_PMP_NP_CLASS NamedParameters #endif namespace CGAL { + + namespace internal { template &r) const + { + for (std::size_t i = r.begin(); i != r.end(); ++i) { + vertex_descriptor vd(i); + if(degree(vd, m_tmesh)<= 3){ + return; + } + halfedge_descriptor hd = halfedge(vd, m_tmesh), done(hd); + + do { //for each hd with vd as target + // no need to look at the neighbor faces + // later do the shared edge test with them + Triangle th = triangle_functor( get(m_vpmap, vd), + get(m_vpmap, source(hd,m_tmesh)), + get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)) ); + halfedge_descriptor start = prev(opposite(prev(opposite(hd,m_tmesh),m_tmesh),m_tmesh),m_tmesh); + halfedge_descriptor stop = opposite(next(hd,m_tmesh),m_tmesh); + while(start != stop){ + if(start < h){ + Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), + get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); + if(do_intersect_3_functor(th, ss)){ + *m_iterator_wrapper++ = std::make_pair(face(h,m_tmesh), face(start, m_tmesh)); + } + } + start = prev(opposite(hd,m_tmesh),m_tmesh); + } + ++hd; + }while(hd != done); + } + } + void operator()(const Box* b, const Box* c) const { halfedge_descriptor h = halfedge(b->info(), m_tmesh); @@ -163,6 +200,7 @@ struct Intersect_facets } } if(shared){ +#if 0 // found shared vertex: assert(hv[i] == gv[j]); // geometric check if the opposite segments intersect the triangles @@ -183,6 +221,7 @@ struct Intersect_facets } else if(do_intersect_3_functor(t2,s1)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); } +#endif return; } @@ -211,6 +250,8 @@ struct Throw_at_output { }// namespace internal + + namespace Polygon_mesh_processing { #ifndef DOXYGEN_RUNNING @@ -226,6 +267,7 @@ self_intersections( const FaceRange& face_range, const NamedParameters& np); #endif + /** * \ingroup PMP_intersection_grp * detects and records self-intersections of a triangulated surface mesh. @@ -253,22 +295,27 @@ self_intersections( const FaceRange& face_range, * * @return `out` */ + + template #else //avoid ambiguity with self_intersections(faces, tmesh, out) - , class P, class T, class R + , class P, class T, class R> #endif -> + + OutputIterator self_intersections(const TriangleMesh& tmesh , OutputIterator out #ifdef DOXYGEN_RUNNING - , const NamedParameters& np) + , const NamedParameters& np #else - , const Named_function_parameters& np) + , const Named_function_parameters& np #endif + ) + { return self_intersections(faces(tmesh), tmesh, out, np); } @@ -281,6 +328,8 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) return self_intersections(tmesh, out, CGAL::Polygon_mesh_processing::parameters::all_default()); } + + /// \endcond /*! @@ -326,6 +375,7 @@ self_intersections( const FaceRange& face_range, typedef TriangleMesh TM; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; // make one box per facet @@ -357,8 +407,18 @@ self_intersections( const FaceRange& face_range, for(Box& b : boxes) box_ptr.push_back(&b); - // compute self-intersections filtered out by boxes + typedef typename GetGeomTraits::type GeomTraits; + + Emptyset_iterator dev0; + CGAL::internal::Intersect_facets + intersect_facets_parallel(tmesh, dev0, vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + + std::cout << "do it"<< std::endl; + tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_parallel); + + // compute self-intersections filtered out by boxes CGAL::internal::Intersect_facets intersect_facets(tmesh, out, vpmap, parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); From ead0da3c7749c1d3327e713f51ee1d7ba7f274e7 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 11:40:40 +0100 Subject: [PATCH 05/61] WIP: not the same number of intersections for Tuyaeaux.stl --- .../CGAL/Box_intersection_d/segment_tree.h | 12 +- .../include/CGAL/box_intersection_d.h | 7 +- .../self_intersections_example.cpp | 6 +- .../self_intersections.h | 223 +++++++++++++++--- 4 files changed, 197 insertions(+), 51 deletions(-) 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 d7514750c9b..c54cae50f28 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 @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -324,8 +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, - tbb::task_group& tg) + std::ptrdiff_t cutoff, int dim, bool in_order) { typedef typename Predicate_traits::Spanning Spanning; typedef typename Predicate_traits::Lo_less Lo_less; @@ -358,9 +356,9 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, // make two calls for roots of segment tree at next level. segment_tree( p_begin, p_end, i_begin, i_span_end, inf, sup, - callback, traits, cutoff, dim - 1, in_order, tg ); + callback, traits, cutoff, dim - 1, in_order ); segment_tree( i_begin, i_span_end, p_begin, p_end, inf, sup, - callback, traits, cutoff, dim - 1, !in_order, tg ); + callback, traits, cutoff, dim - 1, !in_order ); } T mi; @@ -378,13 +376,13 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, i_mid = std::partition( i_span_end, i_end, Lo_less( mi, dim ) ); segment_tree( p_begin, p_mid, i_span_end, i_mid, lo, mi, - callback, traits, cutoff, dim, in_order, tg ); + callback, traits, cutoff, dim, in_order ); // separate right intervals. // right intervals have a high point strictly higher than mi i_mid = std::partition( i_span_end, i_end, Hi_greater( mi, dim ) ); segment_tree( p_mid, p_end, i_span_end, i_mid, mi, hi, - callback, traits, cutoff, dim, in_order, tg ); + callback, traits, cutoff, dim, in_order ); } diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index d2e3415ed8e..bf5a8f3d62a 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -25,7 +25,6 @@ #include #include -#include #include @@ -42,7 +41,6 @@ void box_intersection_custom_predicates_d( std::ptrdiff_t cutoff = 10, Box_intersection_d::Setting setting = Box_intersection_d::BIPARTITE) { - tbb::task_group tg; typedef BoxPredicateTraits Traits; typedef typename Traits::NT NT; CGAL_assertion( Traits::dimension() > 0 ); @@ -50,12 +48,11 @@ void box_intersection_custom_predicates_d( 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, tg); + 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, tg); + inf, sup, callback, traits, cutoff, dim, false); - tg.wait(); } 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 403d22786a0..0db9f8b95ab 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 @@ -1,3 +1,4 @@ +int I,J,KK; #include #include @@ -15,6 +16,7 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char* argv[]) { + I = J = KK = 0; const char* filename = (argc > 1) ? argv[1] : "data/pig.off"; std::ifstream input(filename); @@ -42,6 +44,8 @@ int main(int argc, char* argv[]) PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); std::cout << rtimer.time() << " " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; - + std::cout << "I = " << I << std::endl; + std::cout << "J = " << J << std::endl; + std::cout << "KK = " << KK << std::endl; return 0; } 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 e18be4a35d4..eda406ef940 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 @@ -27,6 +27,7 @@ #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include +#include #ifdef DOXYGEN_RUNNING #define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters @@ -50,8 +52,69 @@ namespace CGAL { - namespace internal { + +template +struct TriangleTriangle { + const TM& m_tmesh; + const VertexPointMap m_vpmap; + typename Kernel::Construct_triangle_3 triangle_functor; + typename Kernel::Do_intersect_3 do_intersect_3_functor; + typedef typename Kernel::Triangle_3 Triangle; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + const std::vector >& seq_v_faces; + std::vector& dointersect; + mutable bool result; + + + TriangleTriangle(const std::vector >& seq_v_faces, + std::vector& dointersect, + const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) + : seq_v_faces(seq_v_faces), + m_tmesh(tmesh), + m_vpmap(vpmap), + triangle_functor(kernel.construct_triangle_3_object()), + do_intersect_3_functor(kernel.do_intersect_3_object()), + dointersect(dointersect), + result(false) + {} + + void operator()(const tbb::blocked_range &r) const + { + for (std::size_t i = r.begin(); i != r.end(); ++i) { + const std::pair& tt = seq_v_faces[i]; + + halfedge_descriptor h = halfedge(tt.first, m_tmesh); + halfedge_descriptor g = halfedge(tt.second ,m_tmesh); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, m_tmesh); + hv[1] = target(next(h, m_tmesh), m_tmesh); + hv[2] = source(h, m_tmesh); + + gv[0] = target(g, m_tmesh); + gv[1] = target(next(g, m_tmesh), m_tmesh); + gv[2] = source(g, m_tmesh); + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); + if(do_intersect_3_functor(t1, t2)){ + dointersect[i] = true; + result = true; + } + } + } +}; + + template ::halfedge_descriptor halfedge_descriptor; @@ -109,30 +173,66 @@ struct Intersect_facets { for (std::size_t i = r.begin(); i != r.end(); ++i) { vertex_descriptor vd(i); - if(degree(vd, m_tmesh)<= 3){ - return; - } + halfedge_descriptor hd = halfedge(vd, m_tmesh), done(hd); - - do { //for each hd with vd as target - // no need to look at the neighbor faces - // later do the shared edge test with them - Triangle th = triangle_functor( get(m_vpmap, vd), - get(m_vpmap, source(hd,m_tmesh)), - get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)) ); - halfedge_descriptor start = prev(opposite(prev(opposite(hd,m_tmesh),m_tmesh),m_tmesh),m_tmesh); - halfedge_descriptor stop = opposite(next(hd,m_tmesh),m_tmesh); - while(start != stop){ - if(start < h){ - Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), - get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); - if(do_intersect_3_functor(th, ss)){ - *m_iterator_wrapper++ = std::make_pair(face(h,m_tmesh), face(start, m_tmesh)); - } - } - start = prev(opposite(hd,m_tmesh),m_tmesh); + if(is_border(hd, m_tmesh)){ + hd = prev(opposite(hd,m_tmesh),m_tmesh); } - ++hd; + + do { //for each hd with vd as target look at all other faces + Point p = get(m_vpmap, vd); + Point q = get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)); + Point r = get(m_vpmap, source(hd,m_tmesh)); + + //std::ostringstream out; + //out << std::endl << "p = " << p << std::endl; + //out << "q = " << q << std::endl; + //out << "r = " << r << std::endl; + + + Triangle th = triangle_functor(p, q, r); + + // first look at the directly shared edges + halfedge_descriptor ohd = opposite(hd, m_tmesh); + if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ + vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); + Point s = get(m_vpmap, ov); + //out << "s 1 = " << s << std::endl; + J++; + if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(r,p,q,s) == POSITIVE){ + //out << "coplanar 1" << std::endl; + *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); + } + } + ohd = opposite(next(hd,m_tmesh), m_tmesh); + if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ + vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); + Point s = get(m_vpmap, ov); + //out << "s 2 = " << s << std::endl; + J++; + if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(p,q,r,s) == POSITIVE){ + //out << "coplanar 2" << std::endl; + *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); + } + } + //std::cout << out.str() << std::flush; + // no need to look at the oppposite segement for the direct neighbor faces + + halfedge_descriptor po = prev(opposite(hd,m_tmesh),m_tmesh); + halfedge_descriptor op = opposite(next(hd,m_tmesh),m_tmesh); + + for(halfedge_descriptor start : halfedges_around_target(hd,m_tmesh)){ + if((start == hd) || (start == op) || (start == po) || is_border(start, m_tmesh)){ + continue; + } + Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), + get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); + if(do_intersect_3_functor(th, ss)){ + I++; + *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(start, m_tmesh)); + } + } + hd = prev(opposite(hd,m_tmesh),m_tmesh); }while(hd != done); } } @@ -153,6 +253,7 @@ struct Intersect_facets halfedge_descriptor opp_h; +#if 0 // check for shared egde for(unsigned int i=0; i<3; ++i){ opp_h = opposite(h, m_tmesh); @@ -181,7 +282,7 @@ struct Intersect_facets } h = next(h, m_tmesh); } - +#endif // check for shared vertex --> maybe intersection, maybe not halfedge_descriptor v; @@ -195,9 +296,9 @@ struct Intersect_facets break; } } - if (shared) { - break; - } + if (shared) { + break; + } } if(shared){ #if 0 @@ -224,7 +325,8 @@ struct Intersect_facets #endif return; } - +#if 0 + KK++; // check for geometric intersection Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), get(m_vpmap, hv[1]), @@ -233,8 +335,11 @@ struct Intersect_facets get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); if(do_intersect_3_functor(t1, t2)){ +#endif *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); +#if 0 } +#endif } // end operator () }; // end struct Intersect_facets @@ -408,24 +513,66 @@ self_intersections( const FaceRange& face_range, box_ptr.push_back(&b); + // (A) Parallel: look at each vertex and its incident faces + // Intersections are written into a concurrent vector typedef typename GetGeomTraits::type GeomTraits; - Emptyset_iterator dev0; - CGAL::internal::Intersect_facets - intersect_facets_parallel(tmesh, dev0, vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + typedef tbb::concurrent_vector > CV; + CV cv_faces; + typedef std::back_insert_iterator CVI; - std::cout << "do it"<< std::endl; + CGAL::internal::Intersect_facets + intersect_facets_parallel(tmesh, + std::back_inserter(cv_faces), // result + vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + + Real_timer rt; + rt.start(); tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_parallel); - + + // Copy from the concurent container to the output iterator + for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ + *out ++= *it; + } + std::cout << "parallel_for " << rt.time() << "sec."<< std::endl; + + // (B) Sequential: Look at pairs of triangles with intersecting bbox + // Copy the pairs which do not share an edge or a vertex into a std::vector + rt.reset(); // compute self-intersections filtered out by boxes - CGAL::internal::Intersect_facets - intersect_facets(tmesh, out, vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + typedef std::vector >SeqV; + SeqV seq_v_faces; + typedef std::back_insert_iterator SeqVI; + + CGAL::internal::Intersect_facets + intersect_facets(tmesh, + std::back_inserter(seq_v_faces), // result + 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; + + // (C) Parallel: + std::vector dointersect(seq_v_faces.size()); + CGAL::internal::TriangleTriangle tt(seq_v_faces, + dointersect, + tmesh, + vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + tbb::parallel_for(tbb::blocked_range(0, seq_v_faces.size()), tt); + if(tt.result){ + std::cout << "there was at least one proper intersection" << std::endl; + } + for(int i = 0; i < seq_v_faces.size(); ++i){ + if(dointersect[i]){ + *out ++= seq_v_faces[i]; + } + } + + std::cout << "box_self_intersection_d " << rt.time() << "sec."<< std::endl; + return out; } /// \cond SKIP_IN_MANUAL From 899d8f7b59437a180e66b2f32b46779c2d046cc1 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 13:01:26 +0100 Subject: [PATCH 06/61] cleanup --- .../self_intersections_example.cpp | 8 +- .../self_intersections.h | 135 ++++-------------- 2 files changed, 28 insertions(+), 115 deletions(-) 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 0db9f8b95ab..2ac214c7993 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 @@ -1,4 +1,3 @@ -int I,J,KK; #include #include @@ -16,7 +15,6 @@ namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char* argv[]) { - I = J = KK = 0; const char* filename = (argc > 1) ? argv[1] : "data/pig.off"; std::ifstream input(filename); @@ -42,10 +40,8 @@ int main(int argc, char* argv[]) std::vector > intersected_tris; PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); - std::cout << rtimer.time() << " " << timer.time() << " sec." << std::endl; + std::cout << std::endl << "Total: " << rtimer.time() << " " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; - std::cout << "I = " << I << std::endl; - std::cout << "J = " << J << std::endl; - std::cout << "KK = " << KK << std::endl; + return 0; } 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 eda406ef940..7a67358dbcb 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 @@ -69,11 +69,12 @@ struct TriangleTriangle { typedef typename boost::graph_traits::face_descriptor face_descriptor; const std::vector >& seq_v_faces; std::vector& dointersect; - mutable bool result; + bool& result; TriangleTriangle(const std::vector >& seq_v_faces, std::vector& dointersect, + bool& result, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) : seq_v_faces(seq_v_faces), m_tmesh(tmesh), @@ -81,7 +82,7 @@ struct TriangleTriangle { triangle_functor(kernel.construct_triangle_3_object()), do_intersect_3_functor(kernel.do_intersect_3_object()), dointersect(dointersect), - result(false) + result(result) {} void operator()(const tbb::blocked_range &r) const @@ -184,11 +185,6 @@ struct Intersect_facets Point q = get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)); Point r = get(m_vpmap, source(hd,m_tmesh)); - //std::ostringstream out; - //out << std::endl << "p = " << p << std::endl; - //out << "q = " << q << std::endl; - //out << "r = " << r << std::endl; - Triangle th = triangle_functor(p, q, r); @@ -197,10 +193,7 @@ struct Intersect_facets if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); Point s = get(m_vpmap, ov); - //out << "s 1 = " << s << std::endl; - J++; if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(r,p,q,s) == POSITIVE){ - //out << "coplanar 1" << std::endl; *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); } } @@ -208,27 +201,20 @@ struct Intersect_facets if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); Point s = get(m_vpmap, ov); - //out << "s 2 = " << s << std::endl; - J++; if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(p,q,r,s) == POSITIVE){ - //out << "coplanar 2" << std::endl; *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); } } - //std::cout << out.str() << std::flush; - // no need to look at the oppposite segement for the direct neighbor faces - halfedge_descriptor po = prev(opposite(hd,m_tmesh),m_tmesh); halfedge_descriptor op = opposite(next(hd,m_tmesh),m_tmesh); for(halfedge_descriptor start : halfedges_around_target(hd,m_tmesh)){ - if((start == hd) || (start == op) || (start == po) || is_border(start, m_tmesh)){ + if((start == hd) || (start == op) || (start == po) || is_border(start, m_tmesh) || (face(hd, m_tmesh) < face(start, m_tmesh))){ continue; } Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); if(do_intersect_3_functor(th, ss)){ - I++; *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(start, m_tmesh)); } } @@ -253,93 +239,21 @@ struct Intersect_facets halfedge_descriptor opp_h; -#if 0 - // 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 - get(m_vpmap, hv[i]); - get(m_vpmap, hv[(i + 1) % 3]); - get(m_vpmap, hv[(i + 2) % 3]); - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); - if(CGAL::coplanar(get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && - CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - 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); - } -#endif - // check for shared vertex --> maybe intersection, maybe not + // ignore shared vertex as already dealt with halfedge_descriptor v; int i(0),j(0); - bool shared = false; - for(; i < 3 && (! shared); ++i){ - for(j = 0; j < 3 && (! shared); ++j){ + for(; i < 3; ++i){ + for(j = 0; j < 3; ++j){ if(hv[i]==gv[j]){ - shared = true; - break; + return; } } - if (shared) { - break; - } } - if(shared){ -#if 0 - // found shared vertex: - assert(hv[i] == gv[j]); - // geometric check if the opposite segments intersect the triangles - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - - Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]) ); - Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), - get(m_vpmap, gv[(j+2)%3])); - - 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()); - } -#endif - return; - } -#if 0 - KK++; - // check for geometric intersection - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - if(do_intersect_3_functor(t1, t2)){ -#endif - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); -#if 0 - } -#endif + *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + } // end operator () }; // end struct Intersect_facets @@ -529,18 +443,18 @@ self_intersections( const FaceRange& face_range, Real_timer rt; rt.start(); + tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_parallel); // Copy from the concurent container to the output iterator for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ *out ++= *it; } - std::cout << "parallel_for " << rt.time() << "sec."<< std::endl; - + std::cout << "(A) Parallel: faces incident to each vertex " << rt.time() << "sec."<< std::endl; + rt.reset(); + // (B) Sequential: Look at pairs of triangles with intersecting bbox // Copy the pairs which do not share an edge or a vertex into a std::vector - rt.reset(); - // compute self-intersections filtered out by boxes typedef std::vector >SeqV; SeqV seq_v_faces; typedef std::back_insert_iterator SeqVI; @@ -553,25 +467,28 @@ self_intersections( const FaceRange& face_range, std::ptrdiff_t cutoff = 2000; CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff); - - // (C) Parallel: + std::cout << "(B) Sequential: boxes that intersect " << rt.time() << "sec."<< std::endl; + rt.reset(); + + // (C) Parallel: Perform geometric test on pairs not sharing an edge or a vertex std::vector dointersect(seq_v_faces.size()); + bool result(false); CGAL::internal::TriangleTriangle tt(seq_v_faces, dointersect, + result, tmesh, vpmap, parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); tbb::parallel_for(tbb::blocked_range(0, seq_v_faces.size()), tt); - if(tt.result){ - std::cout << "there was at least one proper intersection" << std::endl; - } - for(int i = 0; i < seq_v_faces.size(); ++i){ - if(dointersect[i]){ - *out ++= seq_v_faces[i]; + if(result){ + for(int i = 0; i < seq_v_faces.size(); ++i){ + if(dointersect[i]){ + *out ++= seq_v_faces[i]; + } } } - std::cout << "box_self_intersection_d " << rt.time() << "sec."<< std::endl; + std::cout << "(C) Parallel: Filter triangles that intersect " << rt.time() << "sec."<< std::endl; return out; } From fc72b37db46032794d3708f311d74b7ec51a46f4 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 15:31:26 +0100 Subject: [PATCH 07/61] Functor cleanup --- .../self_intersections.h | 281 +++++++++++++++--- 1 file changed, 235 insertions(+), 46 deletions(-) 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 7a67358dbcb..53508614a01 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 @@ -53,6 +53,159 @@ namespace CGAL { 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; + } + + OutputIterator* m_iterator; + bool* m_intersected; + }; +// typedefs + typedef typename Kernel::Segment_3 Segment; + typedef typename Kernel::Triangle_3 Triangle; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::property_map::const_type Ppmap; + +// members + const TM& m_tmesh; + const VertexPointMap m_vpmap; + mutable OutputIterator m_iterator; + mutable bool m_intersected; + mutable boost::function_output_iterator m_iterator_wrapper; + + 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) + : + 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()) + { } + + void operator()(const Box* b, const Box* c) const + { + halfedge_descriptor h = halfedge(b->info(), m_tmesh); + halfedge_descriptor g = halfedge(c->info(),m_tmesh); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, m_tmesh); + hv[1] = target(next(h, m_tmesh), m_tmesh); + hv[2] = source(h, m_tmesh); + + gv[0] = target(g, m_tmesh); + gv[1] = target(next(g, m_tmesh), m_tmesh); + gv[2] = source(g, m_tmesh); + + halfedge_descriptor opp_h; + + // 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 + get(m_vpmap, hv[i]); + get(m_vpmap, hv[(i + 1) % 3]); + get(m_vpmap, hv[(i + 2) % 3]); + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); + + if(CGAL::coplanar(get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]), + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && + CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), + get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)%3]), + 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 v; + + 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: + assert(hv[i] == gv[j]); + // geometric check if the opposite segments intersect the triangles + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); + + Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]) ); + Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), + get(m_vpmap, gv[(j+2)%3])); + + 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, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); + if(do_intersect_3_functor(t1, t2)){ + *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + } + } // end operator () +}; // end struct Intersect_facets + template +struct Incident_faces_filter +{ + // 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; + } + + OutputIterator* m_iterator; + bool* m_intersected; + }; +// typedefs + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + +// members + const TM& m_tmesh; + mutable OutputIterator m_iterator; + mutable bool m_intersected; + mutable boost::function_output_iterator m_iterator_wrapper; + + + Incident_faces_filter(const TM& tmesh, OutputIterator it) + : m_tmesh(tmesh), + m_iterator(it), + m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)) + {} + + void operator()(const Box* b, const Box* c) const + { + halfedge_descriptor h = halfedge(b->info(), m_tmesh); + halfedge_descriptor g = halfedge(c->info(),m_tmesh); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, m_tmesh); + hv[1] = target(next(h, m_tmesh), m_tmesh); + hv[2] = source(h, m_tmesh); + + gv[0] = target(g, m_tmesh); + gv[1] = target(next(g, m_tmesh), m_tmesh); + gv[2] = source(g, m_tmesh); + + halfedge_descriptor opp_h; + + // ignore shared vertex as already dealt with + + halfedge_descriptor v; + + int i(0),j(0); + for(; i < 3; ++i){ + for(j = 0; j < 3; ++j){ + if(hv[i]==gv[j]){ + return; + } + } + } + *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + + } // end operator () +}; + template -struct Intersect_facets +struct Intersect_facets_incident_to_vertex { // wrapper to check whether anything is inserted to output iterator struct Output_iterator_with_bool @@ -158,7 +381,7 @@ struct Intersect_facets typename Kernel::Do_intersect_3 do_intersect_3_functor; - Intersect_facets(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel) + Intersect_facets_incident_to_vertex(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel) : m_tmesh(tmesh), m_vpmap(vpmap), @@ -223,38 +446,6 @@ struct Intersect_facets } } - void operator()(const Box* b, const Box* c) const - { - halfedge_descriptor h = halfedge(b->info(), m_tmesh); - halfedge_descriptor g = halfedge(c->info(),m_tmesh); - - vertex_descriptor hv[3], gv[3]; - hv[0] = target(h, m_tmesh); - hv[1] = target(next(h, m_tmesh), m_tmesh); - hv[2] = source(h, m_tmesh); - - gv[0] = target(g, m_tmesh); - gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - - halfedge_descriptor opp_h; - - - // ignore shared vertex as already dealt with - - halfedge_descriptor v; - - int i(0),j(0); - for(; i < 3; ++i){ - for(j = 0; j < 3; ++j){ - if(hv[i]==gv[j]){ - return; - } - } - } - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); - - } // end operator () }; // end struct Intersect_facets struct Throw_at_output { @@ -435,16 +626,16 @@ self_intersections( const FaceRange& face_range, CV cv_faces; typedef std::back_insert_iterator CVI; - CGAL::internal::Intersect_facets - intersect_facets_parallel(tmesh, - std::back_inserter(cv_faces), // result - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + CGAL::internal::Intersect_facets_incident_to_vertex + intersect_facets_incident_to_vertex(tmesh, + std::back_inserter(cv_faces), // result + vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); Real_timer rt; rt.start(); - tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_parallel); + tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_incident_to_vertex); // Copy from the concurent container to the output iterator for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ @@ -459,14 +650,12 @@ self_intersections( const FaceRange& face_range, SeqV seq_v_faces; typedef std::back_insert_iterator SeqVI; - CGAL::internal::Intersect_facets - intersect_facets(tmesh, - std::back_inserter(seq_v_faces), // result - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + CGAL::internal::Incident_faces_filter + incident_faces_filter(tmesh, + std::back_inserter(seq_v_faces)); std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),incident_faces_filter,cutoff); std::cout << "(B) Sequential: boxes that intersect " << rt.time() << "sec."<< std::endl; rt.reset(); From 732d1d8f8aa26d0ec335222e41b556ee3c07ef25 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 16:32:08 +0100 Subject: [PATCH 08/61] Add overloads with ConcurencyTag --- .../self_intersections_example.cpp | 2 +- .../self_intersections.h | 86 ++++++++++++++++--- 2 files changed, 76 insertions(+), 12 deletions(-) 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 2ac214c7993..440d7738bd5 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 @@ -39,7 +39,7 @@ int main(int argc, char* argv[]) std::vector > intersected_tris; - PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); + PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); std::cout << std::endl << "Total: " << rtimer.time() << " " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; 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 53508614a01..909a00381f3 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 @@ -204,7 +204,7 @@ struct Intersect_facets *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); } } // end operator () -}; // end struct Intersect_facets + }; // end struct Intersect_facets template OutputIterator self_intersections( const FaceRange& face_range, const TriangleMesh& tmesh, OutputIterator out, - const NamedParameters& np); + const NamedParameters& np, + ConcurrencyTag); #endif @@ -506,8 +508,8 @@ self_intersections( const FaceRange& face_range, * @return `out` */ - -template @@ -527,16 +529,16 @@ self_intersections(const TriangleMesh& tmesh ) { - return self_intersections(faces(tmesh), tmesh, out, np); + return self_intersections(faces(tmesh), tmesh, out, np, ConcurrencyTag()); } /// \cond SKIP_IN_MANUAL -template +template OutputIterator self_intersections(const TriangleMesh& tmesh, OutputIterator out) { - return self_intersections(tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return self_intersections(faces(tmesh), tmesh, out, + CGAL::Polygon_mesh_processing::parameters::all_default(), ConcurrencyTag()); } @@ -579,7 +581,67 @@ OutputIterator self_intersections( const FaceRange& face_range, const TriangleMesh& tmesh, OutputIterator out, - const NamedParameters& np) + const NamedParameters& np, + Sequential_tag) +{ + 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; +} + + +template +OutputIterator +self_intersections( const FaceRange& face_range, + const TriangleMesh& tmesh, + OutputIterator out, + const NamedParameters& np, + Parallel_tag) { CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); @@ -682,7 +744,8 @@ self_intersections( const FaceRange& face_range, } /// \cond SKIP_IN_MANUAL -template @@ -691,7 +754,8 @@ OutputIterator self_intersections(const FaceRange& face_range, OutputIterator out) { return self_intersections(face_range, tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::parameters::all_default(), + ConcurrencyTag()); } /// \endcond From 343ca0b4a7639ff0ee64e6bcb256e39639cc258a Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 18:27:32 +0100 Subject: [PATCH 09/61] Add the version that reports all pairs of faces and performs the intersection tests in parallel --- .../self_intersections_example.cpp | 2 + .../self_intersections.h | 270 +++++++++++++++++- 2 files changed, 265 insertions(+), 7 deletions(-) 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 440d7738bd5..179eeec96ca 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 @@ -1,3 +1,5 @@ +struct Parallel_tag_bis {}; + #include #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 909a00381f3..c40df55bae6 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 @@ -41,9 +41,11 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB #include #include #include +#endif #ifdef DOXYGEN_RUNNING #define CGAL_PMP_NP_TEMPLATE_PARAMETERS NamedParameters @@ -81,6 +83,7 @@ struct Intersect_facets typedef typename Kernel::Triangle_3 Triangle; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::property_map::const_type Ppmap; // members @@ -108,7 +111,7 @@ struct Intersect_facets { } void operator()(const Box* b, const Box* c) const - { + { halfedge_descriptor h = halfedge(b->info(), m_tmesh); halfedge_descriptor g = halfedge(c->info(),m_tmesh); @@ -206,7 +209,10 @@ struct Intersect_facets } // end operator () }; // end struct Intersect_facets + +#ifdef CGAL_LINKED_WITH_TBB +// The functor for testing only triangles that do not share an edge or vertex in parallel template @@ -269,6 +275,146 @@ struct TriangleTriangle { }; +// The functor for doing all geometric tests in parallel +template +struct AllPairs { + const TM& m_tmesh; + const VertexPointMap m_vpmap; + mutable OutputIterator m_iterator; + typename Kernel::Construct_segment_3 segment_functor; + typename Kernel::Construct_triangle_3 triangle_functor; + typename Kernel::Do_intersect_3 do_intersect_3_functor; + typedef typename Kernel::Segment_3 Segment; + typedef typename Kernel::Triangle_3 Triangle; + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + const std::vector >& seq_faces; + + + AllPairs(const std::vector >& seq_faces, + OutputIterator it, + const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) + : seq_faces(seq_faces), + m_tmesh(tmesh), + m_vpmap(vpmap), + m_iterator(it), + triangle_functor(kernel.construct_triangle_3_object()), + do_intersect_3_functor(kernel.do_intersect_3_object()) + {} + + void operator()(const tbb::blocked_range &r) const + { + for (std::size_t ri = r.begin(); ri != r.end(); ++ri) { + const std::pair& ff = seq_faces[ri]; + this->operator()(ff); + } + } + + void operator()(const std::pair& ff) const + { + halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); + + vertex_descriptor hv[3], gv[3]; + hv[0] = target(h, m_tmesh); + hv[1] = target(next(h, m_tmesh), m_tmesh); + hv[2] = source(h, m_tmesh); + + gv[0] = target(g, m_tmesh); + gv[1] = target(next(g, m_tmesh), m_tmesh); + gv[2] = source(g, m_tmesh); + + halfedge_descriptor opp_h; + + // check for shared egde + for(unsigned int i=0; i<3; ++i){ + opp_h = opposite(h, m_tmesh); + if(face(opp_h, m_tmesh) == ff.second){ + // there is an intersection if the four points are coplanar and + // the triangles overlap + get(m_vpmap, hv[i]); + get(m_vpmap, hv[(i + 1) % 3]); + get(m_vpmap, hv[(i + 2) % 3]); + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); + + if(CGAL::coplanar(get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]), + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && + CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), + get(m_vpmap, hv[i]), + get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) + == CGAL::POSITIVE){ + *m_iterator++ = ff; + 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 v; + + 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: + assert(hv[i] == gv[j]); + // geometric check if the opposite segments intersect the triangles + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); + + Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), + get(m_vpmap, hv[(i+2)%3]) ); + Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), + get(m_vpmap, gv[(j+2)%3])); + + if(do_intersect_3_functor(t1,s2)){ + *m_iterator ++ = ff; + } else if(do_intersect_3_functor(t2,s1)){ + *m_iterator ++ = ff; + } + return; + } + + // check for geometric intersection + Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), + get(m_vpmap, hv[1]), + get(m_vpmap, hv[2])); + Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), + get(m_vpmap, gv[1]), + get(m_vpmap, gv[2])); + if(do_intersect_3_functor(t1, t2)){ + *m_iterator ++ = ff; + } + } +}; + + +// The functor for filtering pairs of faces that share an edge or vertex template @@ -339,6 +485,27 @@ struct Incident_faces_filter } // end operator () }; +// The functor that filters nothing +template +struct All_faces_filter +{ + mutable OutputIterator m_iterator; + + + All_faces_filter(OutputIterator it) + : m_iterator(it) + {} + + template + void operator()(const Box* b, const Box* c) const + { + *m_iterator ++ = std::make_pair(b->info(), c->info()); + + } // end operator () +}; + + +// The functor that computes intersections for faces incident to a vertex template box_ptr; - box_ptr.reserve(num_faces(tmesh)); + box_ptr.reserve(boxes.size()); for(Box& b : boxes) box_ptr.push_back(&b); @@ -630,6 +798,7 @@ self_intersections( const FaceRange& face_range, return intersect_facets.m_iterator; } +#ifdef CGAL_LINKED_WITH_TBB template +OutputIterator +self_intersections( const FaceRange& face_range, + const TriangleMesh& tmesh, + OutputIterator out, + const NamedParameters& np, + Parallel_tag) +{ + CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); + + typedef TriangleMesh TM; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_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(boxes.size()); + + for(Box& b : boxes) + box_ptr.push_back(&b); + + // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector + std::ptrdiff_t cutoff = 2000; + typedef std::vector >SeqV; + typedef std::back_insert_iterator SeqVI; + SeqV face_pairs; + internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); + + + // (B) Parallel: perform the geometric tests + typedef typename GetGeomTraits::type GeomTraits; + + typedef tbb::concurrent_vector > CV; + CV cv_faces; + typedef std::back_insert_iterator CVI; + + + CGAL::internal::AllPairs + all_pairs(face_pairs, + std::back_inserter(cv_faces), // result + tmesh, + vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + + Real_timer rt; + rt.start(); + + tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); + + // (C) Sequentially: Copy from the concurent container to the output iterator + for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ + *out ++= *it; + } + return out; +} +#endif // CGAL_LINKED_WITH_TBB + + /// \cond SKIP_IN_MANUAL template Date: Tue, 12 Nov 2019 18:35:46 +0100 Subject: [PATCH 10/61] Add CGAL_LINKED_WITH_TBB in the Box_intersection_d without ConcurrencyTag --- .../include/CGAL/Box_intersection_d/segment_tree.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 c54cae50f28..e6a9ca0e05e 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 @@ -24,7 +24,9 @@ #include #include +#ifdef CGAL_LINKED_WITH_TBB #include +#endif #include #include #include @@ -93,8 +95,14 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, bool in_order = true ) { typedef typename Traits::Compare Compare; + +#ifdef CGAL_LINKED_WITH_TBB tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); +#else + std::sort( p_begin, p_end, Compare( 0 ) ); + std::sort( i_begin, i_end, Compare( 0 ) ); +#endif // for each box viewed as interval i for( RandomAccessIter2 i = i_begin; i != i_end; ++i ) { @@ -133,8 +141,13 @@ void modified_two_way_scan( { typedef typename Traits::Compare Compare; +#ifdef CGAL_LINKED_WITH_TBB tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); +#else + std::sort( p_begin, p_end, Compare( 0 ) ); + std::sort( i_begin, i_end, Compare( 0 ) ); +#endif // for each box viewed as interval while( i_begin != i_end && p_begin != p_end ) { From a35a7ebf9b18795c45f931ff0a195941c29064d8 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 12 Nov 2019 18:40:17 +0100 Subject: [PATCH 11/61] fix a reserve() --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c40df55bae6..d923c0cbbe0 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 @@ -843,7 +843,7 @@ self_intersections( const FaceRange& face_range, } // generate box pointers std::vector box_ptr; - box_ptr.reserve(num_faces(tmesh)); + box_ptr.reserve(boxes.size()); for(Box& b : boxes) box_ptr.push_back(&b); From 2d14c67304e0d9b0ebdf4b52de1a71b1e27b59ed Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 13 Nov 2019 09:07:10 +0100 Subject: [PATCH 12/61] Remove unused class Output_iterator_with_bool --- .../self_intersections.h | 75 +++---------------- 1 file changed, 9 insertions(+), 66 deletions(-) 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 d923c0cbbe0..2bbaa472e22 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 @@ -62,22 +62,7 @@ namespace internal { class OutputIterator, class VertexPointMap> struct Intersect_facets -{ - // wrapper to check whether anything is inserted to output iterator - struct Output_iterator_with_bool { - Output_iterator_with_bool(OutputIterator* out, bool* intersected) - : m_iterator(out), m_intersected(intersected) { } - - template - void operator()(const T& t) { - *m_intersected = true; - *(*m_iterator)++ = t; - } - - OutputIterator* m_iterator; - bool* m_intersected; - }; // typedefs typedef typename Kernel::Segment_3 Segment; typedef typename Kernel::Triangle_3 Triangle; @@ -90,8 +75,6 @@ struct Intersect_facets const TM& m_tmesh; const VertexPointMap m_vpmap; mutable OutputIterator m_iterator; - mutable bool m_intersected; - mutable boost::function_output_iterator m_iterator_wrapper; typename Kernel::Construct_segment_3 segment_functor; typename Kernel::Construct_triangle_3 triangle_functor; @@ -103,8 +86,6 @@ struct Intersect_facets 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()) @@ -146,7 +127,7 @@ struct Intersect_facets get(m_vpmap, hv[(i+1)%3]), get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) == CGAL::POSITIVE){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + *m_iterator++ = std::make_pair(b->info(), c->info()); return; } else { // there is a shared edge but no intersection return; @@ -189,9 +170,9 @@ struct Intersect_facets get(m_vpmap, gv[(j+2)%3])); if(do_intersect_3_functor(t1,s2)){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + *m_iterator++ = 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()); + *m_iterator++ = std::make_pair(b->info(), c->info()); } return; } @@ -204,7 +185,7 @@ struct Intersect_facets get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); if(do_intersect_3_functor(t1, t2)){ - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + *m_iterator++ = std::make_pair(b->info(), c->info()); } } // end operator () }; // end struct Intersect_facets @@ -420,21 +401,6 @@ template struct Incident_faces_filter { - // 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; - } - - OutputIterator* m_iterator; - bool* m_intersected; - }; // typedefs typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; @@ -442,14 +408,10 @@ struct Incident_faces_filter // members const TM& m_tmesh; mutable OutputIterator m_iterator; - mutable bool m_intersected; - mutable boost::function_output_iterator m_iterator_wrapper; - Incident_faces_filter(const TM& tmesh, OutputIterator it) : m_tmesh(tmesh), - m_iterator(it), - m_iterator_wrapper(Output_iterator_with_bool(&m_iterator, &m_intersected)) + m_iterator(it) {} void operator()(const Box* b, const Box* c) const @@ -480,7 +442,7 @@ struct Incident_faces_filter } } } - *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); + *m_iterator++ = std::make_pair(b->info(), c->info()); } // end operator () }; @@ -513,21 +475,6 @@ template struct Intersect_facets_incident_to_vertex { - // 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; - } - - OutputIterator* m_iterator; - bool* m_intersected; - }; // typedefs typedef typename Kernel::Point_3 Point; typedef typename Kernel::Segment_3 Segment; @@ -540,8 +487,6 @@ struct Intersect_facets_incident_to_vertex const TM& m_tmesh; const VertexPointMap m_vpmap; mutable OutputIterator m_iterator; - mutable bool m_intersected; - mutable boost::function_output_iterator m_iterator_wrapper; typename Kernel::Construct_segment_3 segment_functor; typename Kernel::Construct_triangle_3 triangle_functor; @@ -553,8 +498,6 @@ struct Intersect_facets_incident_to_vertex 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()) @@ -584,7 +527,7 @@ struct Intersect_facets_incident_to_vertex vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); Point s = get(m_vpmap, ov); if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(r,p,q,s) == POSITIVE){ - *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); + *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); } } ohd = opposite(next(hd,m_tmesh), m_tmesh); @@ -592,7 +535,7 @@ struct Intersect_facets_incident_to_vertex vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); Point s = get(m_vpmap, ov); if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(p,q,r,s) == POSITIVE){ - *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); + *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); } } halfedge_descriptor po = prev(opposite(hd,m_tmesh),m_tmesh); @@ -605,7 +548,7 @@ struct Intersect_facets_incident_to_vertex Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); if(do_intersect_3_functor(th, ss)){ - *m_iterator_wrapper++ = std::make_pair(face(hd,m_tmesh), face(start, m_tmesh)); + *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(start, m_tmesh)); } } hd = prev(opposite(hd,m_tmesh),m_tmesh); From 5ea8d361296966a2d79a23467b571812a16b23c9 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 13 Nov 2019 09:35:48 +0100 Subject: [PATCH 13/61] Do not use a concurrent_vector --- .../self_intersections_example.cpp | 2 +- .../self_intersections.h | 37 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) 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 179eeec96ca..25c75967ee3 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 @@ -41,7 +41,7 @@ int main(int argc, char* argv[]) std::vector > intersected_tris; - PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); + PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); std::cout << std::endl << "Total: " << rtimer.time() << " " << timer.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; 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 2bbaa472e22..fc2d33d1738 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 @@ -259,12 +259,10 @@ struct TriangleTriangle { // The functor for doing all geometric tests in parallel template struct AllPairs { const TM& m_tmesh; const VertexPointMap m_vpmap; - mutable OutputIterator m_iterator; typename Kernel::Construct_segment_3 segment_functor; typename Kernel::Construct_triangle_3 triangle_functor; typename Kernel::Do_intersect_3 do_intersect_3_functor; @@ -275,15 +273,15 @@ struct AllPairs { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; const std::vector >& seq_faces; - + std::vector& dointersect; AllPairs(const std::vector >& seq_faces, - OutputIterator it, + std::vector& dointersect, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) : seq_faces(seq_faces), + dointersect(dointersect), m_tmesh(tmesh), m_vpmap(vpmap), - m_iterator(it), triangle_functor(kernel.construct_triangle_3_object()), do_intersect_3_functor(kernel.do_intersect_3_object()) {} @@ -291,13 +289,14 @@ struct AllPairs { void operator()(const tbb::blocked_range &r) const { for (std::size_t ri = r.begin(); ri != r.end(); ++ri) { - const std::pair& ff = seq_faces[ri]; - this->operator()(ff); + + this->operator()(ri); } } - void operator()(const std::pair& ff) const + void operator()(std::size_t ri) const { + const std::pair& ff = seq_faces[ri]; halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); vertex_descriptor hv[3], gv[3]; @@ -331,7 +330,7 @@ struct AllPairs { get(m_vpmap, hv[(i+1)%3]), get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) == CGAL::POSITIVE){ - *m_iterator++ = ff; + dointersect[ri]=true; return; } else { // there is a shared edge but no intersection return; @@ -374,9 +373,9 @@ struct AllPairs { get(m_vpmap, gv[(j+2)%3])); if(do_intersect_3_functor(t1,s2)){ - *m_iterator ++ = ff; + dointersect[ri] = true; } else if(do_intersect_3_functor(t2,s1)){ - *m_iterator ++ = ff; + dointersect[ri] = true; } return; } @@ -389,7 +388,7 @@ struct AllPairs { get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); if(do_intersect_3_functor(t1, t2)){ - *m_iterator ++ = ff; + dointersect[ri] = true; } } }; @@ -916,14 +915,11 @@ self_intersections( const FaceRange& face_range, // (B) Parallel: perform the geometric tests typedef typename GetGeomTraits::type GeomTraits; - typedef tbb::concurrent_vector > CV; - CV cv_faces; - typedef std::back_insert_iterator CVI; - + std::vector dointersect(face_pairs.size(),0); - CGAL::internal::AllPairs + CGAL::internal::AllPairs all_pairs(face_pairs, - std::back_inserter(cv_faces), // result + dointersect, tmesh, vpmap, parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); @@ -934,8 +930,9 @@ self_intersections( const FaceRange& face_range, tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); // (C) Sequentially: Copy from the concurent container to the output iterator - for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ - *out ++= *it; + for(int i=0; i < dointersect.size(); ++i){ + if(dointersect[i]) + *out ++= face_pairs[i]; } return out; } From 884b2cf2abe1206c57ec09d5e72084f2ac3febbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Nov 2019 15:41:11 +0100 Subject: [PATCH 14/61] restore removed code --- .../CGAL/Box_intersection_d/segment_tree.h | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) 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 e6a9ca0e05e..5c31223d85a 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 @@ -345,10 +345,37 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, const T inf = box_limits< T >::inf(); const T sup = box_limits< T >::sup(); +#if CGAL_BOX_INTERSECTION_DEBUG + CGAL_STATIC_THREAD_LOCAL_VARIABLE(int, level, -1); + Counter bla( level ); + CGAL_BOX_INTERSECTION_DUMP("range: [" << lo << "," << hi << ") dim " + << dim << std::endl ) + CGAL_BOX_INTERSECTION_DUMP("intervals: " ) + //dump_box_numbers( i_begin, i_end, traits ); + dump_intervals( i_begin, i_end, traits, dim ); + CGAL_BOX_INTERSECTION_DUMP("points: " ) + //dump_box_numbers( p_begin, p_end, traits ); + dump_points( p_begin, p_end, traits, dim ); +#endif + +#if CGAL_SEGMENT_TREE_CHECK_INVARIANTS + { + // first: each point is inside segment [lo,hi) + for( RandomAccessIter1 it = p_begin; it != p_end; ++it ) { + CGAL_assertion( Lo_less( hi, dim )(*it) ); + CGAL_assertion( Lo_less( lo, dim )(*it) == false ); + } + // second: each interval intersects segment [lo,hi) + for( RandomAccessIter2 it = i_begin; it != i_end; ++it ) + CGAL_assertion( Hi_greater(lo,dim)(*it) && Lo_less(hi,dim)(*it)); + } +#endif + if( p_begin == p_end || i_begin == i_end || lo >= hi ) return; if( dim == 0 ) { + CGAL_BOX_INTERSECTION_DUMP( "dim = 0. scanning ... " << std::endl ) one_way_scan( p_begin, p_end, i_begin, i_end, callback, traits, dim, in_order ); return; @@ -357,6 +384,7 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, if( std::distance( p_begin, p_end ) < cutoff || std::distance( i_begin, i_end ) < cutoff ) { + CGAL_BOX_INTERSECTION_DUMP( "scanning ... " << std::endl ) modified_two_way_scan( p_begin, p_end, i_begin, i_end, callback, traits, dim, in_order ); return; @@ -366,7 +394,8 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, std::partition( i_begin, i_end, Spanning( lo, hi, dim ) ); if( i_begin != i_span_end ) { - + CGAL_BOX_INTERSECTION_DUMP( "checking spanning intervals ... " + << std::endl ) // make two calls for roots of segment tree at next level. segment_tree( p_begin, p_end, i_begin, i_span_end, inf, sup, callback, traits, cutoff, dim - 1, in_order ); @@ -378,6 +407,10 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, RandomAccessIter1 p_mid = split_points( p_begin, p_end, traits, dim, mi ); if( p_mid == p_begin || p_mid == p_end ) { + CGAL_BOX_INTERSECTION_DUMP( "unable to split points! ") + //dump_points( p_begin, p_end, traits, dim ); + CGAL_BOX_INTERSECTION_DUMP( "performing modified two_way_san ... " + << std::endl ) modified_two_way_scan( p_begin, p_end, i_span_end, i_end, callback, traits, dim, in_order ); return; @@ -387,17 +420,21 @@ void segment_tree( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, // separate left intervals. // left intervals have a low point strictly less than mi i_mid = std::partition( i_span_end, i_end, Lo_less( mi, dim ) ); - + CGAL_BOX_INTERSECTION_DUMP("->left" << std::endl ) segment_tree( p_begin, p_mid, i_span_end, i_mid, lo, mi, callback, traits, cutoff, dim, in_order ); // separate right intervals. // right intervals have a high point strictly higher than mi i_mid = std::partition( i_span_end, i_end, Hi_greater( mi, dim ) ); - + CGAL_BOX_INTERSECTION_DUMP("->right"<< std::endl ) segment_tree( p_mid, p_end, i_span_end, i_mid, mi, hi, callback, traits, cutoff, dim, in_order ); } +#if CGAL_BOX_INTERSECTION_DEBUG + #undef CGAL_BOX_INTERSECTION_DUMP +#endif +#undef CGAL_BOX_INTERSECTION_DEBUG } // end namespace Box_intersection_d From ceddeb9756be02b3f197ee58b11b6d143bad75b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 13 Nov 2019 15:55:08 +0100 Subject: [PATCH 15/61] hide debug code --- .../self_intersections.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) 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 fc2d33d1738..1a888d59fdd 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 @@ -25,6 +25,10 @@ #include #include +#ifdef CGAL_PMP_SI_DEBUG +#include +#endif + #include #include @@ -804,18 +808,21 @@ self_intersections( const FaceRange& face_range, std::back_inserter(cv_faces), // result vpmap, parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); - +#ifdef CGAL_PMP_SI_DEBUG Real_timer rt; rt.start(); +#endif tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_incident_to_vertex); // Copy from the concurent container to the output iterator - for(CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ + for(typename CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ *out ++= *it; } +#ifdef CGAL_PMP_SI_DEBUG std::cout << "(A) Parallel: faces incident to each vertex " << rt.time() << "sec."<< std::endl; rt.reset(); +#endif // (B) Sequential: Look at pairs of triangles with intersecting bbox // Copy the pairs which do not share an edge or a vertex into a std::vector @@ -829,8 +836,10 @@ self_intersections( const FaceRange& face_range, std::ptrdiff_t cutoff = 2000; CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),incident_faces_filter,cutoff); +#ifdef CGAL_PMP_SI_DEBUG std::cout << "(B) Sequential: boxes that intersect " << rt.time() << "sec."<< std::endl; rt.reset(); +#endif // (C) Parallel: Perform geometric test on pairs not sharing an edge or a vertex std::vector dointersect(seq_v_faces.size()); @@ -849,8 +858,9 @@ self_intersections( const FaceRange& face_range, } } } - +#ifdef CGAL_PMP_SI_DEBUG std::cout << "(C) Parallel: Filter triangles that intersect " << rt.time() << "sec."<< std::endl; +#endif return out; } @@ -924,9 +934,6 @@ self_intersections( const FaceRange& face_range, vpmap, parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); - Real_timer rt; - rt.start(); - tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); // (C) Sequentially: Copy from the concurent container to the output iterator From e4b205bca664e9757fa65014d58890aba887c084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 14 Nov 2019 06:31:43 +0100 Subject: [PATCH 16/61] update doc + reorder/factorize code --- .../self_intersections.h | 425 ++++++++---------- 1 file changed, 178 insertions(+), 247 deletions(-) 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 1a888d59fdd..098c17ebfa1 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 @@ -66,7 +66,7 @@ namespace internal { class OutputIterator, class VertexPointMap> struct Intersect_facets - { +{ // typedefs typedef typename Kernel::Segment_3 Segment; typedef typename Kernel::Triangle_3 Triangle; @@ -84,7 +84,6 @@ struct Intersect_facets typename Kernel::Construct_triangle_3 triangle_functor; typename Kernel::Do_intersect_3 do_intersect_3_functor; - Intersect_facets(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel) : m_tmesh(tmesh), @@ -93,10 +92,10 @@ struct Intersect_facets segment_functor(kernel.construct_segment_3_object()), triangle_functor(kernel.construct_triangle_3_object()), do_intersect_3_functor(kernel.do_intersect_3_object()) - { } + {} void operator()(const Box* b, const Box* c) const - { + { halfedge_descriptor h = halfedge(b->info(), m_tmesh); halfedge_descriptor g = halfedge(c->info(),m_tmesh); @@ -107,8 +106,8 @@ struct Intersect_facets gv[0] = target(g, m_tmesh); gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - + gv[2] = source(g, m_tmesh); + halfedge_descriptor opp_h; // check for shared egde @@ -153,9 +152,9 @@ struct Intersect_facets break; } } - if (shared) { - break; - } + if (shared) { + break; + } } if(shared){ // found shared vertex: @@ -192,12 +191,11 @@ struct Intersect_facets *m_iterator++ = std::make_pair(b->info(), c->info()); } } // end operator () - }; // end struct Intersect_facets - +}; // end struct Intersect_facets #ifdef CGAL_LINKED_WITH_TBB - // The functor for testing only triangles that do not share an edge or vertex in parallel +// TO BE REMOVED? template @@ -215,7 +213,6 @@ struct TriangleTriangle { std::vector& dointersect; bool& result; - TriangleTriangle(const std::vector >& seq_v_faces, std::vector& dointersect, bool& result, @@ -228,7 +225,7 @@ struct TriangleTriangle { dointersect(dointersect), result(result) {} - + void operator()(const tbb::blocked_range &r) const { for (std::size_t i = r.begin(); i != r.end(); ++i) { @@ -236,15 +233,15 @@ struct TriangleTriangle { halfedge_descriptor h = halfedge(tt.first, m_tmesh); halfedge_descriptor g = halfedge(tt.second ,m_tmesh); - + vertex_descriptor hv[3], gv[3]; hv[0] = target(h, m_tmesh); hv[1] = target(next(h, m_tmesh), m_tmesh); hv[2] = source(h, m_tmesh); - + gv[0] = target(g, m_tmesh); gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); + gv[2] = source(g, m_tmesh); Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), get(m_vpmap, hv[1]), get(m_vpmap, hv[2])); @@ -259,37 +256,41 @@ struct TriangleTriangle { } }; - +//TODO: use the same code for the linear pass? // The functor for doing all geometric tests in parallel template -struct AllPairs { - const TM& m_tmesh; - const VertexPointMap m_vpmap; - typename Kernel::Construct_segment_3 segment_functor; - typename Kernel::Construct_triangle_3 triangle_functor; - typename Kernel::Do_intersect_3 do_intersect_3_functor; +struct AllPairs +{ +// types typedef typename Kernel::Segment_3 Segment; typedef typename Kernel::Triangle_3 Triangle; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + +// data members + const TM& m_tmesh; + const VertexPointMap m_vpmap; const std::vector >& seq_faces; std::vector& dointersect; - + typename Kernel::Construct_segment_3 segment_functor; + typename Kernel::Construct_triangle_3 triangle_functor; + typename Kernel::Do_intersect_3 do_intersect_3_functor; + + AllPairs(const std::vector >& seq_faces, std::vector& dointersect, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) - : seq_faces(seq_faces), - dointersect(dointersect), - m_tmesh(tmesh), - m_vpmap(vpmap), - triangle_functor(kernel.construct_triangle_3_object()), - do_intersect_3_functor(kernel.do_intersect_3_object()) + : m_tmesh(tmesh) + , m_vpmap(vpmap) + , seq_faces(seq_faces) + , dointersect(dointersect) + , triangle_functor(kernel.construct_triangle_3_object()) + , do_intersect_3_functor(kernel.do_intersect_3_object()) {} - + void operator()(const tbb::blocked_range &r) const { for (std::size_t ri = r.begin(); ri != r.end(); ++ri) { @@ -302,7 +303,7 @@ struct AllPairs { { const std::pair& ff = seq_faces[ri]; halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); - + vertex_descriptor hv[3], gv[3]; hv[0] = target(h, m_tmesh); hv[1] = target(next(h, m_tmesh), m_tmesh); @@ -310,8 +311,8 @@ struct AllPairs { gv[0] = target(g, m_tmesh); gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - + gv[2] = source(g, m_tmesh); + halfedge_descriptor opp_h; // check for shared egde @@ -397,7 +398,6 @@ struct AllPairs { } }; - // The functor for filtering pairs of faces that share an edge or vertex template info(), c->info()); - + } // end operator () }; -// The functor that filters nothing +// The functor that filters nothing template struct All_faces_filter { @@ -465,7 +465,7 @@ struct All_faces_filter void operator()(const Box* b, const Box* c) const { *m_iterator ++ = std::make_pair(b->info(), c->info()); - + } // end operator () }; @@ -510,7 +510,7 @@ struct Intersect_facets_incident_to_vertex { for (std::size_t i = r.begin(); i != r.end(); ++i) { vertex_descriptor vd(i); - + halfedge_descriptor hd = halfedge(vd, m_tmesh), done(hd); if(is_border(hd, m_tmesh)){ hd = prev(opposite(hd,m_tmesh),m_tmesh); @@ -521,9 +521,8 @@ struct Intersect_facets_incident_to_vertex Point q = get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)); Point r = get(m_vpmap, source(hd,m_tmesh)); - - Triangle th = triangle_functor(p, q, r); - + Triangle th = triangle_functor(p, q, r); + // first look at the directly shared edges halfedge_descriptor ohd = opposite(hd, m_tmesh); if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ @@ -558,10 +557,9 @@ struct Intersect_facets_incident_to_vertex }while(hd != done); } } - }; // end struct Intersect_facets_incident_to_vertex #endif - + struct Throw_at_output { class Throw_at_output_exception: public std::exception { }; @@ -574,97 +572,20 @@ struct Throw_at_output { }// namespace internal - - namespace Polygon_mesh_processing { -#ifndef DOXYGEN_RUNNING -template -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np, - ConcurrencyTag); -#endif - - -/** - * \ingroup PMP_intersection_grp - * detects and records self-intersections of a triangulated surface mesh. - * This function depends on the package \ref PkgBoxIntersectionD - * @pre `CGAL::is_triangle_mesh(tmesh)` - * - * @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 tmesh the triangulated surface mesh to be checked - * @param out output iterator to be filled with all pairs of non-adjacent faces that intersect. - In case `tmesh` contains some degenerate faces, for each degenerate face `f` a pair `(f,f)` - will be put in `out` before any other self intersection between non-degenerate faces. - These are the only pairs where degenerate faces will be reported. - * @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 - * - * @return `out` - */ - -template < class ConcurrencyTag = Sequential_tag - , class TriangleMesh - , class OutputIterator -#ifdef DOXYGEN_RUNNING - , class NamedParameters> -#else //avoid ambiguity with self_intersections(faces, tmesh, out) - , class P, class T, class R> -#endif - - -OutputIterator -self_intersections(const TriangleMesh& tmesh - , OutputIterator out -#ifdef DOXYGEN_RUNNING - , const NamedParameters& np -#else - , const Named_function_parameters& np -#endif - ) - -{ - return self_intersections(faces(tmesh), tmesh, out, np, ConcurrencyTag()); -} - -/// \cond SKIP_IN_MANUAL -template -OutputIterator -self_intersections(const TriangleMesh& tmesh, OutputIterator out) -{ - return self_intersections(faces(tmesh), tmesh, out, - CGAL::Polygon_mesh_processing::parameters::all_default(), ConcurrencyTag()); -} - - -/// \endcond - /*! * \ingroup PMP_intersection_grp - * Same as above but the self-intersections reported - * are only limited to the faces in `face_range`. + * 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` and `Parallel_tag`. * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, * model of `Range`. * Its iterator type is `RandomAccessIterator`. @@ -684,19 +605,17 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) * `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 +template < class ConcurrencyTag = Sequential_tag, + class TriangleMesh, + class FaceRange, + class OutputIterator, + class NamedParameters> OutputIterator self_intersections( const FaceRange& face_range, const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np, - Sequential_tag) + OutputIterator out, + const NamedParameters& np) { CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); @@ -704,7 +623,7 @@ self_intersections( const FaceRange& face_range, 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 + // make one box per face std::vector boxes; boxes.reserve( std::distance( boost::begin(face_range), boost::end(face_range) ) @@ -733,7 +652,45 @@ self_intersections( const FaceRange& face_range, for(Box& b : boxes) box_ptr.push_back(&b); - // compute self-intersections filtered out by boxes +#if !defined(CGAL_LINKED_WITH_TBB) + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); +#else + if (boost::is_convertible::value) + { + // (Parallel version of the code) + // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector + std::ptrdiff_t cutoff = 2000; + typedef std::vector >SeqV; + typedef std::back_insert_iterator SeqVI; + SeqV face_pairs; + internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); + + // (B) Parallel: perform the geometric tests + typedef typename GetGeomTraits::type GeomTraits; + + std::vector dointersect(face_pairs.size(),0); + + CGAL::internal::AllPairs + all_pairs(face_pairs, + dointersect, + tmesh, + vpmap, + parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + + tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); + + // (C) Sequentially: Copy from the concurent container to the output iterator + for(int i=0; i < dointersect.size(); ++i){ + if(dointersect[i]) + *out ++= face_pairs[i]; + } + return out; + } +#endif + + // (Sequential version of the code) compute self-intersections filtered out by boxes typedef typename GetGeomTraits::type GeomTraits; CGAL::internal::Intersect_facets intersect_facets(tmesh, out, vpmap, @@ -744,8 +701,80 @@ self_intersections( const FaceRange& face_range, return intersect_facets.m_iterator; } -#ifdef CGAL_LINKED_WITH_TBB - +/// \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(), + ConcurrencyTag()); +} +/// \endcond + + +/** + * \ingroup PMP_intersection_grp + * 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` and `Parallel_tag`. + * @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 tmesh the triangulated surface mesh to be checked + * @param out output iterator to be filled with all pairs of non-adjacent faces that intersect. + In case `tmesh` contains some degenerate faces, for each degenerate face `f` a pair `(f,f)` + will be put in `out` before any other self intersection between non-degenerate faces. + These are the only pairs where degenerate faces will be reported. + * @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 + * + * @return `out` + */ +template < class ConcurrencyTag = Sequential_tag + , class TriangleMesh + , class OutputIterator + , class CGAL_PMP_NP_TEMPLATE_PARAMETERS> +OutputIterator +self_intersections(const TriangleMesh& tmesh, + OutputIterator out, + const CGAL_PMP_NP_CLASS& np) +{ + return self_intersections(faces(tmesh), tmesh, out, np, ConcurrencyTag()); +} + +/// \cond SKIP_IN_MANUAL +template +OutputIterator +self_intersections(const TriangleMesh& tmesh, OutputIterator out) +{ + return self_intersections(faces(tmesh), tmesh, out, parameters::all_default()); +} +/// \endcond + +// experimental code for parallel processing on vertices +// (slower than general parallel on boxes). To be removed. +#if 0 template ::face_descriptor face_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::Box_intersection_d::Box_with_info_d Box; // make one box per facet @@ -812,7 +840,7 @@ self_intersections( const FaceRange& face_range, Real_timer rt; rt.start(); #endif - + tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_incident_to_vertex); // Copy from the concurent container to the output iterator @@ -823,13 +851,13 @@ self_intersections( const FaceRange& face_range, std::cout << "(A) Parallel: faces incident to each vertex " << rt.time() << "sec."<< std::endl; rt.reset(); #endif - + // (B) Sequential: Look at pairs of triangles with intersecting bbox // Copy the pairs which do not share an edge or a vertex into a std::vector typedef std::vector >SeqV; SeqV seq_v_faces; typedef std::back_insert_iterator SeqVI; - + CGAL::internal::Incident_faces_filter incident_faces_filter(tmesh, std::back_inserter(seq_v_faces)); @@ -840,7 +868,7 @@ self_intersections( const FaceRange& face_range, std::cout << "(B) Sequential: boxes that intersect " << rt.time() << "sec."<< std::endl; rt.reset(); #endif - + // (C) Parallel: Perform geometric test on pairs not sharing an edge or a vertex std::vector dointersect(seq_v_faces.size()); bool result(false); @@ -863,104 +891,7 @@ self_intersections( const FaceRange& face_range, #endif return out; } - - -template -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np, - Parallel_tag) -{ - CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); - - typedef TriangleMesh TM; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_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(boxes.size()); - - for(Box& b : boxes) - box_ptr.push_back(&b); - - // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector - std::ptrdiff_t cutoff = 2000; - typedef std::vector >SeqV; - typedef std::back_insert_iterator SeqVI; - SeqV face_pairs; - internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); - - - // (B) Parallel: perform the geometric tests - typedef typename GetGeomTraits::type GeomTraits; - - std::vector dointersect(face_pairs.size(),0); - - CGAL::internal::AllPairs - all_pairs(face_pairs, - dointersect, - tmesh, - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); - - tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); - - // (C) Sequentially: Copy from the concurent container to the output iterator - for(int i=0; i < dointersect.size(); ++i){ - if(dointersect[i]) - *out ++= face_pairs[i]; - } - return out; -} #endif // CGAL_LINKED_WITH_TBB - - -/// \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(), - ConcurrencyTag()); -} -/// \endcond /** * \ingroup PMP_intersection_grp From 45cd4dc8bff29aa50fd4b0ae87175357d5ae741f Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 14 Nov 2019 11:21:40 +0100 Subject: [PATCH 17/61] remove parameter; Add ConcurrencyTag to does_self_intersect --- .../self_intersections.h | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) 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 098c17ebfa1..c036990cc08 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 @@ -751,7 +751,7 @@ self_intersections(const FaceRange& face_range, * * @return `out` */ -template < class ConcurrencyTag = Sequential_tag +template @@ -760,7 +760,7 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out, const CGAL_PMP_NP_CLASS& np) { - return self_intersections(faces(tmesh), tmesh, out, np, ConcurrencyTag()); + return self_intersections(faces(tmesh), tmesh, out, np); } /// \cond SKIP_IN_MANUAL @@ -899,6 +899,8 @@ self_intersections( const FaceRange& face_range, * 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` and `Parallel_tag`. * @tparam TriangleMesh a model of `FaceListGraph` * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -914,7 +916,8 @@ self_intersections( const FaceRange& face_range, * * @return `true` if `tmesh` self-intersects */ -template bool does_self_intersect(const TriangleMesh& tmesh @@ -925,7 +928,7 @@ bool does_self_intersect(const TriangleMesh& tmesh try { typedef boost::function_output_iterator OutputIterator; - self_intersections(tmesh, OutputIterator(), np); + self_intersections(tmesh, OutputIterator(), np); } catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) { return true; } @@ -956,7 +959,8 @@ bool does_self_intersect(const TriangleMesh& tmesh * * @return `true` if the faces in `face_range` self-intersect */ -template @@ -969,7 +973,7 @@ bool does_self_intersect(const FaceRange& face_range, try { typedef boost::function_output_iterator OutputIterator; - self_intersections(face_range, tmesh, OutputIterator(), np); + self_intersections(face_range, tmesh, OutputIterator(), np); } catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) { return true; } @@ -978,18 +982,18 @@ bool does_self_intersect(const FaceRange& face_range, } /// \cond SKIP_IN_MANUAL -template +template bool does_self_intersect(const TriangleMesh& tmesh) { - return does_self_intersect(tmesh, + return does_self_intersect(tmesh, CGAL::Polygon_mesh_processing::parameters::all_default()); } -template +template bool does_self_intersect(const FaceRange& face_range, const TriangleMesh& tmesh) { - return does_self_intersect(face_range, tmesh, + return does_self_intersect(face_range, tmesh, CGAL::Polygon_mesh_processing::parameters::all_default()); } From 899b9ec3843df08c40b4f160c1676fe252a40074 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 14 Nov 2019 11:31:50 +0100 Subject: [PATCH 18/61] Remove experimental code --- .../self_intersections.h | 321 +----------------- 1 file changed, 1 insertion(+), 320 deletions(-) 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 c036990cc08..12fb916727e 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 @@ -193,69 +193,8 @@ struct Intersect_facets } // end operator () }; // end struct Intersect_facets + #ifdef CGAL_LINKED_WITH_TBB -// The functor for testing only triangles that do not share an edge or vertex in parallel -// TO BE REMOVED? -template -struct TriangleTriangle { - const TM& m_tmesh; - const VertexPointMap m_vpmap; - typename Kernel::Construct_triangle_3 triangle_functor; - typename Kernel::Do_intersect_3 do_intersect_3_functor; - typedef typename Kernel::Triangle_3 Triangle; - - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - const std::vector >& seq_v_faces; - std::vector& dointersect; - bool& result; - - TriangleTriangle(const std::vector >& seq_v_faces, - std::vector& dointersect, - bool& result, - const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) - : seq_v_faces(seq_v_faces), - m_tmesh(tmesh), - m_vpmap(vpmap), - triangle_functor(kernel.construct_triangle_3_object()), - do_intersect_3_functor(kernel.do_intersect_3_object()), - dointersect(dointersect), - result(result) - {} - - void operator()(const tbb::blocked_range &r) const - { - for (std::size_t i = r.begin(); i != r.end(); ++i) { - const std::pair& tt = seq_v_faces[i]; - - halfedge_descriptor h = halfedge(tt.first, m_tmesh); - halfedge_descriptor g = halfedge(tt.second ,m_tmesh); - - vertex_descriptor hv[3], gv[3]; - hv[0] = target(h, m_tmesh); - hv[1] = target(next(h, m_tmesh), m_tmesh); - hv[2] = source(h, m_tmesh); - - gv[0] = target(g, m_tmesh); - gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - if(do_intersect_3_functor(t1, t2)){ - dointersect[i] = true; - result = true; - } - } - } -}; - //TODO: use the same code for the linear pass? // The functor for doing all geometric tests in parallel template -struct Incident_faces_filter -{ -// typedefs - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - -// members - const TM& m_tmesh; - mutable OutputIterator m_iterator; - - Incident_faces_filter(const TM& tmesh, OutputIterator it) - : m_tmesh(tmesh), - m_iterator(it) - {} - - void operator()(const Box* b, const Box* c) const - { - halfedge_descriptor h = halfedge(b->info(), m_tmesh); - halfedge_descriptor g = halfedge(c->info(),m_tmesh); - - vertex_descriptor hv[3], gv[3]; - hv[0] = target(h, m_tmesh); - hv[1] = target(next(h, m_tmesh), m_tmesh); - hv[2] = source(h, m_tmesh); - - gv[0] = target(g, m_tmesh); - gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - - halfedge_descriptor opp_h; - - // ignore shared vertex as already dealt with - - halfedge_descriptor v; - - int i(0),j(0); - for(; i < 3; ++i){ - for(j = 0; j < 3; ++j){ - if(hv[i]==gv[j]){ - return; - } - } - } - *m_iterator++ = std::make_pair(b->info(), c->info()); - - } // end operator () -}; // The functor that filters nothing template @@ -470,94 +358,6 @@ struct All_faces_filter }; -// The functor that computes intersections for faces incident to a vertex -template -struct Intersect_facets_incident_to_vertex -{ -// typedefs - typedef typename Kernel::Point_3 Point; - typedef typename Kernel::Segment_3 Segment; - typedef typename Kernel::Triangle_3 Triangle; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::property_map::const_type Ppmap; - -// members - const TM& m_tmesh; - const VertexPointMap m_vpmap; - mutable OutputIterator m_iterator; - - 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_incident_to_vertex(const TM& tmesh, OutputIterator it, VertexPointMap vpmap, const Kernel& kernel) - : - m_tmesh(tmesh), - m_vpmap(vpmap), - m_iterator(it), - segment_functor(kernel.construct_segment_3_object()), - triangle_functor(kernel.construct_triangle_3_object()), - do_intersect_3_functor(kernel.do_intersect_3_object()) - { } - - void operator()(const tbb::blocked_range &r) const - { - for (std::size_t i = r.begin(); i != r.end(); ++i) { - vertex_descriptor vd(i); - - halfedge_descriptor hd = halfedge(vd, m_tmesh), done(hd); - if(is_border(hd, m_tmesh)){ - hd = prev(opposite(hd,m_tmesh),m_tmesh); - } - - do { //for each hd with vd as target look at all other faces - Point p = get(m_vpmap, vd); - Point q = get(m_vpmap, target(next(hd,m_tmesh), m_tmesh)); - Point r = get(m_vpmap, source(hd,m_tmesh)); - - Triangle th = triangle_functor(p, q, r); - - // first look at the directly shared edges - halfedge_descriptor ohd = opposite(hd, m_tmesh); - if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ - vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); - Point s = get(m_vpmap, ov); - if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(r,p,q,s) == POSITIVE){ - *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); - } - } - ohd = opposite(next(hd,m_tmesh), m_tmesh); - if((! is_border(ohd,m_tmesh)) && (hd < ohd)){ - vertex_descriptor ov = target(next(ohd,m_tmesh), m_tmesh); - Point s = get(m_vpmap, ov); - if(CGAL::coplanar(p,q,r,s) && CGAL::coplanar_orientation(p,q,r,s) == POSITIVE){ - *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(ohd, m_tmesh)); - } - } - halfedge_descriptor po = prev(opposite(hd,m_tmesh),m_tmesh); - halfedge_descriptor op = opposite(next(hd,m_tmesh),m_tmesh); - - for(halfedge_descriptor start : halfedges_around_target(hd,m_tmesh)){ - if((start == hd) || (start == op) || (start == po) || is_border(start, m_tmesh) || (face(hd, m_tmesh) < face(start, m_tmesh))){ - continue; - } - Segment ss = segment_functor(get(m_vpmap, source(start,m_tmesh)), - get(m_vpmap, target(next(start,m_tmesh), m_tmesh))); - if(do_intersect_3_functor(th, ss)){ - *m_iterator++ = std::make_pair(face(hd,m_tmesh), face(start, m_tmesh)); - } - } - hd = prev(opposite(hd,m_tmesh),m_tmesh); - }while(hd != done); - } - } -}; // end struct Intersect_facets_incident_to_vertex #endif struct Throw_at_output { @@ -772,126 +572,7 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) } /// \endcond -// experimental code for parallel processing on vertices -// (slower than general parallel on boxes). To be removed. -#if 0 -template -OutputIterator -self_intersections( const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np, - int) -{ - 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(boxes.size()); - - for(Box& b : boxes) - box_ptr.push_back(&b); - - - // (A) Parallel: look at each vertex and its incident faces - // Intersections are written into a concurrent vector - typedef typename GetGeomTraits::type GeomTraits; - - typedef tbb::concurrent_vector > CV; - CV cv_faces; - typedef std::back_insert_iterator CVI; - - CGAL::internal::Intersect_facets_incident_to_vertex - intersect_facets_incident_to_vertex(tmesh, - std::back_inserter(cv_faces), // result - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); -#ifdef CGAL_PMP_SI_DEBUG - Real_timer rt; - rt.start(); -#endif - - tbb::parallel_for(tbb::blocked_range(0, num_vertices(tmesh)), intersect_facets_incident_to_vertex); - - // Copy from the concurent container to the output iterator - for(typename CV::iterator it = cv_faces.begin(); it != cv_faces.end(); ++it){ - *out ++= *it; - } -#ifdef CGAL_PMP_SI_DEBUG - std::cout << "(A) Parallel: faces incident to each vertex " << rt.time() << "sec."<< std::endl; - rt.reset(); -#endif - - // (B) Sequential: Look at pairs of triangles with intersecting bbox - // Copy the pairs which do not share an edge or a vertex into a std::vector - typedef std::vector >SeqV; - SeqV seq_v_faces; - typedef std::back_insert_iterator SeqVI; - - CGAL::internal::Incident_faces_filter - incident_faces_filter(tmesh, - std::back_inserter(seq_v_faces)); - - std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),incident_faces_filter,cutoff); -#ifdef CGAL_PMP_SI_DEBUG - std::cout << "(B) Sequential: boxes that intersect " << rt.time() << "sec."<< std::endl; - rt.reset(); -#endif - - // (C) Parallel: Perform geometric test on pairs not sharing an edge or a vertex - std::vector dointersect(seq_v_faces.size()); - bool result(false); - CGAL::internal::TriangleTriangle tt(seq_v_faces, - dointersect, - result, - tmesh, - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); - tbb::parallel_for(tbb::blocked_range(0, seq_v_faces.size()), tt); - if(result){ - for(int i = 0; i < seq_v_faces.size(); ++i){ - if(dointersect[i]){ - *out ++= seq_v_faces[i]; - } - } - } -#ifdef CGAL_PMP_SI_DEBUG - std::cout << "(C) Parallel: Filter triangles that intersect " << rt.time() << "sec."<< std::endl; -#endif - return out; -} -#endif // CGAL_LINKED_WITH_TBB /** * \ingroup PMP_intersection_grp From f033e0a2447f4b493e2607ee0b4cf5cdc340e634 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 14 Nov 2019 11:45:37 +0100 Subject: [PATCH 19/61] Cleanup --- .../self_intersections_example.cpp | 18 +++-------- .../self_intersections.h | 32 +++++++------------ 2 files changed, 16 insertions(+), 34 deletions(-) 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 25c75967ee3..011e642891e 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 @@ -1,11 +1,7 @@ -struct Parallel_tag_bis {}; - #include #include #include -#include -#include #include @@ -26,23 +22,17 @@ int main(int argc, char* argv[]) std::cerr << "Not a valid input file." << std::endl; return 1; } - /* - bool intersecting = PMP::does_self_intersect(mesh, + + bool intersecting = PMP::does_self_intersect(mesh, PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl; - */ - CGAL::Real_timer rtimer; - CGAL::Timer timer; - rtimer.start(); - timer.start(); - std::vector > intersected_tris; - PMP::self_intersections(mesh, std::back_inserter(intersected_tris)); - std::cout << std::endl << "Total: " << rtimer.time() << " " << timer.time() << " sec." << std::endl; + PMP::self_intersections(faces(mesh),mesh, std::back_inserter(intersected_tris)); + std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; return 0; 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 12fb916727e..9eb4ee03988 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 @@ -212,19 +212,19 @@ struct AllPairs // data members const TM& m_tmesh; const VertexPointMap m_vpmap; - const std::vector >& seq_faces; + const std::vector >& face_pairs; std::vector& dointersect; typename Kernel::Construct_segment_3 segment_functor; typename Kernel::Construct_triangle_3 triangle_functor; typename Kernel::Do_intersect_3 do_intersect_3_functor; - AllPairs(const std::vector >& seq_faces, + AllPairs(const std::vector >& face_pairs, std::vector& dointersect, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) : m_tmesh(tmesh) , m_vpmap(vpmap) - , seq_faces(seq_faces) + , face_pairs(face_pairs) , dointersect(dointersect) , triangle_functor(kernel.construct_triangle_3_object()) , do_intersect_3_functor(kernel.do_intersect_3_object()) @@ -240,7 +240,7 @@ struct AllPairs void operator()(std::size_t ri) const { - const std::pair& ff = seq_faces[ri]; + const std::pair& ff = face_pairs[ri]; halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); vertex_descriptor hv[3], gv[3]; @@ -296,9 +296,9 @@ struct AllPairs break; } } - if (shared) { - break; - } + if (shared) { + break; + } } if(shared){ // found shared vertex: @@ -316,11 +316,7 @@ struct AllPairs Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), get(m_vpmap, gv[(j+2)%3])); - if(do_intersect_3_functor(t1,s2)){ - dointersect[ri] = true; - } else if(do_intersect_3_functor(t2,s1)){ - dointersect[ri] = true; - } + dointersect[ri] = (do_intersect_3_functor(t1, s2)) || do_intersect_3_functor(t2, s1); return; } @@ -331,9 +327,7 @@ struct AllPairs Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); - if(do_intersect_3_functor(t1, t2)){ - dointersect[ri] = true; - } + dointersect[ri] = do_intersect_3_functor(t1, t2); } }; @@ -425,8 +419,7 @@ self_intersections( const FaceRange& face_range, // make one box per face std::vector boxes; - boxes.reserve( - std::distance( boost::begin(face_range), boost::end(face_range) ) + boxes.reserve( std::distance( boost::begin(face_range), boost::end(face_range) ) ); typedef typename GetVertexPointMap::const_type VertexPointMap; @@ -511,9 +504,8 @@ 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(), - ConcurrencyTag()); + return self_intersections(face_range, tmesh, out, + CGAL::Polygon_mesh_processing::parameters::all_default()); } /// \endcond From 9c9284fbb4133b928d7c3bedf71ebea2b403e6ea Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 14 Nov 2019 12:17:46 +0100 Subject: [PATCH 20/61] make typedef public --- .../include/CGAL/internal/Static_filters/Static_filters.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 95216db79f9..6fd346434fb 100644 --- a/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h +++ b/Filtered_kernel/include/CGAL/internal/Static_filters/Static_filters.h @@ -98,8 +98,8 @@ class Static_filters : public K_base { typedef Static_filters Self; - typedef Static_filters_predicates::Coplanar_3 Coplanar_3; public: + typedef Static_filters_predicates::Coplanar_3 Coplanar_3; #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS typedef Static_filters_predicates::Equal_2 Equal_2; typedef Static_filters_predicates::Equal_3 Equal_3; From 3caad9bc88ed30652b99364dfede876a52c0289e Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Thu, 14 Nov 2019 13:26:47 +0100 Subject: [PATCH 21/61] Remove #include --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 1 - 1 file changed, 1 deletion(-) 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 9eb4ee03988..325f7c028be 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 @@ -48,7 +48,6 @@ #ifdef CGAL_LINKED_WITH_TBB #include #include -#include #endif #ifdef DOXYGEN_RUNNING From ff960adea0290cf8845faaf21b01e0873ec7b16c Mon Sep 17 00:00:00 2001 From: Mael Date: Thu, 14 Nov 2019 17:08:58 +0100 Subject: [PATCH 22/61] Fix namespace lookup issue (and a warning) --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 9eb4ee03988..b80b7069550 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 @@ -457,7 +457,7 @@ self_intersections( const FaceRange& face_range, typedef std::vector >SeqV; typedef std::back_insert_iterator SeqVI; SeqV face_pairs; - internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); + CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); // (B) Parallel: perform the geometric tests @@ -475,7 +475,7 @@ self_intersections( const FaceRange& face_range, tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); // (C) Sequentially: Copy from the concurent container to the output iterator - for(int i=0; i < dointersect.size(); ++i){ + for(std::size_t i=0; i < dointersect.size(); ++i){ if(dointersect[i]) *out ++= face_pairs[i]; } From d6a89652a152ae956e35a9a9ef61ab5d6c978d13 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 15 Nov 2019 12:48:16 +0100 Subject: [PATCH 23/61] CGAL:: Add Parallel_if_available_tag --- STL_Extension/include/CGAL/tags.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/STL_Extension/include/CGAL/tags.h b/STL_Extension/include/CGAL/tags.h index 4b033abaf32..2b88992794b 100644 --- a/STL_Extension/include/CGAL/tags.h +++ b/STL_Extension/include/CGAL/tags.h @@ -26,7 +26,7 @@ namespace CGAL { struct Void {}; // Boolean_tag is a model of the Boost Integral Constant concept. -// https://www.boost.org/libs/mpl/doc/refmanual/integral-constant.html +// https://www.boost.org/libs/mpl/doc/refmanual/integral-constant.html template struct Boolean_tag { typedef boost::mpl::integral_c_tag tag; @@ -58,6 +58,13 @@ struct Null_functor { struct Sequential_tag {}; struct Parallel_tag : public Sequential_tag {}; +#ifdef CGAL_LINKED_WITH_TBB +typedef CGAL::Parallel_tag Parallel_if_available_tag; +#else +typedef CGAL::Sequential_tag Parallel_if_available_tag; +#endif + + // A function that asserts a specific compile time tag // forcing its two arguments to have equal type. template From 363f77145c2aee9b4697b7819a8363207102d7eb Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 15 Nov 2019 14:24:09 +0100 Subject: [PATCH 24/61] Do first self-intersection tests in parallel in the demo --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 8 +++++++- .../demo/Polyhedron/Scene_polyhedron_selection_item.cpp | 2 +- Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index fc4afa3bb09..bce7f8b0b9c 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -250,7 +250,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 ) @@ -261,6 +264,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/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 09dd204eff6..88365d2667d 100644 --- a/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp @@ -1656,7 +1656,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_)) From bef2b5f1b8343e922fff3d48de02d7f8e46eb546 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 15 Nov 2019 16:21:25 +0100 Subject: [PATCH 25/61] Parallelize using 2 or 4 parallel threads --- .../CGAL/Box_intersection_d/segment_tree.h | 15 +--- .../include/CGAL/box_intersection_d.h | 72 ++++++++++++++++--- .../self_intersections_example.cpp | 9 ++- .../self_intersections.h | 30 +++++--- 4 files changed, 91 insertions(+), 35 deletions(-) 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 5c31223d85a..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,9 +23,6 @@ #include #include -#ifdef CGAL_LINKED_WITH_TBB -#include -#endif #include #include #include @@ -96,13 +92,9 @@ void one_way_scan( RandomAccessIter1 p_begin, RandomAccessIter1 p_end, { typedef typename Traits::Compare Compare; -#ifdef CGAL_LINKED_WITH_TBB - tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); - tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); -#else + // 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 ) ); -#endif // for each box viewed as interval i for( RandomAccessIter2 i = i_begin; i != i_end; ++i ) { @@ -141,13 +133,8 @@ void modified_two_way_scan( { typedef typename Traits::Compare Compare; -#ifdef CGAL_LINKED_WITH_TBB - tbb::parallel_sort( p_begin, p_end, Compare( 0 ) ); - tbb::parallel_sort( i_begin, i_end, Compare( 0 ) ); -#else std::sort( p_begin, p_end, Compare( 0 ) ); std::sort( i_begin, i_end, Compare( 0 ) ); -#endif // for each box viewed as interval while( i_begin != i_end && p_begin != p_end ) { diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index bf5a8f3d62a..1d210d76f90 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -25,6 +25,7 @@ #include #include +#include "tbb/parallel_invoke.h" #include @@ -178,14 +179,69 @@ 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); +#ifndef CGAL_LINKED_WITH_TBB + box_intersection_d( begin, end, i.begin(), i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); +#else + + // TODO: Check which of the two following approaches is better + // The first one makes three copies of the vector and performs + // four parallel tasks + // The second one makes one copy and performs two times two parallel tasks +#ifdef CGAL_BI_FOR_SPEED + + + std::vector< val_t> j( begin, end); + std::vector< val_t> k( begin, end); + + RandomAccessIter mid = begin; + std::advance(mid, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midi = i.begin(); + std::advance(midi, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midj = j.begin(); + std::advance(midj, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midk = k.begin(); + std::advance(midk, std::distance(begin,end)/2); + + tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( j.begin(), midj, midk, k.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( midj, j.end(), k.begin(), midk, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); +#else + RandomAccessIter mid = begin; + std::advance(mid, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midi = i.begin(); + std::advance(midi, std::distance(begin,end)/2); + + tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); + tbb::parallel_invoke([&]{box_intersection_d( begin, mid, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); +#endif + +#endif } template< class RandomAccessIter, class Callback, class BoxTraits > 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 011e642891e..28249397952 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,6 +2,7 @@ #include #include +#include #include @@ -22,17 +23,21 @@ int main(int argc, char* argv[]) std::cerr << "Not a valid input file." << std::endl; return 1; } - + + CGAL::Real_timer rt; + rt.start(); + /* bool intersecting = PMP::does_self_intersect(mesh, PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl; - + */ std::vector > intersected_tris; PMP::self_intersections(faces(mesh),mesh, std::back_inserter(intersected_tris)); + std::cout << rt.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; return 0; 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 55adf9ab558..c6a4b42925b 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 @@ -48,6 +48,7 @@ #ifdef CGAL_LINKED_WITH_TBB #include #include +#include #endif #ifdef DOXYGEN_RUNNING @@ -197,6 +198,7 @@ struct Intersect_facets //TODO: use the same code for the linear pass? // The functor for doing all geometric tests in parallel template struct AllPairs @@ -211,14 +213,14 @@ struct AllPairs // data members const TM& m_tmesh; const VertexPointMap m_vpmap; - const std::vector >& face_pairs; + const FacePairs& face_pairs; std::vector& dointersect; typename Kernel::Construct_segment_3 segment_functor; typename Kernel::Construct_triangle_3 triangle_functor; typename Kernel::Do_intersect_3 do_intersect_3_functor; - AllPairs(const std::vector >& face_pairs, + AllPairs(const FacePairs& face_pairs, std::vector& dointersect, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) : m_tmesh(tmesh) @@ -345,7 +347,7 @@ struct All_faces_filter template void operator()(const Box* b, const Box* c) const { - *m_iterator ++ = std::make_pair(b->info(), c->info()); + *m_iterator ++ = std::make_pair(b->info(), c->info()); } // end operator () }; @@ -378,7 +380,7 @@ namespace Polygon_mesh_processing { * @pre `CGAL::is_triangle_mesh(tmesh)` * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` and `Parallel_tag`. + * Possible values are `Sequential_tag`, `Parallel_tag`, and `Parallel_if_available_tag`. * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, * model of `Range`. * Its iterator type is `RandomAccessIterator`. @@ -453,10 +455,14 @@ self_intersections( const FaceRange& face_range, // (Parallel version of the code) // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector std::ptrdiff_t cutoff = 2000; - typedef std::vector >SeqV; - typedef std::back_insert_iterator SeqVI; - SeqV face_pairs; - CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); +#if 0 + typedef std::vector >FacePairs; +#else + typedef tbb::concurrent_vector >FacePairs; +#endif + typedef std::back_insert_iterator FacePairsI; + FacePairs face_pairs; + CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); // (B) Parallel: perform the geometric tests @@ -464,7 +470,7 @@ self_intersections( const FaceRange& face_range, std::vector dointersect(face_pairs.size(),0); - CGAL::internal::AllPairs + CGAL::internal::AllPairs all_pairs(face_pairs, dointersect, tmesh, @@ -520,7 +526,7 @@ self_intersections(const FaceRange& face_range, * @pre `CGAL::is_triangle_mesh(tmesh)` * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` and `Parallel_tag`. + * 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 * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` @@ -572,7 +578,7 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) * @pre `CGAL::is_triangle_mesh(tmesh)` * * @tparam ConcurrencyTag enables sequential versus parallel algorithm. - * Possible values are `Sequential_tag` and `Parallel_tag`. + * 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" * @@ -614,6 +620,8 @@ bool does_self_intersect(const TriangleMesh& tmesh * 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" From a44674a694456d98f1af9040ae4ff82d670910ae Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 15 Nov 2019 21:45:19 +0100 Subject: [PATCH 26/61] Add ConcurrencyTag in Box_intersection_d --- .../include/CGAL/box_intersection_d.h | 76 ++++++++++++++----- .../self_intersections_example.cpp | 11 +-- .../self_intersections.h | 13 ++-- 3 files changed, 65 insertions(+), 35 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 1d210d76f90..51c41cd5156 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -25,7 +25,9 @@ #include #include -#include "tbb/parallel_invoke.h" +#ifdef CGAL_LINKED_WITH_TBB +#include +#endif #include @@ -177,26 +179,46 @@ void box_self_intersection_d( Callback callback, BoxTraits box_traits, std::ptrdiff_t cutoff, - Box_intersection_d::Topology topology) + Box_intersection_d::Topology topology, + Sequential_tag) { // 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); -#ifndef CGAL_LINKED_WITH_TBB + box_intersection_d( begin, end, i.begin(), i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); +} + + +template< class RandomAccessIter, class Callback, class BoxTraits > +void box_self_intersection_d( + RandomAccessIter begin, RandomAccessIter end, + Callback callback, + BoxTraits box_traits, + std::ptrdiff_t cutoff, + Box_intersection_d::Topology topology, + Parallel_tag) +{ +#if !defined(CGAL_LINKED_WITH_TBB) + use(begin); use(end); use(callback); use(box_traits); use(cutoff); use(topology); + CGAL_static_assertion_msg (!(boost::is_convertible::value), + "Parallel_tag is enabled but TBB is unavailable."); #else + // 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); // TODO: Check which of the two following approaches is better // The first one makes three copies of the vector and performs // four parallel tasks // The second one makes one copy and performs two times two parallel tasks #ifdef CGAL_BI_FOR_SPEED - - std::vector< val_t> j( begin, end); std::vector< val_t> k( begin, end); @@ -221,7 +243,7 @@ void box_self_intersection_d( [&]{ box_intersection_d( midj, j.end(), k.begin(), midk, callback, box_traits, cutoff, topology, Box_intersection_d::COMPLETE); } ); -#else +#else RandomAccessIter mid = begin; std::advance(mid, std::distance(begin,end)/2); typename std::vector< val_t>::iterator midi = i.begin(); @@ -239,44 +261,58 @@ void box_self_intersection_d( [&]{ box_intersection_d( mid, end, i.begin(), midi, callback, box_traits, cutoff, topology, Box_intersection_d::COMPLETE); } ); -#endif +#endif -#endif +#endif +} + +// Generic call with box traits parameter, specialized for self-intersection. +// - make all default parameters explicit overloads (workaround) +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, + Box_intersection_d::Topology topology) +{ + box_self_intersection_d(begin,end, callback, box_traits, cutoff, topology, ConcurrencyTag()); } -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, + 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, @@ -284,10 +320,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, @@ -296,7 +332,7 @@ 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_self_intersection_d(begin, end, callback, Box_traits(), cutoff, topology ); } 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 28249397952..240632ee690 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,7 +2,6 @@ #include #include -#include #include @@ -24,20 +23,16 @@ int main(int argc, char* argv[]) return 1; } - CGAL::Real_timer rt; - rt.start(); - /* - bool intersecting = PMP::does_self_intersect(mesh, + bool intersecting = PMP::does_self_intersect(mesh, PMP::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); std::cout << (intersecting ? "There are self-intersections." : "There is no self-intersection.") << std::endl; - */ + std::vector > intersected_tris; - PMP::self_intersections(faces(mesh),mesh, std::back_inserter(intersected_tris)); + PMP::self_intersections(faces(mesh),mesh, std::back_inserter(intersected_tris)); - std::cout << rt.time() << " sec." << std::endl; std::cout << intersected_tris.size() << " pairs of triangles intersect." << std::endl; return 0; 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 c6a4b42925b..156569ad1ab 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 @@ -450,20 +450,19 @@ self_intersections( const FaceRange& face_range, CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else + if (boost::is_convertible::value) { - // (Parallel version of the code) + // (Parallel version of the code) // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector std::ptrdiff_t cutoff = 2000; -#if 0 - typedef std::vector >FacePairs; -#else + typedef tbb::concurrent_vector >FacePairs; -#endif + typedef std::back_insert_iterator FacePairsI; FacePairs face_pairs; CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); // (B) Parallel: perform the geometric tests typedef typename GetGeomTraits::type GeomTraits; @@ -557,7 +556,7 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator 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 From a682dcb3602d9f3a195d2e79791899083a5e9fae Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 18 Nov 2019 14:21:21 +0100 Subject: [PATCH 27/61] use -> USE --- Box_intersection_d/include/CGAL/box_intersection_d.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 51c41cd5156..ce8b81b854e 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -204,7 +204,7 @@ void box_self_intersection_d( Parallel_tag) { #if !defined(CGAL_LINKED_WITH_TBB) - use(begin); use(end); use(callback); use(box_traits); use(cutoff); use(topology); + USE(begin); USE(end); USE(callback); USE(box_traits); USE(cutoff); USE(topology); CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else From d33eb65cbf5688b713ea690e7ff2198707b1eeaf Mon Sep 17 00:00:00 2001 From: Mael Date: Mon, 18 Nov 2019 15:43:04 +0100 Subject: [PATCH 28/61] fix CGAL_USE usage --- Box_intersection_d/include/CGAL/box_intersection_d.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index ce8b81b854e..3759f2584b9 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -25,6 +25,8 @@ #include #include +#include + #ifdef CGAL_LINKED_WITH_TBB #include #endif @@ -204,7 +206,7 @@ void box_self_intersection_d( Parallel_tag) { #if !defined(CGAL_LINKED_WITH_TBB) - USE(begin); USE(end); USE(callback); USE(box_traits); USE(cutoff); USE(topology); + CGAL_USE(begin); CGAL_USE(end); CGAL_USE(callback); CGAL_USE(box_traits); CGAL_USE(cutoff); CGAL_USE(topology); CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else From 4bbaafe80830d35530a28c8315a2d6e60b82a6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 11:56:10 +0100 Subject: [PATCH 29/61] Fix using undefined type --- Box_intersection_d/include/CGAL/box_intersection_d.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 3759f2584b9..89effb7ce06 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -207,8 +207,7 @@ void box_self_intersection_d( { #if !defined(CGAL_LINKED_WITH_TBB) CGAL_USE(begin); CGAL_USE(end); CGAL_USE(callback); CGAL_USE(box_traits); CGAL_USE(cutoff); CGAL_USE(topology); - CGAL_static_assertion_msg (!(boost::is_convertible::value), - "Parallel_tag is enabled but TBB is unavailable."); + CGAL_static_assertion_msg(false, "Parallel_tag is enabled but TBB is unavailable."); #else // Copying rather than calling 'box_intersection_d(begin, end, begin, end, ...' // is necessary because the 'std::partition' and range splits on the first range From 44e2b52ca7a2c958550f8c9ed7c0992c14efb833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 12:50:21 +0100 Subject: [PATCH 30/61] Clean superfluous overloads --- .../include/CGAL/box_intersection_d.h | 171 ++++++++---------- 1 file changed, 74 insertions(+), 97 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 89effb7ce06..41da730d747 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -172,101 +172,6 @@ void box_intersection_d( 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 > -void box_self_intersection_d( - RandomAccessIter begin, RandomAccessIter end, - Callback callback, - BoxTraits box_traits, - std::ptrdiff_t cutoff, - Box_intersection_d::Topology topology, - Sequential_tag) -{ - // 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 > -void box_self_intersection_d( - RandomAccessIter begin, RandomAccessIter end, - Callback callback, - BoxTraits box_traits, - std::ptrdiff_t cutoff, - Box_intersection_d::Topology topology, - Parallel_tag) -{ -#if !defined(CGAL_LINKED_WITH_TBB) - CGAL_USE(begin); CGAL_USE(end); CGAL_USE(callback); CGAL_USE(box_traits); CGAL_USE(cutoff); CGAL_USE(topology); - CGAL_static_assertion_msg(false, "Parallel_tag is enabled but TBB is unavailable."); -#else - // 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); - - // TODO: Check which of the two following approaches is better - // The first one makes three copies of the vector and performs - // four parallel tasks - // The second one makes one copy and performs two times two parallel tasks -#ifdef CGAL_BI_FOR_SPEED - std::vector< val_t> j( begin, end); - std::vector< val_t> k( begin, end); - - RandomAccessIter mid = begin; - std::advance(mid, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midi = i.begin(); - std::advance(midi, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midj = j.begin(); - std::advance(midj, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midk = k.begin(); - std::advance(midk, std::distance(begin,end)/2); - - tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( j.begin(), midj, midk, k.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( midj, j.end(), k.begin(), midk, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); -#else - RandomAccessIter mid = begin; - std::advance(mid, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midi = i.begin(); - std::advance(midi, std::distance(begin,end)/2); - - tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); - tbb::parallel_invoke([&]{box_intersection_d( begin, mid, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); -#endif - -#endif -} - // Generic call with box traits parameter, specialized for self-intersection. // - make all default parameters explicit overloads (workaround) template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback, class BoxTraits > @@ -277,10 +182,82 @@ void box_self_intersection_d( std::ptrdiff_t cutoff, Box_intersection_d::Topology topology) { - box_self_intersection_d(begin,end, callback, box_traits, cutoff, topology, ConcurrencyTag()); +#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) + { + // 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); + + // TODO: Check which of the two following approaches is better + // The first one makes three copies of the vector and performs four parallel tasks + // The second one makes one copy, but must perform two times two parallel tasks (can't + // do all four at the same time otherwise the sort / split will conflict) +#ifdef CGAL_BOX_INTER_FOUR_RANGES + std::vector< val_t> j( begin, end); + std::vector< val_t> k( begin, end); + + RandomAccessIter mid = begin; + std::advance(mid, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midi = i.begin(); + std::advance(midi, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midj = j.begin(); + std::advance(midj, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midk = k.begin(); + std::advance(midk, std::distance(begin,end)/2); + + tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( j.begin(), midj, midk, k.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( midj, j.end(), k.begin(), midk, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); +#else // CGAL_BOX_INTER_FOUR_RANGES + RandomAccessIter mid = begin; + std::advance(mid, std::distance(begin,end)/2); + typename std::vector< val_t>::iterator midi = i.begin(); + std::advance(midi, std::distance(begin,end)/2); + + tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); + tbb::parallel_invoke([&]{box_intersection_d( begin, mid, midi, i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); }, + [&]{ box_intersection_d( mid, end, i.begin(), midi, + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } ); +#endif // CGAL_BOX_INTER_FOUR_RANGES + } + else +#endif // CGAL_LINKED_WITH_TBB + { + // 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 ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback, class BoxTraits > void box_self_intersection_d( RandomAccessIter begin, RandomAccessIter end, From ac86fadd7a60059db65e7fec5eb6c84649067e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 12:51:17 +0100 Subject: [PATCH 31/61] Misc code formatting improvements --- .../include/CGAL/box_intersection_d.h | 4 +- .../internal/Static_filters/Static_filters.h | 29 ++-- .../self_intersections_example.cpp | 24 ++-- .../self_intersections.h | 126 ++++++++---------- STL_Extension/include/CGAL/tags.h | 1 - 5 files changed, 79 insertions(+), 105 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 41da730d747..7521802ba49 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -266,7 +266,7 @@ void box_self_intersection_d( std::ptrdiff_t cutoff) { return box_self_intersection_d(begin, end, callback, box_traits, cutoff, - Box_intersection_d::CLOSED); + Box_intersection_d::CLOSED); } template< class ConcurrencyTag = Sequential_tag, class RandomAccessIter, class Callback, class BoxTraits > @@ -311,7 +311,7 @@ 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_traits(), cutoff, topology ); } 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 6fd346434fb..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,9 +41,6 @@ #endif // CGAL_DISABLE_STATIC_FILTERS_ADDED_2011 - -# include - #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS # include # include @@ -67,6 +64,7 @@ # include #endif // NOT NOT CGAL_NO_DO_INTERSECT_STATIC_FILTERS +#include #include #include #include @@ -99,7 +97,6 @@ class Static_filters : public K_base typedef Static_filters Self; public: - typedef Static_filters_predicates::Coplanar_3 Coplanar_3; #ifndef CGAL_NO_EQUAL_3_STATIC_FILTERS typedef Static_filters_predicates::Equal_2 Equal_2; typedef Static_filters_predicates::Equal_3 Equal_3; @@ -124,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; @@ -140,35 +138,29 @@ public: collinear_3_object() const { return Collinear_3(); } - Coplanar_3 - coplanar_3_object() const - { - return Coplanar_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 @@ -191,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/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/self_intersections_example.cpp index 240632ee690..1ce5501e5cb 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,13 @@ #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 +21,17 @@ 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))); + 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 - << (intersecting ? "There are self-intersections." : "There is no self-intersection.") - << std::endl; - std::vector > intersected_tris; - PMP::self_intersections(faces(mesh),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; + + return EXIT_SUCCESS; } 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 156569ad1ab..0aef552862a 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 @@ -57,10 +57,9 @@ #endif namespace CGAL { - namespace internal { - template ::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::property_map::const_type Ppmap; // members @@ -97,7 +96,7 @@ struct Intersect_facets void operator()(const Box* b, const Box* c) const { halfedge_descriptor h = halfedge(b->info(), m_tmesh); - halfedge_descriptor g = halfedge(c->info(),m_tmesh); + halfedge_descriptor g = halfedge(c->info(), m_tmesh); vertex_descriptor hv[3], gv[3]; hv[0] = target(h, m_tmesh); @@ -116,10 +115,10 @@ struct Intersect_facets if(face(opp_h, m_tmesh) == c->info()){ // there is an intersection if the four points are coplanar and // the triangles overlap - get(m_vpmap, hv[i]); - get(m_vpmap, hv[(i + 1) % 3]); - get(m_vpmap, hv[(i + 2) % 3]); - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); + get(m_vpmap, hv[i]); + get(m_vpmap, hv[(i + 1) % 3]); + get(m_vpmap, hv[(i + 2) % 3]); + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); if(CGAL::coplanar(get(m_vpmap, hv[i]), get(m_vpmap, hv[(i+1)%3]), @@ -158,7 +157,8 @@ struct Intersect_facets } if(shared){ // found shared vertex: - assert(hv[i] == gv[j]); + CGAL_assertion(hv[i] == gv[j]); + // geometric check if the opposite segments intersect the triangles Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), get(m_vpmap, hv[1]), @@ -223,18 +223,17 @@ struct AllPairs AllPairs(const FacePairs& face_pairs, std::vector& dointersect, const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) - : m_tmesh(tmesh) - , m_vpmap(vpmap) - , face_pairs(face_pairs) - , dointersect(dointersect) - , triangle_functor(kernel.construct_triangle_3_object()) - , do_intersect_3_functor(kernel.do_intersect_3_object()) + : m_tmesh(tmesh), + m_vpmap(vpmap), + face_pairs(face_pairs), + dointersect(dointersect), + triangle_functor(kernel.construct_triangle_3_object()), + do_intersect_3_functor(kernel.do_intersect_3_object()) {} void operator()(const tbb::blocked_range &r) const { for (std::size_t ri = r.begin(); ri != r.end(); ++ri) { - this->operator()(ri); } } @@ -261,10 +260,10 @@ struct AllPairs if(face(opp_h, m_tmesh) == ff.second){ // there is an intersection if the four points are coplanar and // the triangles overlap - get(m_vpmap, hv[i]); - get(m_vpmap, hv[(i + 1) % 3]); - get(m_vpmap, hv[(i + 2) % 3]); - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); + get(m_vpmap, hv[i]); + get(m_vpmap, hv[(i + 1) % 3]); + get(m_vpmap, hv[(i + 2) % 3]); + get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); if(CGAL::coplanar(get(m_vpmap, hv[i]), get(m_vpmap, hv[(i+1)%3]), @@ -303,7 +302,8 @@ struct AllPairs } if(shared){ // found shared vertex: - assert(hv[i] == gv[j]); + CGAL_assertion(hv[i] == gv[j]); + // geometric check if the opposite segments intersect the triangles Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), get(m_vpmap, hv[1]), @@ -328,7 +328,7 @@ struct AllPairs Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), get(m_vpmap, gv[1]), get(m_vpmap, gv[2])); - dointersect[ri] = do_intersect_3_functor(t1, t2); + dointersect[ri] = do_intersect_3_functor(t1, t2); } }; @@ -339,17 +339,13 @@ struct All_faces_filter { mutable OutputIterator m_iterator; - - All_faces_filter(OutputIterator it) - : m_iterator(it) - {} + All_faces_filter(OutputIterator it) : m_iterator(it) {} template void operator()(const Box* b, const Box* c) const { *m_iterator ++ = std::make_pair(b->info(), c->info()); - - } // end operator () + } }; @@ -414,19 +410,21 @@ self_intersections( const FaceRange& face_range, { CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); - typedef TriangleMesh TM; - typedef typename boost::graph_traits::face_descriptor face_descriptor; + 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 face - std::vector boxes; - boxes.reserve( std::distance( boost::begin(face_range), boost::end(face_range) ) - ); + typedef typename GetGeomTraits::type GeomTraits; + GeomTraits gt = parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits()); 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)); + // make one box per face + std::vector boxes; + boxes.reserve(std::distance(boost::begin(face_range), boost::end(face_range))); + for(face_descriptor f : face_range) { typename boost::property_traits::reference @@ -439,6 +437,7 @@ self_intersections( const FaceRange& face_range, else boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f)); } + // generate box pointers std::vector box_ptr; box_ptr.reserve(boxes.size()); @@ -450,31 +449,22 @@ self_intersections( const FaceRange& face_range, CGAL_static_assertion_msg (!(boost::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else - - if (boost::is_convertible::value) + if (boost::is_convertible::value) { // (Parallel version of the code) // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector std::ptrdiff_t cutoff = 2000; - typedef tbb::concurrent_vector >FacePairs; + typedef tbb::concurrent_vector >FacePairs; typedef std::back_insert_iterator FacePairsI; FacePairs face_pairs; CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),all_faces_filter,cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), all_faces_filter, cutoff); // (B) Parallel: perform the geometric tests - typedef typename GetGeomTraits::type GeomTraits; - - std::vector dointersect(face_pairs.size(),0); - - CGAL::internal::AllPairs - all_pairs(face_pairs, - dointersect, - tmesh, - vpmap, - parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits())); + std::vector dointersect(face_pairs.size(), 0); + CGAL::internal::AllPairs all_pairs(face_pairs, dointersect, tmesh, vpmap, gt); tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); @@ -488,13 +478,11 @@ self_intersections( const FaceRange& face_range, #endif // (Sequential version of the code) 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())); + CGAL::internal::Intersect_facets + intersect_facets(tmesh, out, vpmap, gt); std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets,cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets, cutoff); return intersect_facets.m_iterator; } @@ -508,8 +496,7 @@ 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()); + return self_intersections(face_range, tmesh, out, CGAL::parameters::all_default()); } /// \endcond @@ -547,10 +534,10 @@ self_intersections(const FaceRange& face_range, * * @return `out` */ -template +template OutputIterator self_intersections(const TriangleMesh& tmesh, OutputIterator out, @@ -568,8 +555,6 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) } /// \endcond - - /** * \ingroup PMP_intersection_grp * tests if a triangulated surface mesh self-intersects. @@ -594,11 +579,10 @@ self_intersections(const TriangleMesh& tmesh, OutputIterator out) * @return `true` if `tmesh` self-intersects */ template -bool does_self_intersect(const TriangleMesh& tmesh - , const CGAL_PMP_NP_CLASS& np) + class TriangleMesh, + class CGAL_PMP_NP_TEMPLATE_PARAMETERS> +bool does_self_intersect(const TriangleMesh& tmesh, + const CGAL_PMP_NP_CLASS& np) { CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); @@ -641,8 +625,7 @@ bool does_self_intersect(const TriangleMesh& tmesh template + class NamedParameters> bool does_self_intersect(const FaceRange& face_range, const TriangleMesh& tmesh, const NamedParameters& np) @@ -664,18 +647,15 @@ bool does_self_intersect(const FaceRange& face_range, template bool does_self_intersect(const TriangleMesh& tmesh) { - return does_self_intersect(tmesh, - CGAL::Polygon_mesh_processing::parameters::all_default()); + return does_self_intersect(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 diff --git a/STL_Extension/include/CGAL/tags.h b/STL_Extension/include/CGAL/tags.h index 2b88992794b..8feef206784 100644 --- a/STL_Extension/include/CGAL/tags.h +++ b/STL_Extension/include/CGAL/tags.h @@ -63,7 +63,6 @@ typedef CGAL::Parallel_tag Parallel_if_available_tag; #else typedef CGAL::Sequential_tag Parallel_if_available_tag; #endif - // A function that asserts a specific compile time tag // forcing its two arguments to have equal type. From 9ef1c976c61ccdac5269f5984944deb3c62d4f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 12:51:36 +0100 Subject: [PATCH 32/61] Use one of the tests of self_intersection.h to test the parallel tags --- .../self_intersection_surface_mesh_test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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..6d468a267d1 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,16 +1,16 @@ -#include -#include -#include -#include - #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; @@ -35,17 +35,17 @@ test_self_intersections(const char* filename, const bool expected) timer.start(); std::vector > intersected_tris; - CGAL::Polygon_mesh_processing::self_intersections( + 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))); + CGAL::parameters::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, + bool intersecting_2 = CGAL::Polygon_mesh_processing::does_self_intersect(m, CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m))); std::cout << "does_self_intersect test took " << timer.time() << " sec." << std::endl; From b7d20e00332b322d650bf5b73a2467ca5f4b297c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 14:40:30 +0100 Subject: [PATCH 33/61] Move range splitting higher to also parallelize 'box_intersection_d()' --- .../include/CGAL/box_intersection_d.h | 291 ++++++++++-------- 1 file changed, 158 insertions(+), 133 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 7521802ba49..0f4088b50b6 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -26,17 +26,103 @@ #include #include +#include #ifdef CGAL_LINKED_WITH_TBB #include #endif +#include #include 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) + { + typename std::iterator_traits::difference_type r1hs = std::distance(begin1, end1) / 2; + typename std::iterator_traits::difference_type r2hs = std::distance(begin2, end2) / 2; + + // TODO: Check which of the two following approaches is better + // The first one makes three copies of the vector and performs four parallel tasks + // The second one makes one copy, but must perform two times two parallel tasks (can't + // do all four at the same time otherwise the sort / split will conflict) +#ifdef CGAL_BOX_INTER_FOUR_RANGES + typedef typename std::iterator_traits::value_type val_t; + + std::vector< val_t> r3( begin1, end1); + std::vector< val_t> r4( begin2, end2); + + RandomAccessIter1 mid1 = begin1; + std::advance(mid1, r1hs); + RandomAccessIter2 mid2 = begin2; + std::advance(mid2, r2hs); + typename std::vector< val_t>::iterator mid3 = r3.begin(); + std::advance(mid3, r1hs); + typename std::vector< val_t>::iterator mid4 = r4.begin(); + std::advance(mid4, r2hs); + + tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( mid1, end1, mid2, end2, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r3.begin(), mid3, mid4, r4.end(), inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( mid3, r3.end(), r4.begin(), mid4, inf, sup, + callback, traits, cutoff, dim, in_order); } ); +#else // CGAL_BOX_INTER_FOUR_RANGES + RandomAccessIter1 mid1 = begin1; + std::advance(mid1, r1hs); + RandomAccessIter2 mid2 = begin2; + std::advance(mid2, r2hs); + + tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( mid1, end1, mid2, end2, inf, sup, + callback, traits, cutoff, dim, in_order); } ); + tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, mid2, end2, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( mid1, end1, begin2, mid2, inf, sup, + callback, traits, cutoff, dim, in_order); } ); + +#endif // CGAL_BOX_INTER_FOUR_RANGES + } + else +#endif // CGAL_LINKED_WITH_TBB + { + Box_intersection_d::segment_tree(begin1, end1, begin2, end2, inf, sup, callback, traits, cutoff, dim, in_order); + } +} + +} // namespace internal + +// Generic call with custom predicate traits parameter. +template< class ConcurrencyTag = Sequential_tag, + class RandomAccessIter1, class RandomAccessIter2, class Callback, class BoxPredicateTraits > void box_intersection_custom_predicates_d( RandomAccessIter1 begin1, RandomAccessIter1 end1, @@ -46,24 +132,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, @@ -74,18 +151,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, @@ -93,35 +171,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, @@ -129,52 +211,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 ConcurrencyTag = Sequential_tag, 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, @@ -182,83 +270,19 @@ void box_self_intersection_d( std::ptrdiff_t cutoff, Box_intersection_d::Topology topology) { -#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) - { - // 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); + // 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); - // TODO: Check which of the two following approaches is better - // The first one makes three copies of the vector and performs four parallel tasks - // The second one makes one copy, but must perform two times two parallel tasks (can't - // do all four at the same time otherwise the sort / split will conflict) -#ifdef CGAL_BOX_INTER_FOUR_RANGES - std::vector< val_t> j( begin, end); - std::vector< val_t> k( begin, end); - - RandomAccessIter mid = begin; - std::advance(mid, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midi = i.begin(); - std::advance(midi, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midj = j.begin(); - std::advance(midj, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midk = k.begin(); - std::advance(midk, std::distance(begin,end)/2); - - tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( j.begin(), midj, midk, k.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( midj, j.end(), k.begin(), midk, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); -#else // CGAL_BOX_INTER_FOUR_RANGES - RandomAccessIter mid = begin; - std::advance(mid, std::distance(begin,end)/2); - typename std::vector< val_t>::iterator midi = i.begin(); - std::advance(midi, std::distance(begin,end)/2); - - tbb::parallel_invoke([&]{ box_intersection_d( begin, mid, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); - tbb::parallel_invoke([&]{box_intersection_d( begin, mid, midi, i.end(), - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); }, - [&]{ box_intersection_d( mid, end, i.begin(), midi, - callback, box_traits, cutoff, topology, - Box_intersection_d::COMPLETE); } ); -#endif // CGAL_BOX_INTER_FOUR_RANGES - } - else -#endif // CGAL_LINKED_WITH_TBB - { - // 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); - } + box_intersection_d( begin, end, i.begin(), i.end(), + callback, box_traits, cutoff, topology, + Box_intersection_d::COMPLETE); } -template< class ConcurrencyTag = Sequential_tag, 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, @@ -269,7 +293,8 @@ void box_self_intersection_d( Box_intersection_d::CLOSED); } -template< class ConcurrencyTag = Sequential_tag, 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, From 52ce0b6ac41d993708e6b0d44a143574bed4698c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 16:40:11 +0100 Subject: [PATCH 34/61] Change Box_with_info to use the policy ID_EXPLICIT by default ID_FROM_BOX_ADDRESS does not work when you pass a range of boxes by value and not by pointers. Since doing that while using ID_FROM_BOX_ADDRESS is completely silent (no errors despite not being compatible), this is super dangerous. Besides, the Box_d has default policy ID_EXPLICIT, so it should have been that in the first place. --- .../CGAL/Box_intersection_d/Box_with_info_d.h | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) 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..990f3dd5fbb 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, ID_EXPLICIT> 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 From b6dd62be5213706acd93cbbd9ad965eaad0183ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 17:06:47 +0100 Subject: [PATCH 35/61] Use ID_FROM_BOX_ADDRESS in Box_with_info_d where safe That is, where we are passing box ranges by pointer. See also 52ce0b6ac41d993708e6b0d44a143574bed4698c --- ...ABB_traversal_traits_with_transformation.h | 1 - .../Corefinement/intersection_callbacks.h | 16 +++++++++---- .../internal/Corefinement/intersection_impl.h | 4 ++-- .../internal/repair_extra.h | 3 ++- .../Polygon_mesh_processing/intersection.h | 24 +++++++++++++------ .../self_intersections.h | 4 +++- .../internal/validity.h | 6 +++-- 7 files changed, 40 insertions(+), 18 deletions(-) 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 715dea7057b..0f2f9717be0 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; 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..0373aefbf8a 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; 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..f564c26b304 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -401,8 +401,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); @@ -543,7 +545,8 @@ compute_face_polyline_intersection( const FaceRange& face_range, 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; // make one box per facet std::vector boxes1; @@ -679,7 +682,8 @@ compute_face_polylines_intersection(const FaceRange& face_range, 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; @@ -773,7 +777,9 @@ 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; @@ -856,7 +862,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; @@ -1595,7 +1603,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())); 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 0aef552862a..526f143235e 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 @@ -412,7 +412,9 @@ self_intersections( const FaceRange& face_range, 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; typedef typename GetGeomTraits::type GeomTraits; GeomTraits gt = parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits()); 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..cdf8ce2de80 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; From 41bb11cdee456a3a231bd1d9cf7d5b728727f200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 17:08:25 +0100 Subject: [PATCH 36/61] Make unique indentation style a little less unique (no real changes) --- .../include/CGAL/box_intersection_d.h | 43 ++++--- .../internal/Corefinement/intersection_impl.h | 9 +- .../internal/repair_extra.h | 1 - .../Polygon_mesh_processing/intersection.h | 112 ++++++------------ .../internal/validity.h | 3 +- 5 files changed, 64 insertions(+), 104 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index 0f4088b50b6..cdbf058fcb6 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 @@ -339,24 +339,23 @@ void box_self_intersection_d( 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, @@ -366,18 +365,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, @@ -390,20 +389,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, @@ -411,12 +410,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, @@ -425,7 +424,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); } @@ -433,7 +432,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; @@ -441,7 +440,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) { @@ -458,17 +457,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/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 0f2f9717be0..0033074f0f4 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 @@ -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 0373aefbf8a..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 @@ -142,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 f564c26b304..13f60f31f03 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,21 @@ #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 { @@ -416,12 +417,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; @@ -435,6 +432,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)); @@ -451,7 +449,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()); @@ -461,10 +458,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(), @@ -543,7 +537,7 @@ 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 CGAL::Box_intersection_d::ID_FROM_BOX_ADDRESS Box_policy; typedef CGAL::Box_intersection_d::Box_with_info_d Box; @@ -551,14 +545,8 @@ compute_face_polyline_intersection( const FaceRange& face_range, // 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) { @@ -574,7 +562,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]), @@ -590,12 +577,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(), @@ -675,9 +657,7 @@ 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) )); @@ -688,22 +668,21 @@ compute_face_polylines_intersection(const FaceRange& face_range, // 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) { @@ -734,12 +713,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(), @@ -784,13 +758,8 @@ compute_polyline_polyline_intersection(const Polyline& polyline1, // 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) { @@ -819,10 +788,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(), @@ -879,6 +845,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) { @@ -886,9 +853,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) { @@ -923,15 +891,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(), @@ -1614,21 +1578,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; } @@ -1644,7 +1605,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()); } @@ -1837,9 +1798,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/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.h b/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/internal/validity.h index cdf8ce2de80..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 @@ -285,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); } From 16350e84a444815ab4bf33d478b57414e0618c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 17:12:44 +0100 Subject: [PATCH 37/61] Fix bad typedef --- .../include/CGAL/Box_intersection_d/Box_with_info_d.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 990f3dd5fbb..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 @@ -29,7 +29,7 @@ class Box_with_info_d protected: Info_ m_info; public: - typedef Box_d< NT_, N, ID_EXPLICIT> Base; + typedef Box_d< NT_, N, IdPolicy> Base; typedef NT_ NT; typedef Info_ Info; From 1e6b42d029b5ce96e9822533537a17f58bfbde0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 18:40:03 +0100 Subject: [PATCH 38/61] Add a split in 3 box_intersection_d parallel version --- .../include/CGAL/box_intersection_d.h | 84 ++++++++++++++++--- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index cdbf058fcb6..ff0698dd780 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -34,6 +34,7 @@ #include #include +#include namespace CGAL { namespace internal { @@ -64,27 +65,32 @@ void box_intersection_segment_tree_d( #else // CGAL_LINKED_WITH_TBB if(boost::is_convertible::value) { - typename std::iterator_traits::difference_type r1hs = std::distance(begin1, end1) / 2; - typename std::iterator_traits::difference_type r2hs = std::distance(begin2, end2) / 2; + unsigned thread_n = std::thread::hardware_concurrency(); + std::cout << thread_n << " threads" << std::endl; // TODO: Check which of the two following approaches is better // The first one makes three copies of the vector and performs four parallel tasks // The second one makes one copy, but must perform two times two parallel tasks (can't // do all four at the same time otherwise the sort / split will conflict) -#ifdef CGAL_BOX_INTER_FOUR_RANGES +#ifdef CGAL_BOX_INTER_ONE_SPLIT // cuts in 2 --> 2 copies of each vector, 9 pairs + std::cout << "Split in 2" << std::endl; + typedef typename std::iterator_traits::value_type val_t; + typename std::iterator_traits::difference_type r1_half = std::distance(begin1, end1) / 2; + typename std::iterator_traits::difference_type r2_half = std::distance(begin2, end2) / 2; + std::vector< val_t> r3( begin1, end1); std::vector< val_t> r4( begin2, end2); RandomAccessIter1 mid1 = begin1; - std::advance(mid1, r1hs); + std::advance(mid1, r1_half); RandomAccessIter2 mid2 = begin2; - std::advance(mid2, r2hs); + std::advance(mid2, r2_half); typename std::vector< val_t>::iterator mid3 = r3.begin(); - std::advance(mid3, r1hs); + std::advance(mid3, r1_half); typename std::vector< val_t>::iterator mid4 = r4.begin(); - std::advance(mid4, r2hs); + std::advance(mid4, r2_half); tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, callback, traits, cutoff, dim, in_order); }, @@ -94,11 +100,69 @@ void box_intersection_segment_tree_d( callback, traits, cutoff, dim, in_order); }, [&]{ Box_intersection_d::segment_tree( mid3, r3.end(), r4.begin(), mid4, inf, sup, callback, traits, cutoff, dim, in_order); } ); -#else // CGAL_BOX_INTER_FOUR_RANGES +#elif defined(CGAL_BOX_INTER_TWO_SPLIT) // cuts in 3 --> 3 copies of each vector, 9 pairs + std::cout << "Split in 3" << std::endl; + + typedef typename std::iterator_traits::value_type val_t; + typedef typename std::vector< val_t>::iterator It; + + typename std::iterator_traits::difference_type r1_third = std::distance(begin1, end1) / 3; + typename std::iterator_traits::difference_type r1_two_third = 2 * std::distance(begin1, end1) / 3; + typename std::iterator_traits::difference_type r2_third = std::distance(begin2, end2) / 3; + typename std::iterator_traits::difference_type r2_two_third = 2 * std::distance(begin2, end2) / 3; + + std::vector< val_t> r3( begin1, end1); + std::vector< val_t> r4( begin2, end2); + std::vector< val_t> r5( begin1, end1); + std::vector< val_t> r6( begin2, end2); + + RandomAccessIter1 r1_left = begin1; std::advance(r1_left, r1_third); + RandomAccessIter2 r2_left = begin2; std::advance(r2_left, r2_third); + It r3_left = r3.begin(); std::advance(r3_left, r1_third); + It r4_left = r4.begin(); std::advance(r4_left, r2_third); + It r5_left = r5.begin(); std::advance(r5_left, r1_third); + It r6_left = r6.begin(); std::advance(r6_left, r2_third); + + RandomAccessIter1 r1_right = begin1; std::advance(r1_right, r1_two_third); + RandomAccessIter2 r2_right = begin2; std::advance(r2_right, r2_two_third); + It r3_right = r3.begin(); std::advance(r3_right, r1_two_third); + It r4_right = r4.begin(); std::advance(r4_right, r2_two_third); + It r5_right = r5.begin(); std::advance(r5_right, r1_two_third); + It r6_right = r6.begin(); std::advance(r6_right, r2_two_third); + + tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, r1_left, begin2, r2_left, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r1_left, r1_right, r2_left, r2_right, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r1_right, end1, r2_right, end2, inf, sup, + callback, traits, cutoff, dim, in_order); }, + + // shifted 1 + [&]{ Box_intersection_d::segment_tree( r3.begin(), r3_left, r4_left, r4_right, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r3_left, r3_right, r4_right, r4.end(), inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r3_right, r3.end(), r4.begin(), r4_left, inf, sup, + callback, traits, cutoff, dim, in_order); }, + + // shifted 2 + [&]{ Box_intersection_d::segment_tree( r5.begin(), r5_left, r6_right, r6.end(), inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r5_left, r5_right, r6.begin(), r6_left, inf, sup, + callback, traits, cutoff, dim, in_order); }, + [&]{ Box_intersection_d::segment_tree( r5_right, r5.end(), r6_left, r6_right, inf, sup, + callback, traits, cutoff, dim, in_order); } ); + +#else + std::cout << "2x2" << std::endl; + + typename std::iterator_traits::difference_type r1_half = std::distance(begin1, end1) / 2; + typename std::iterator_traits::difference_type r2_half = std::distance(begin2, end2) / 2; + RandomAccessIter1 mid1 = begin1; - std::advance(mid1, r1hs); + std::advance(mid1, r1_half); RandomAccessIter2 mid2 = begin2; - std::advance(mid2, r2hs); + std::advance(mid2, r2_half); tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, callback, traits, cutoff, dim, in_order); }, From 47c0ce254ed408b71ebba92df1b907ded5f2c266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 19 Nov 2019 18:40:34 +0100 Subject: [PATCH 39/61] Enrich example --- .../self_intersections_example.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 1ce5501e5cb..a36a5003ae7 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 @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -24,14 +25,22 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } + CGAL::Real_timer timer; + timer.start(); + + std::cout << "Using parallel mode? " << std::is_same::value << std::endl; + 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::vector > intersected_tris; - PMP::self_intersections(faces(mesh), 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; + timer.stop(); + double t = timer.time(); + std::cout << "Time: " << t << std::endl; + return EXIT_SUCCESS; } From d302c56d056521af4a8bdccf0477504a799e062c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 2 Dec 2019 15:01:26 +0100 Subject: [PATCH 40/61] Keep a single version (3 split) of parallel box_intersection_d --- .../include/CGAL/box_intersection_d.h | 87 +++++-------------- 1 file changed, 23 insertions(+), 64 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index ff0698dd780..ca0683a0a67 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -34,7 +34,10 @@ #include #include -#include + +//////////////////////////////////////////////////////////////////////////////////////////////// +/// THE CALLBACK MUST BE THREADSAFE IF YOU ARE USING THE PARALLEL MODE +//////////////////////////////////////////////////////////////////////////////////////////////// namespace CGAL { namespace internal { @@ -65,51 +68,29 @@ void box_intersection_segment_tree_d( #else // CGAL_LINKED_WITH_TBB if(boost::is_convertible::value) { - unsigned thread_n = std::thread::hardware_concurrency(); - std::cout << thread_n << " threads" << std::endl; - - // TODO: Check which of the two following approaches is better - // The first one makes three copies of the vector and performs four parallel tasks - // The second one makes one copy, but must perform two times two parallel tasks (can't - // do all four at the same time otherwise the sort / split will conflict) -#ifdef CGAL_BOX_INTER_ONE_SPLIT // cuts in 2 --> 2 copies of each vector, 9 pairs - std::cout << "Split in 2" << std::endl; - - typedef typename std::iterator_traits::value_type val_t; - - typename std::iterator_traits::difference_type r1_half = std::distance(begin1, end1) / 2; - typename std::iterator_traits::difference_type r2_half = std::distance(begin2, end2) / 2; - - std::vector< val_t> r3( begin1, end1); - std::vector< val_t> r4( begin2, end2); - - RandomAccessIter1 mid1 = begin1; - std::advance(mid1, r1_half); - RandomAccessIter2 mid2 = begin2; - std::advance(mid2, r2_half); - typename std::vector< val_t>::iterator mid3 = r3.begin(); - std::advance(mid3, r1_half); - typename std::vector< val_t>::iterator mid4 = r4.begin(); - std::advance(mid4, r2_half); - - tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( mid1, end1, mid2, end2, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( r3.begin(), mid3, mid4, r4.end(), inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( mid3, r3.end(), r4.begin(), mid4, inf, sup, - callback, traits, cutoff, dim, in_order); } ); -#elif defined(CGAL_BOX_INTER_TWO_SPLIT) // cuts in 3 --> 3 copies of each vector, 9 pairs - std::cout << "Split in 3" << std::endl; - + // Below takes both box ranges and split each range in 3, and then does cross products + // to get all combinations (9 pairs). + // + // 3 is chosen such that we get 9 tasks in parallel, which is close to the usual number + // of threads (8-12) on a (current) "normal" machine. This could potentially be generalized + // by grabbing the number of available threads (n = std::thread::hardware_concurrency()) and + // splitting in 'i' and 'j' such that i*j=n. + // + // The memory footprint due to having to duplicate box ranges is empirically observed + // to be negligible (as long as a range of pointers is passed) + // typedef typename std::iterator_traits::value_type val_t; - typedef typename std::vector< val_t>::iterator It; + typedef typename std::vector< val_t>::iterator It; typename std::iterator_traits::difference_type r1_third = std::distance(begin1, end1) / 3; - typename std::iterator_traits::difference_type r1_two_third = 2 * std::distance(begin1, end1) / 3; + typename std::iterator_traits::difference_type r1_two_third = 2 * r1_third; typename std::iterator_traits::difference_type r2_third = std::distance(begin2, end2) / 3; - typename std::iterator_traits::difference_type r2_two_third = 2 * std::distance(begin2, end2) / 3; + typename std::iterator_traits::difference_type r2_two_third = 2 * r2_third; + + CGAL_assertion(0 <= r1_third && r1_third <= r1_two_third && + (r1_two_third < std::distance(begin1, end1) || std::distance(begin1, end1) == 0)); + CGAL_assertion(0 <= r2_third && r2_third <= r2_two_third && + (r2_two_third < std::distance(begin2, end2) || std::distance(begin2, end2) == 0)); std::vector< val_t> r3( begin1, end1); std::vector< val_t> r4( begin2, end2); @@ -152,28 +133,6 @@ void box_intersection_segment_tree_d( callback, traits, cutoff, dim, in_order); }, [&]{ Box_intersection_d::segment_tree( r5_right, r5.end(), r6_left, r6_right, inf, sup, callback, traits, cutoff, dim, in_order); } ); - -#else - std::cout << "2x2" << std::endl; - - typename std::iterator_traits::difference_type r1_half = std::distance(begin1, end1) / 2; - typename std::iterator_traits::difference_type r2_half = std::distance(begin2, end2) / 2; - - RandomAccessIter1 mid1 = begin1; - std::advance(mid1, r1_half); - RandomAccessIter2 mid2 = begin2; - std::advance(mid2, r2_half); - - tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, begin2, mid2, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( mid1, end1, mid2, end2, inf, sup, - callback, traits, cutoff, dim, in_order); } ); - tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, mid1, mid2, end2, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( mid1, end1, begin2, mid2, inf, sup, - callback, traits, cutoff, dim, in_order); } ); - -#endif // CGAL_BOX_INTER_FOUR_RANGES } else #endif // CGAL_LINKED_WITH_TBB From 82bf0f22f17e451182424cb575f92b9a48946fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 2 Dec 2019 15:01:50 +0100 Subject: [PATCH 41/61] Test parallel box_intersection_d and ptr-based box_intersection_d --- .../test/Box_intersection_d/CMakeLists.txt | 19 +- .../test/Box_intersection_d/test_box_grid.cpp | 426 +++++++++++------- 2 files changed, 264 insertions(+), 181 deletions(-) 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; } From 0191d868fa61eaae0e6c5461a34eff7b9825ce87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Mon, 2 Dec 2019 16:39:58 +0100 Subject: [PATCH 42/61] Simplify and clean parallel code for PMP::self_intersections --- .../self_intersections.h | 522 +++++++----------- 1 file changed, 210 insertions(+), 312 deletions(-) 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 526f143235e..7d9e84da942 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,76 +21,163 @@ #include -#include -#include -#include - -#ifdef CGAL_PMP_SI_DEBUG -#include -#endif - -#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 + #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 +// 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; + + 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); + + halfedge_descriptor opp_h; + + // check for shared edge + for(unsigned int i=0; i<3; ++i) + { + 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; + } + } + + 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 + Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); + Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); + + Segment s1 = construct_segment(get(vpmap, hv[(i+1)%3]), get(vpmap, hv[(i+2)%3]) ); + 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 + Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); + Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); + if(do_intersect(t1, t2)) + return true; + + return false; +}; + +template struct Intersect_facets { -// typedefs - typedef typename Kernel::Segment_3 Segment; - typedef typename Kernel::Triangle_3 Triangle; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_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; + 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) + Intersect_facets(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) : - m_tmesh(tmesh), - m_vpmap(vpmap), - m_iterator(it), - 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 @@ -98,272 +185,82 @@ struct Intersect_facets halfedge_descriptor h = halfedge(b->info(), m_tmesh); halfedge_descriptor g = halfedge(c->info(), m_tmesh); - vertex_descriptor hv[3], gv[3]; - hv[0] = target(h, m_tmesh); - hv[1] = target(next(h, m_tmesh), m_tmesh); - hv[2] = source(h, m_tmesh); - - gv[0] = target(g, m_tmesh); - gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - - halfedge_descriptor opp_h; - - // 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 - get(m_vpmap, hv[i]); - get(m_vpmap, hv[(i + 1) % 3]); - get(m_vpmap, hv[(i + 2) % 3]); - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); - - if(CGAL::coplanar(get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && - CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) - == CGAL::POSITIVE){ - *m_iterator++ = 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 v; - - 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 - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - - Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]) ); - Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), - get(m_vpmap, gv[(j+2)%3])); - - if(do_intersect_3_functor(t1,s2)){ - *m_iterator++ = std::make_pair(b->info(), c->info()); - } else if(do_intersect_3_functor(t2,s1)){ - *m_iterator++ = std::make_pair(b->info(), c->info()); - } - return; - } - - // check for geometric intersection - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - if(do_intersect_3_functor(t1, t2)){ + 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()); - } - } // end operator () -}; // end struct Intersect_facets + } +}; - #ifdef CGAL_LINKED_WITH_TBB -//TODO: use the same code for the linear pass? -// The functor for doing all geometric tests in parallel -template -struct AllPairs +// The functor doing all geometric tests in parallel +template +struct Concurrent_face_intersection_tester { -// types - typedef typename Kernel::Segment_3 Segment; - typedef typename Kernel::Triangle_3 Triangle; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; -// data members const TM& m_tmesh; - const VertexPointMap m_vpmap; - const FacePairs& face_pairs; - std::vector& dointersect; - typename Kernel::Construct_segment_3 segment_functor; - typename Kernel::Construct_triangle_3 triangle_functor; - typename Kernel::Do_intersect_3 do_intersect_3_functor; + const VPM m_vpmap; + const FacePairs& m_face_pairs; + DoIntersectVector& m_do_intersect_vector; + typename GT::Construct_segment_3 m_construct_segment; + typename GT::Construct_triangle_3 m_construct_triangle; + typename GT::Do_intersect_3 m_do_intersect; - - AllPairs(const FacePairs& face_pairs, - std::vector& dointersect, - const TM& tmesh, VertexPointMap vpmap, const Kernel& kernel) - : m_tmesh(tmesh), + Concurrent_face_intersection_tester(const FacePairs& face_pairs, + DoIntersectVector& do_intersect_vector, + const TM& tmesh, + VPM vpmap, + const GT& gt) + : + m_tmesh(tmesh), m_vpmap(vpmap), - face_pairs(face_pairs), - dointersect(dointersect), - triangle_functor(kernel.construct_triangle_3_object()), - do_intersect_3_functor(kernel.do_intersect_3_object()) + m_face_pairs(face_pairs), + m_do_intersect_vector(do_intersect_vector), + 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 tbb::blocked_range &r) const { - for (std::size_t ri = r.begin(); ri != r.end(); ++ri) { + for(std::size_t ri = r.begin(); ri != r.end(); ++ri) this->operator()(ri); - } } void operator()(std::size_t ri) const { - const std::pair& ff = face_pairs[ri]; + const std::pair& ff = m_face_pairs[ri]; halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); - vertex_descriptor hv[3], gv[3]; - hv[0] = target(h, m_tmesh); - hv[1] = target(next(h, m_tmesh), m_tmesh); - hv[2] = source(h, m_tmesh); - - gv[0] = target(g, m_tmesh); - gv[1] = target(next(g, m_tmesh), m_tmesh); - gv[2] = source(g, m_tmesh); - - halfedge_descriptor opp_h; - - // check for shared egde - for(unsigned int i=0; i<3; ++i){ - opp_h = opposite(h, m_tmesh); - if(face(opp_h, m_tmesh) == ff.second){ - // there is an intersection if the four points are coplanar and - // the triangles overlap - get(m_vpmap, hv[i]); - get(m_vpmap, hv[(i + 1) % 3]); - get(m_vpmap, hv[(i + 2) % 3]); - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh)); - - if(CGAL::coplanar(get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) && - CGAL::coplanar_orientation(get(m_vpmap, hv[(i+2)%3]), - get(m_vpmap, hv[i]), - get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, target(next(opp_h, m_tmesh), m_tmesh))) - == CGAL::POSITIVE){ - dointersect[ri]=true; - 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 v; - - 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 - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - - Segment s1 = segment_functor( get(m_vpmap, hv[(i+1)%3]), - get(m_vpmap, hv[(i+2)%3]) ); - Segment s2 = segment_functor( get(m_vpmap, gv[(j+1)%3]), - get(m_vpmap, gv[(j+2)%3])); - - dointersect[ri] = (do_intersect_3_functor(t1, s2)) || do_intersect_3_functor(t2, s1); - return; - } - - // check for geometric intersection - Triangle t1 = triangle_functor( get(m_vpmap, hv[0]), - get(m_vpmap, hv[1]), - get(m_vpmap, hv[2])); - Triangle t2 = triangle_functor( get(m_vpmap, gv[0]), - get(m_vpmap, gv[1]), - get(m_vpmap, gv[2])); - dointersect[ri] = do_intersect_3_functor(t1, t2); + if(do_faces_intersect(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect)) + m_do_intersect_vector[ri] = true; } }; - -// The functor that filters nothing +// This filter does not filter anything, but simply forwards intersecting pair information so that +// filtering can be done outside of the call to 'box_intersection_d' template struct All_faces_filter { - mutable OutputIterator m_iterator; - - All_faces_filter(OutputIterator it) : m_iterator(it) {} + All_faces_filter(OutputIterator it) : m_iterator(it) { } template - void operator()(const Box* b, const Box* c) const - { - *m_iterator ++ = std::make_pair(b->info(), c->info()); - } + void operator()(const Box* b, const Box* c) const { *m_iterator++ = std::make_pair(b->info(), c->info()); } + + mutable OutputIterator m_iterator; }; - - #endif -struct Throw_at_output { - class Throw_at_output_exception: public std::exception - { }; +struct Throw_at_output +{ + class Throw_at_output_exception: public std::exception { }; template - void operator()(const T& /* t */) const { - throw Throw_at_output_exception(); - } + void operator()(const T& /* t */) const { throw Throw_at_output_exception(); } }; -}// namespace internal - -namespace Polygon_mesh_processing { +} // namespace internal /*! * \ingroup PMP_intersection_grp @@ -403,7 +300,7 @@ template < class ConcurrencyTag = Sequential_tag, class OutputIterator, class NamedParameters> OutputIterator -self_intersections( const FaceRange& face_range, +self_intersections(const FaceRange& face_range, const TriangleMesh& tmesh, OutputIterator out, const NamedParameters& np) @@ -416,25 +313,25 @@ self_intersections( const FaceRange& face_range, 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 GeomTraits; - GeomTraits gt = parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GeomTraits()); + typedef typename GetGeomTraits::type GT; + GT gt = parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GT()); - 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)); + typedef typename GetVertexPointMap::const_type VPM; + VPM vpmap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, tmesh)); // make one box per face std::vector boxes; - boxes.reserve(std::distance(boost::begin(face_range), boost::end(face_range))); + boxes.reserve(std::distance(std::begin(face_range), std::end(face_range))); for(face_descriptor f : face_range) { - typename boost::property_traits::reference + 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) ) + if(collinear(p, q, r) ) *out++= std::make_pair(f,f); else boxes.push_back(Box(p.bbox() + q.bbox() + r.bbox(), f)); @@ -448,40 +345,43 @@ self_intersections( const FaceRange& face_range, box_ptr.push_back(&b); #if !defined(CGAL_LINKED_WITH_TBB) - CGAL_static_assertion_msg (!(boost::is_convertible::value), + CGAL_static_assertion_msg (!(std::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else - if (boost::is_convertible::value) + if(std::is_convertible::value) { - // (Parallel version of the code) - // (A) Sequentially write all pairs of faces with intersecting bbox into a std::vector + // (A) Parallel: Write all pairs of faces with intersecting bbox std::ptrdiff_t cutoff = 2000; - typedef tbb::concurrent_vector >FacePairs; + typedef tbb::concurrent_vector > Face_pairs; + typedef std::back_insert_iterator Face_pairs_back_inserter; - typedef std::back_insert_iterator FacePairsI; - FacePairs face_pairs; - CGAL::internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); + Face_pairs face_pairs; + internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), all_faces_filter, cutoff); - // (B) Parallel: perform the geometric tests - std::vector dointersect(face_pairs.size(), 0); - CGAL::internal::AllPairs all_pairs(face_pairs, dointersect, tmesh, vpmap, gt); + // (B) Parallel: Perform the geometric tests + typedef std::vector Do_intersect_vector; + typedef internal::Concurrent_face_intersection_tester Tester; - tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), all_pairs); + Do_intersect_vector do_intersect(face_pairs.size(), 0); + Tester tester(face_pairs, do_intersect, tmesh, vpmap, gt); + tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), tester); // (C) Sequentially: Copy from the concurent container to the output iterator - for(std::size_t i=0; i < dointersect.size(); ++i){ - if(dointersect[i]) + for(std::size_t i=0; i - intersect_facets(tmesh, out, vpmap, gt); + // Sequential version of the code + // Compute self-intersections filtered out by boxes + typedef internal::Intersect_facets Intersecting_facet_filter; + Intersecting_facet_filter intersect_facets(tmesh, vpmap, gt, out); std::ptrdiff_t cutoff = 2000; CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets, cutoff); @@ -502,7 +402,6 @@ self_intersections(const FaceRange& face_range, } /// \endcond - /** * \ingroup PMP_intersection_grp * collects intersections between all the faces of a triangulated surface mesh. @@ -590,10 +489,10 @@ bool does_self_intersect(const TriangleMesh& tmesh, try { - typedef boost::function_output_iterator OutputIterator; + typedef boost::function_output_iterator OutputIterator; self_intersections(tmesh, OutputIterator(), np); } - catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) + catch(internal::Throw_at_output::Throw_at_output_exception& ) { return true; } return false; @@ -636,10 +535,10 @@ bool does_self_intersect(const FaceRange& face_range, try { - typedef boost::function_output_iterator OutputIterator; + typedef boost::function_output_iterator OutputIterator; self_intersections(face_range, tmesh, OutputIterator(), np); } - catch( CGAL::internal::Throw_at_output::Throw_at_output_exception& ) + catch(internal::Throw_at_output::Throw_at_output_exception& ) { return true; } return false; @@ -660,8 +559,7 @@ bool does_self_intersect(const FaceRange& face_range, } /// \endcond -}// end namespace Polygon_mesh_processing - +}// namespace Polygon_mesh_processing }// namespace CGAL #include From a1adb5fc947f6a4bbb5b26799b6e9af02a8883e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 10:10:34 +0100 Subject: [PATCH 43/61] Use correct parallel tags in the example --- .../self_intersections_example.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) 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 a36a5003ae7..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 @@ -1,10 +1,11 @@ #include #include -#include #include +#include #include +#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; @@ -25,22 +26,22 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; } + std::cout << "Using parallel mode? " << std::is_same::value << std::endl; + CGAL::Real_timer timer; timer.start(); - std::cout << "Using parallel mode? " << std::is_same::value << std::endl; - - bool intersecting = PMP::does_self_intersect( - mesh, CGAL::parameters::vertex_point_map(get(CGAL::vertex_point, mesh))); + 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(faces(mesh), 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; - timer.stop(); - double t = timer.time(); - std::cout << "Time: " << t << std::endl; + std::cout << "Elapsed time (self intersections): " << timer.time() << std::endl; return EXIT_SUCCESS; } From c0921a5e530e92baaebd75ac63506d114f937fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 12:00:31 +0100 Subject: [PATCH 44/61] Fix collecting all intersecting pairs before throwing + fix NP improper forward --- .../self_intersections.h | 291 ++++++++++-------- 1 file changed, 158 insertions(+), 133 deletions(-) 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 7d9e84da942..935e0314b7b 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 @@ -31,9 +31,6 @@ #include #include -#include -#include - #ifdef CGAL_LINKED_WITH_TBB #include #include @@ -252,61 +249,27 @@ struct All_faces_filter }; #endif -struct Throw_at_output -{ - class Throw_at_output_exception: public std::exception { }; +class Throw_at_output_exception + : public std::exception +{ }; - template - void operator()(const T& /* t */) const { throw Throw_at_output_exception(); } -}; - -} // 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 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 < class ConcurrencyTag = Sequential_tag, - class TriangleMesh, - class FaceRange, - class OutputIterator, - class NamedParameters> -OutputIterator -self_intersections(const FaceRange& face_range, - const TriangleMesh& tmesh, - OutputIterator out, - const NamedParameters& np) +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)); + using CGAL::parameters::choose_parameter; + using CGAL::parameters::get_parameter; + typedef TriangleMesh TM; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -314,11 +277,13 @@ self_intersections(const FaceRange& face_range, typedef CGAL::Box_intersection_d::Box_with_info_d Box; typedef typename GetGeomTraits::type GT; - GT gt = parameters::choose_parameter(parameters::get_parameter(np, internal_np::geom_traits), GT()); + GT gt = choose_parameter(get_parameter(np, internal_np::geom_traits), GT()); typedef typename GetVertexPointMap::const_type VPM; - VPM vpmap = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point), - get_const_property_map(boost::vertex_point, tmesh)); + VPM vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_const_property_map(boost::vertex_point, tmesh)); + + const std::ptrdiff_t cutoff = 2000; // make one box per face std::vector boxes; @@ -331,10 +296,19 @@ self_intersections(const FaceRange& face_range, 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); + // 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 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 @@ -344,6 +318,9 @@ self_intersections(const FaceRange& face_range, for(Box& b : boxes) box_ptr.push_back(&b); + // In case we are throwing, like in `does_self_intersect()` + auto throwing_callback = [] (const Box*, const Box*) { throw internal::Throw_at_output_exception(); }; + #if !defined(CGAL_LINKED_WITH_TBB) CGAL_static_assertion_msg (!(std::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); @@ -351,14 +328,16 @@ self_intersections(const FaceRange& face_range, if(std::is_convertible::value) { // (A) Parallel: Write all pairs of faces with intersecting bbox - std::ptrdiff_t cutoff = 2000; - typedef tbb::concurrent_vector > Face_pairs; typedef std::back_insert_iterator Face_pairs_back_inserter; Face_pairs face_pairs; internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), all_faces_filter, cutoff); + + if(throw_on_SI) + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_callback, cutoff); + else + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), all_faces_filter, cutoff); // (B) Parallel: Perform the geometric tests typedef std::vector Do_intersect_vector; @@ -380,23 +359,72 @@ self_intersections(const FaceRange& face_range, #endif // Sequential version of the code // Compute self-intersections filtered out by boxes - typedef internal::Intersect_facets Intersecting_facet_filter; + typedef internal::Intersect_facets Intersecting_facet_filter; Intersecting_facet_filter intersect_facets(tmesh, vpmap, gt, out); - std::ptrdiff_t cutoff = 2000; - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(),intersect_facets, cutoff); + if(throw_on_SI) + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_callback, cutoff); + else + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), intersect_facets, cutoff); + return intersect_facets.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 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 < 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 -OutputIterator + class FacePairOutputIterator> +FacePairOutputIterator self_intersections(const FaceRange& face_range, const TriangleMesh& tmesh, - OutputIterator out) + FacePairOutputIterator out) { return self_intersections(face_range, tmesh, out, CGAL::parameters::all_default()); } @@ -415,7 +443,7 @@ self_intersections(const FaceRange& face_range, * @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 `FacePairOutputIterator` holding objects of type * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` * @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters" * @@ -437,25 +465,78 @@ self_intersections(const FaceRange& face_range, */ template -OutputIterator +FacePairOutputIterator self_intersections(const TriangleMesh& tmesh, - OutputIterator out, + FacePairOutputIterator out, const CGAL_PMP_NP_CLASS& 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(faces(tmesh), tmesh, out, parameters::all_default()); } /// \endcond +/** + * \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" + * + * @param face_range the set of faces to test for self-intersection + * @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 `SelfIntersectionTraits` \cgalParamEnd + * \cgalNamedParamsEnd + * + * @warning The parallel version of the algorithm has a small overhead as the range of faces + * is duplicated to allow concurrent work. Consequently, if the mesh has a large number + * of self-intersections, the sequential version of the algorithm might be faster. + * + * + * @return `true` if the faces in `face_range` self-intersect + */ +template +bool does_self_intersect(const FaceRange& face_range, + const TriangleMesh& tmesh, + const NamedParameters& np) +{ + CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); + + try + { + CGAL::Emptyset_iterator unused_out; + internal::self_intersections_impl(face_range, tmesh, unused_out, true /*throw*/, np); + } + catch(internal::Throw_at_output_exception&) + { + return true; + } + + return false; +} + /** * \ingroup PMP_intersection_grp * tests if a triangulated surface mesh self-intersects. @@ -485,70 +566,14 @@ template OutputIterator; - self_intersections(tmesh, OutputIterator(), np); - } - catch(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" - * - * @param face_range the set of faces to test for self-intersection - * @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 `SelfIntersectionTraits` \cgalParamEnd - * \cgalNamedParamsEnd - * - * @return `true` if the faces in `face_range` self-intersect - */ -template -bool does_self_intersect(const FaceRange& face_range, - const TriangleMesh& tmesh, - const NamedParameters& np) -{ - CGAL_precondition(CGAL::is_triangle_mesh(tmesh)); - - try - { - typedef boost::function_output_iterator OutputIterator; - self_intersections(face_range, tmesh, OutputIterator(), np); - } - catch(internal::Throw_at_output::Throw_at_output_exception& ) - { return true; } - - return false; + return does_self_intersect(faces(tmesh), tmesh, np); } /// \cond SKIP_IN_MANUAL template bool does_self_intersect(const TriangleMesh& tmesh) { - return does_self_intersect(tmesh, CGAL::parameters::all_default()); + return does_self_intersect(faces(tmesh), tmesh, CGAL::parameters::all_default()); } template From cbf78b3de16206d2a77754db333c691de7206777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 12:11:19 +0100 Subject: [PATCH 45/61] Minor doc / comment changes --- .../CGAL/Polygon_mesh_processing/self_intersections.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 935e0314b7b..c0abe0e8d84 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 @@ -289,6 +289,7 @@ self_intersections_impl(const FaceRange& face_range, 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) { typename boost::property_traits::reference @@ -347,7 +348,7 @@ self_intersections_impl(const FaceRange& face_range, Tester tester(face_pairs, do_intersect, tmesh, vpmap, gt); tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), tester); - // (C) Sequentially: Copy from the concurent container to the output iterator + // (C) Sequential: Copy from the concurent container to the output iterator for(std::size_t i=0; i Date: Wed, 20 Nov 2019 11:42:47 +0100 Subject: [PATCH 46/61] Document the new type --- STL_Extension/doc/STL_Extension/CGAL/tags.h | 11 +++++++++-- .../doc/STL_Extension/PackageDescription.txt | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/STL_Extension/doc/STL_Extension/CGAL/tags.h b/STL_Extension/doc/STL_Extension/CGAL/tags.h index 5e102c1d8ca..9a54c36a4fe 100644 --- a/STL_Extension/doc/STL_Extension/CGAL/tags.h +++ b/STL_Extension/doc/STL_Extension/CGAL/tags.h @@ -69,18 +69,25 @@ struct Null_functor { /*! \ingroup PkgSTLExtensionUtilities -Tag used to enable/disable concurrency. +Tag used to disable concurrency. For example, it may be used by a user to request the sequential version of an algorithm. */ struct Sequential_tag {}; /*! \ingroup PkgSTLExtensionUtilities -Tag used to enable/disable concurrency. +Tag used to enable concurrency. For example, it may be used by a user to request the parallel version of an algorithm. */ struct Parallel_tag {}; +/*! +\ingroup PkgSTLExtensionUtilities +This tag is a convenience typedef to `Parallel_tag` if the third party library \ref thirdpartyTBB +has been found and linked, and to `Sequential_tag` otherwise. +*/ +struct Parallel_if_available_tag {}; + /*! \ingroup PkgSTLExtensionUtilities diff --git a/STL_Extension/doc/STL_Extension/PackageDescription.txt b/STL_Extension/doc/STL_Extension/PackageDescription.txt index df921c5c6e0..4372a8f37d3 100644 --- a/STL_Extension/doc/STL_Extension/PackageDescription.txt +++ b/STL_Extension/doc/STL_Extension/PackageDescription.txt @@ -109,6 +109,9 @@ - `CGAL::Tag_false` - `CGAL::Null_tag` - `CGAL::Null_functor` +- `CGAL::Sequential_tag` +- `CGAL::Parallel_tag` +- `CGAL::Parallel_if_available_tag` - `CGAL::Uncertain` - `CGAL::Default` - `CGAL::Fast` From b93e556ff31afdc7a9ed59a8879e05f26be73934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 14:20:24 +0100 Subject: [PATCH 47/61] Document the parallel version of the box_intersection_d --- .../CGAL/box_intersection_d.h | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) 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..4a7840e47a2 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,27 @@ 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. + + \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 +295,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 +313,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 +512,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 +546,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 +559,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, From 6bd31f593e3b8ac89677b854a5d681167e083420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 14:30:11 +0100 Subject: [PATCH 48/61] Minor doc fix --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c0abe0e8d84..2a69d29b960 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 @@ -387,7 +387,7 @@ self_intersections_impl(const FaceRange& face_range, * 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 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" * @@ -444,7 +444,7 @@ self_intersections(const FaceRange& face_range, * @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 FacePairOutputIterator a model of `FacePairOutputIterator` 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" * From 47585d85b5bd5b20b80a827ec6678953e89b136a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 16:12:49 +0100 Subject: [PATCH 49/61] Add an additional comment in the doc about parallel box_intersection_d --- .../doc/Box_intersection_d/CGAL/box_intersection_d.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 4a7840e47a2..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 @@ -250,7 +250,9 @@ void box_intersection_all_pairs_d( 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. + 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 From c526d40b4438b6c959e84b439bc011cf1df90e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 16:17:53 +0100 Subject: [PATCH 50/61] Fix throwing as soon as boxes intersect and not checking for actual intersection --- .../self_intersections.h | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) 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 2a69d29b960..f6ca79f207d 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 @@ -37,6 +37,8 @@ #include #endif +#include + #include #include #include @@ -156,7 +158,7 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, template -struct Intersect_facets +struct Intersect_faces { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -167,7 +169,7 @@ struct Intersect_facets typename GT::Construct_triangle_3 m_construct_triangle; typename GT::Do_intersect_3 m_do_intersect; - Intersect_facets(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) + Intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) : m_iterator(it), m_tmesh(tmesh), @@ -253,6 +255,12 @@ class Throw_at_output_exception : public std::exception { }; +struct Throw_at_output +{ + template + void operator()(const T&) const { throw Throw_at_output_exception(); } +}; + template Throwing_output_iterator; + typedef internal::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), @@ -336,7 +349,7 @@ self_intersections_impl(const FaceRange& face_range, internal::All_faces_filter all_faces_filter(std::back_inserter(face_pairs)); if(throw_on_SI) - CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), throwing_callback, cutoff); + 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(), all_faces_filter, cutoff); @@ -360,15 +373,15 @@ self_intersections_impl(const FaceRange& face_range, #endif // Sequential version of the code // Compute self-intersections filtered out by boxes - typedef internal::Intersect_facets Intersecting_facet_filter; - Intersecting_facet_filter intersect_facets(tmesh, vpmap, gt, out); + typedef internal::Intersect_faces 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_callback, cutoff); + 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_facets, cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), intersect_faces, cutoff); - return intersect_facets.m_iterator; + return intersect_faces.m_iterator; } } // namespace internal From e9e3d9b5b0242e82cf59911681c3c68df3bfcf92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 16:23:35 +0100 Subject: [PATCH 51/61] Add missing includes --- .../include/CGAL/Polygon_mesh_processing/intersection.h | 6 ++++++ .../CGAL/Polygon_mesh_processing/self_intersections.h | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) 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 13f60f31f03..f46e8ccd821 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/intersection.h @@ -28,10 +28,16 @@ #include #include +#include #include #include #include +#include +#include +#include +#include + namespace CGAL { namespace Polygon_mesh_processing{ namespace internal { 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 f6ca79f207d..a18fde6c068 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 @@ -28,8 +28,9 @@ #include #include #include -#include #include +#include +#include #ifdef CGAL_LINKED_WITH_TBB #include From b210bf3f08dcccbd2d1b29ff075fde95a27705a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Tue, 3 Dec 2019 19:56:00 +0100 Subject: [PATCH 52/61] Fix conflict in struct names --- .../CGAL/Polygon_mesh_processing/self_intersections.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 a18fde6c068..8e239bc077f 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 @@ -159,7 +159,7 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, template -struct Intersect_faces +struct Strict_intersect_faces // meaning, not just a shared subface { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -170,7 +170,7 @@ struct Intersect_faces typename GT::Construct_triangle_3 m_construct_triangle; typename GT::Do_intersect_3 m_do_intersect; - Intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) + Strict_intersect_faces(const TM& tmesh, VPM vpmap, const GT& gt, OutputIterator it) : m_iterator(it), m_tmesh(tmesh), @@ -333,7 +333,7 @@ self_intersections_impl(const FaceRange& face_range, // 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::Intersect_faces Throwing_filter; + typedef internal::Strict_intersect_faces Throwing_filter; Throwing_filter throwing_filter(tmesh, vpmap, gt, Throwing_output_iterator()); #if !defined(CGAL_LINKED_WITH_TBB) @@ -374,7 +374,7 @@ self_intersections_impl(const FaceRange& face_range, #endif // Sequential version of the code // Compute self-intersections filtered out by boxes - typedef internal::Intersect_faces Intersecting_faces_filter; + typedef internal::Strict_intersect_faces Intersecting_faces_filter; Intersecting_faces_filter intersect_faces(tmesh, vpmap, gt, out); if(throw_on_SI) From 57fed1416a2fae663da3cab1a30fc49ef73d53d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 4 Dec 2019 09:10:49 +0100 Subject: [PATCH 53/61] Factorize code creating throwing output iterators --- .../self_intersections.h | 17 ++++------------- .../Polyhedron/Plugins/IO/OFF_io_plugin.cpp | 7 +++++-- .../demo/Polyhedron/Scene_surface_mesh_item.cpp | 3 ++- STL_Extension/include/CGAL/exceptions.h | 12 ++++++++++++ 4 files changed, 23 insertions(+), 16 deletions(-) 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 8e239bc077f..c160ccf99e5 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 @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CGAL_LINKED_WITH_TBB #include @@ -252,16 +253,6 @@ struct All_faces_filter }; #endif -class Throw_at_output_exception - : public std::exception -{ }; - -struct Throw_at_output -{ - template - void operator()(const T&) const { throw Throw_at_output_exception(); } -}; - template Throwing_output_iterator; + 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()); @@ -539,7 +530,7 @@ bool does_self_intersect(const FaceRange& face_range, CGAL::Emptyset_iterator unused_out; internal::self_intersections_impl(face_range, tmesh, unused_out, true /*throw*/, np); } - catch(internal::Throw_at_output_exception&) + catch(CGAL::internal::Throw_at_output_exception&) { return true; } 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_surface_mesh_item.cpp b/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp index 88365d2667d..021bbf46a7f 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 @@ -1578,7 +1579,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; } 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 From 5fdeb063261f825b86334fce38ecee335e49306a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 11 Dec 2019 09:36:27 +0100 Subject: [PATCH 54/61] Generalize box_d 'divide and conquer' approach to any given integer --- .../include/CGAL/box_intersection_d.h | 172 ++++++++++++------ 1 file changed, 117 insertions(+), 55 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index ca0683a0a67..fb70c7ad6c2 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -29,7 +29,7 @@ #include #ifdef CGAL_LINKED_WITH_TBB -#include +#include #endif #include @@ -68,71 +68,133 @@ void box_intersection_segment_tree_d( #else // CGAL_LINKED_WITH_TBB if(boost::is_convertible::value) { - // Below takes both box ranges and split each range in 3, and then does cross products - // to get all combinations (9 pairs). + // Here is an illustration for n=2. // - // 3 is chosen such that we get 9 tasks in parallel, which is close to the usual number - // of threads (8-12) on a (current) "normal" machine. This could potentially be generalized - // by grabbing the number of available threads (n = std::thread::hardware_concurrency()) and - // splitting in 'i' and 'j' such that i*j=n. + // 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] // - // The memory footprint due to having to duplicate box ranges is empirically observed - // to be negligible (as long as a range of pointers is passed) + // 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] // - typedef typename std::iterator_traits::value_type val_t; - typedef typename std::vector< val_t>::iterator It; + // Ranges must be duplicates since sorting is performed - typename std::iterator_traits::difference_type r1_third = std::distance(begin1, end1) / 3; - typename std::iterator_traits::difference_type r1_two_third = 2 * r1_third; - typename std::iterator_traits::difference_type r2_third = std::distance(begin2, end2) / 3; - typename std::iterator_traits::difference_type r2_two_third = 2 * r2_third; + typedef typename std::iterator_traits::value_type val_t; + typedef typename std::iterator_traits::difference_type diff_size; - CGAL_assertion(0 <= r1_third && r1_third <= r1_two_third && - (r1_two_third < std::distance(begin1, end1) || std::distance(begin1, end1) == 0)); - CGAL_assertion(0 <= r2_third && r2_third <= r2_two_third && - (r2_two_third < std::distance(begin2, end2) || std::distance(begin2, end2) == 0)); + typedef std::vector val_container; + typedef typename val_container::iterator It; - std::vector< val_t> r3( begin1, end1); - std::vector< val_t> r4( begin2, end2); - std::vector< val_t> r5( begin1, end1); - std::vector< val_t> r6( begin2, end2); + static constexpr int n = 4; - RandomAccessIter1 r1_left = begin1; std::advance(r1_left, r1_third); - RandomAccessIter2 r2_left = begin2; std::advance(r2_left, r2_third); - It r3_left = r3.begin(); std::advance(r3_left, r1_third); - It r4_left = r4.begin(); std::advance(r4_left, r2_third); - It r5_left = r5.begin(); std::advance(r5_left, r1_third); - It r6_left = r6.begin(); std::advance(r6_left, r2_third); + const diff_size r1s = std::distance(begin1, end1); + const diff_size r2s = std::distance(begin2, end2); - RandomAccessIter1 r1_right = begin1; std::advance(r1_right, r1_two_third); - RandomAccessIter2 r2_right = begin2; std::advance(r2_right, r2_two_third); - It r3_right = r3.begin(); std::advance(r3_right, r1_two_third); - It r4_right = r4.begin(); std::advance(r4_right, r2_two_third); - It r5_right = r5.begin(); std::advance(r5_right, r1_two_third); - It r6_right = r6.begin(); std::advance(r6_right, r2_two_third); + val_container range_1_copies, range_2_copies; + range_1_copies.reserve(r1s * n); + range_2_copies.reserve(r2s * n); - tbb::parallel_invoke([&]{ Box_intersection_d::segment_tree( begin1, r1_left, begin2, r2_left, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( r1_left, r1_right, r2_left, r2_right, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( r1_right, end1, r2_right, end2, inf, sup, - callback, traits, cutoff, dim, in_order); }, + const diff_size r1_step = r1s / n; + const diff_size r2_step = r2s / n; - // shifted 1 - [&]{ Box_intersection_d::segment_tree( r3.begin(), r3_left, r4_left, r4_right, inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( r3_left, r3_right, r4_right, r4.end(), inf, sup, - callback, traits, cutoff, dim, in_order); }, - [&]{ Box_intersection_d::segment_tree( r3_right, r3.end(), r4.begin(), r4_left, inf, sup, - callback, traits, cutoff, dim, in_order); }, + for(int i=0; i, n> range_1_iterators; + std::array, n> range_2_iterators; + + for(int i=0; i Date: Wed, 11 Dec 2019 09:52:52 +0100 Subject: [PATCH 55/61] Reintegrate the callback within the call to box_intersection_d() This is motivated by the fact that if you have a configuration where there is a large number of boxes intersection (such as k*n^2, with n being the number of faces), then the size of the concurrent container can be very large and thus the memory footprint would be huge. Instead, since the box_intersection_d call is now parallel, we can just do callbacks in the tree directly. The only thing is, we want to have these (heavy) callback calls to be roughly balanced. For this, we random shuffle the range of faces. Same runtime as before, no more huge memory footprint! --- .../self_intersections.h | 103 ++++-------------- 1 file changed, 20 insertions(+), 83 deletions(-) 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 c160ccf99e5..5a00000fbc1 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 @@ -24,14 +24,16 @@ #include #include +#include #include #include #include #include -#include +#include #include #include -#include +#include +#include #ifdef CGAL_LINKED_WITH_TBB #include @@ -191,68 +193,6 @@ struct Strict_intersect_faces // meaning, not just a shared subface } }; -#ifdef CGAL_LINKED_WITH_TBB -// The functor doing all geometric tests in parallel -template -struct Concurrent_face_intersection_tester -{ - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - const TM& m_tmesh; - const VPM m_vpmap; - const FacePairs& m_face_pairs; - DoIntersectVector& m_do_intersect_vector; - typename GT::Construct_segment_3 m_construct_segment; - typename GT::Construct_triangle_3 m_construct_triangle; - typename GT::Do_intersect_3 m_do_intersect; - - Concurrent_face_intersection_tester(const FacePairs& face_pairs, - DoIntersectVector& do_intersect_vector, - const TM& tmesh, - VPM vpmap, - const GT& gt) - : - m_tmesh(tmesh), - m_vpmap(vpmap), - m_face_pairs(face_pairs), - m_do_intersect_vector(do_intersect_vector), - 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 tbb::blocked_range &r) const - { - for(std::size_t ri = r.begin(); ri != r.end(); ++ri) - this->operator()(ri); - } - - void operator()(std::size_t ri) const - { - const std::pair& ff = m_face_pairs[ri]; - halfedge_descriptor h = halfedge(ff.first, m_tmesh), g = halfedge(ff.second, m_tmesh); - - if(do_faces_intersect(h, g, m_tmesh, m_vpmap, m_construct_segment, m_construct_triangle, m_do_intersect)) - m_do_intersect_vector[ri] = true; - } -}; - -// This filter does not filter anything, but simply forwards intersecting pair information so that -// filtering can be done outside of the call to 'box_intersection_d' -template -struct All_faces_filter -{ - All_faces_filter(OutputIterator it) : m_iterator(it) { } - - template - void operator()(const Box* b, const Box* c) const { *m_iterator++ = std::make_pair(b->info(), c->info()); } - - mutable OutputIterator m_iterator; -}; -#endif - template ::value) { - // (A) Parallel: Write all pairs of faces with intersecting bbox - typedef tbb::concurrent_vector > Face_pairs; - typedef std::back_insert_iterator Face_pairs_back_inserter; + // 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; - internal::All_faces_filter all_faces_filter(std::back_inserter(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(), all_faces_filter, cutoff); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), callback, cutoff); - // (B) Parallel: Perform the geometric tests - typedef std::vector Do_intersect_vector; - typedef internal::Concurrent_face_intersection_tester Tester; - - Do_intersect_vector do_intersect(face_pairs.size(), 0); - Tester tester(face_pairs, do_intersect, tmesh, vpmap, gt); - tbb::parallel_for(tbb::blocked_range(0, face_pairs.size()), tester); - - // (C) Sequential: Copy from the concurent container to the output iterator - for(std::size_t i=0; i Date: Tue, 17 Dec 2019 17:57:54 +0100 Subject: [PATCH 56/61] Use 'seed' even when TBB is not linked --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 2 ++ 1 file changed, 2 insertions(+) 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 5a00000fbc1..55563d8b1da 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 @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CGAL_LINKED_WITH_TBB #include @@ -224,6 +225,7 @@ self_intersections_impl(const FaceRange& face_range, 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; From e33fa57213505d1fadddcff9d05993c53cc05f45 Mon Sep 17 00:00:00 2001 From: Mael Date: Tue, 4 Feb 2020 18:15:04 +0100 Subject: [PATCH 57/61] Use new tag in PMP tests --- .../self_intersection_surface_mesh_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6d468a267d1..32ddf4b2b6b 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 @@ -35,7 +35,7 @@ test_self_intersections(const char* filename, const bool expected) timer.start(); std::vector > intersected_tris; - CGAL::Polygon_mesh_processing::self_intersections( + CGAL::Polygon_mesh_processing::self_intersections( m, std::back_inserter(intersected_tris), CGAL::parameters::vertex_index_map(get(CGAL::vertex_point, m))); @@ -45,7 +45,7 @@ test_self_intersections(const char* filename, const bool expected) 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, + bool intersecting_2 = CGAL::Polygon_mesh_processing::does_self_intersect(m, CGAL::Polygon_mesh_processing::parameters::vertex_index_map(get(CGAL::vertex_point, m))); std::cout << "does_self_intersect test took " << timer.time() << " sec." << std::endl; From c2f99dc723a7ed63c500e07be0798bbdfe7966b1 Mon Sep 17 00:00:00 2001 From: Mael Date: Tue, 4 Feb 2020 18:18:45 +0100 Subject: [PATCH 58/61] Actually use TBB in test... --- .../test/Polygon_mesh_processing/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 40a606b3124..31851957f1a 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -98,6 +98,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() From 8773cee832570e6d54e1b156e5be3be316696eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 5 Feb 2020 10:54:11 +0100 Subject: [PATCH 59/61] Minor code improvements --- .../include/CGAL/box_intersection_d.h | 2 + .../self_intersections.h | 40 ++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Box_intersection_d/include/CGAL/box_intersection_d.h b/Box_intersection_d/include/CGAL/box_intersection_d.h index fb70c7ad6c2..94752c41462 100644 --- a/Box_intersection_d/include/CGAL/box_intersection_d.h +++ b/Box_intersection_d/include/CGAL/box_intersection_d.h @@ -186,6 +186,8 @@ void box_intersection_segment_tree_d( It r1_end = (r1_endi == -1) ? range_1_copies.end() : range_1_iterators[r1_endi][r1_endj]; It r2_start = range_2_iterators[i][(j+i)%n]; It r2_end = (r2_endi == -1) ? range_2_copies.end() : range_2_iterators[r2_endi][r2_endj]; + CGAL_assertion(range_1_copies.begin() <= r1_start && r1_start <= r1_end && r1_end <= range_1_copies.end()); + CGAL_assertion(range_2_copies.begin() <= r2_start && r2_start <= r2_end && r2_end <= range_2_copies.end()); // Specify "copy by value" otherwise the values of iterators for next (i,j) iterations // become shared with different lambdas being run in parallel, and things go wrong 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 55563d8b1da..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 @@ -74,6 +74,9 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, 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); @@ -83,12 +86,10 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, gv[1] = target(next(g, tmesh), tmesh); gv[2] = source(g, tmesh); - halfedge_descriptor opp_h; - // check for shared edge for(unsigned int i=0; i<3; ++i) { - opp_h = opposite(h, tmesh); + 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 @@ -138,11 +139,11 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, CGAL_assertion(hv[i] == gv[j]); // geometric check if the opposite segments intersect the triangles - Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); - Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); + 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])); - Segment s1 = construct_segment(get(vpmap, hv[(i+1)%3]), get(vpmap, hv[(i+2)%3]) ); - Segment s2 = construct_segment(get(vpmap, gv[(j+1)%3]), get(vpmap, gv[(j+2)%3])); + 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; @@ -153,9 +154,9 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, } // check for geometric intersection - Triangle t1 = construct_triangle(get(vpmap, hv[0]), get(vpmap, hv[1]), get(vpmap, hv[2])); - Triangle t2 = construct_triangle(get(vpmap, gv[0]), get(vpmap, gv[1]), get(vpmap, gv[2])); - if(do_intersect(t1, t2)) + 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; @@ -163,7 +164,7 @@ bool do_faces_intersect(typename boost::graph_traits::halfedge_descriptor h, template -struct Strict_intersect_faces // meaning, not just a shared subface +struct Strict_intersect_faces // "strict" as in "not sharing a subface" { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; @@ -186,8 +187,8 @@ struct Strict_intersect_faces // meaning, not just a shared subface void operator()(const Box* b, const Box* c) const { - halfedge_descriptor h = halfedge(b->info(), m_tmesh); - halfedge_descriptor g = halfedge(c->info(), m_tmesh); + const halfedge_descriptor h = halfedge(b->info(), m_tmesh); + const halfedge_descriptor g = halfedge(c->info(), m_tmesh); 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()); @@ -212,6 +213,7 @@ self_intersections_impl(const FaceRange& face_range, using CGAL::parameters::get_parameter; 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; @@ -236,10 +238,11 @@ self_intersections_impl(const FaceRange& 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(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)); + 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 @@ -302,15 +305,16 @@ self_intersections_impl(const FaceRange& face_range, return out; } #endif + // Sequential version of the code // Compute self-intersections filtered out by boxes typedef internal::Strict_intersect_faces 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); + 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); + CGAL::box_self_intersection_d(box_ptr.begin(), box_ptr.end(), intersect_faces, cutoff); return intersect_faces.m_iterator; } From 4bc3d850218ed14f469be2914e20ae2d950286a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Wed, 5 Feb 2020 10:54:26 +0100 Subject: [PATCH 60/61] Don't test parallel features with EPECK, since it's not threadsafe --- .../self_intersection_surface_mesh_test.cpp | 73 ++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) 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 32ddf4b2b6b..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 @@ -11,12 +11,15 @@ #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic; -typedef CGAL::Exact_predicates_exact_constructions_kernel Epec; +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::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; } From 5c9eb2fdfe0282a276ccd4db89f9a4beb6cf0af8 Mon Sep 17 00:00:00 2001 From: Mael Date: Fri, 7 Feb 2020 11:10:15 +0100 Subject: [PATCH 61/61] Update CHANGES.md --- Installation/CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 736a64839c6..646ca085b5f 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